Home / Class/ IndexLayerArchiveFactory Class — spring-boot Architecture

IndexLayerArchiveFactory Class — spring-boot Architecture

Architecture documentation for the IndexLayerArchiveFactory class in ExportedImageTar.java from the spring-boot codebase.

Entity Profile

Relationship Graph

Source Code

buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ExportedImageTar.java lines 146–264

	private static class IndexLayerArchiveFactory extends LayerArchiveFactory {

		private final Map<String, String> layerMediaTypes;

		IndexLayerArchiveFactory(Path tarFile, ImageArchiveIndex index) throws IOException {
			this(tarFile, withNestedIndexes(tarFile, index));
		}

		IndexLayerArchiveFactory(Path tarFile, List<ImageArchiveIndex> indexes) throws IOException {
			Set<String> manifestDigests = getDigests(indexes, this::isManifest);
			Set<String> manifestListDigests = getDigests(indexes, IndexLayerArchiveFactory::isManifestList);
			List<ManifestList> manifestLists = getManifestLists(tarFile, manifestListDigests);
			List<Manifest> manifests = getManifests(tarFile, manifestDigests, manifestLists);
			this.layerMediaTypes = manifests.stream()
				.flatMap((manifest) -> manifest.getLayers().stream())
				.collect(Collectors.toMap(IndexLayerArchiveFactory::getEntryName, BlobReference::getMediaType));
		}

		private static List<ImageArchiveIndex> withNestedIndexes(Path tarFile, ImageArchiveIndex index)
				throws IOException {
			Set<String> indexDigests = getDigests(Stream.of(index), IndexLayerArchiveFactory::isIndex);
			List<ImageArchiveIndex> indexes = new ArrayList<>();
			indexes.add(index);
			indexes.addAll(getDigestMatches(tarFile, indexDigests, ImageArchiveIndex::of));
			return indexes;
		}

		private static Set<String> getDigests(List<ImageArchiveIndex> indexes, Predicate<BlobReference> predicate) {
			return getDigests(indexes.stream(), predicate);
		}

		private static Set<String> getDigests(Stream<ImageArchiveIndex> indexes, Predicate<BlobReference> predicate) {
			return indexes.flatMap((index) -> index.getManifests().stream())
				.filter(predicate)
				.map(BlobReference::getDigest)
				.collect(Collectors.toUnmodifiableSet());
		}

		private static List<ManifestList> getManifestLists(Path tarFile, Set<String> digests) throws IOException {
			return getDigestMatches(tarFile, digests, ManifestList::of);
		}

		private List<Manifest> getManifests(Path tarFile, Set<String> manifestDigests, List<ManifestList> manifestLists)
				throws IOException {
			Set<String> digests = new HashSet<>(manifestDigests);
			manifestLists.stream()
				.flatMap(ManifestList::streamManifests)
				.filter(this::isManifest)
				.map(BlobReference::getDigest)
				.forEach(digests::add);
			return getDigestMatches(tarFile, digests, Manifest::of);
		}

		private static <T> List<T> getDigestMatches(Path tarFile, Set<String> digests,
				ThrowingFunction<InputStream, T> factory) throws IOException {
			if (digests.isEmpty()) {
				return Collections.emptyList();
			}
			Set<String> names = digests.stream()
				.map(IndexLayerArchiveFactory::getEntryName)
				.collect(Collectors.toUnmodifiableSet());
			List<T> result = new ArrayList<>();
			try (TarArchiveInputStream tar = openTar(tarFile)) {
				TarArchiveEntry entry = tar.getNextEntry();
				while (entry != null) {
					if (names.contains(entry.getName())) {
						result.add(factory.apply(tar));
					}
					entry = tar.getNextEntry();
				}
			}
			return Collections.unmodifiableList(result);
		}

		private boolean isManifest(BlobReference reference) {
			return isJsonWithPrefix(reference.getMediaType(), "application/vnd.oci.image.manifest.v")
					|| isJsonWithPrefix(reference.getMediaType(), "application/vnd.docker.distribution.manifest.v");
		}

		private static boolean isIndex(BlobReference reference) {
			return isJsonWithPrefix(reference.getMediaType(), "application/vnd.oci.image.index.v");
		}

		private static boolean isManifestList(BlobReference reference) {
			return isJsonWithPrefix(reference.getMediaType(), "application/vnd.docker.distribution.manifest.list.v");
		}

		private static boolean isJsonWithPrefix(String mediaType, String prefix) {
			return mediaType.startsWith(prefix) && mediaType.endsWith("+json");
		}

		private static String getEntryName(BlobReference reference) {
			return getEntryName(reference.getDigest());
		}

		private static String getEntryName(String digest) {
			return "blobs/" + digest.replace(':', '/');
		}

		@Override
		@Nullable TarArchive getLayerArchive(TarArchiveInputStream tar, TarArchiveEntry entry) {
			String mediaType = this.layerMediaTypes.get(entry.getName());
			if (mediaType == null) {
				return null;
			}
			return TarArchive.fromInputStream(tar, getCompression(mediaType));
		}

		private Compression getCompression(String mediaType) {
			if (mediaType.endsWith(".tar.gzip") || mediaType.endsWith(".tar+gzip")) {
				return Compression.GZIP;
			}
			if (mediaType.endsWith(".tar.zstd") || mediaType.endsWith(".tar+zstd")) {
				return Compression.ZSTD;
			}
			return Compression.NONE;
		}

	}

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free