Home / Class/ Processor Class — spring-boot Architecture

Processor Class — spring-boot Architecture

Architecture documentation for the Processor class in BootZipCopyAction.java from the spring-boot codebase.

Entity Profile

Source Code

build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java lines 188–489

	private class Processor {

		private final ZipArchiveOutputStream out;

		private final @Nullable LayersIndex layerIndex;

		private LoaderZipEntries.@Nullable WrittenEntries writtenLoaderEntries;

		private final Set<String> writtenDirectories = new LinkedHashSet<>();

		private final Map<String, FileCopyDetails> writtenLibraries = new LinkedHashMap<>();

		private final Map<String, FileCopyDetails> reachabilityMetadataProperties = new HashMap<>();

		Processor(ZipArchiveOutputStream out) {
			this.out = out;
			this.layerIndex = (BootZipCopyAction.this.layerResolver != null)
					? new LayersIndex(BootZipCopyAction.this.layerResolver.getLayers()) : null;
		}

		void process(FileCopyDetails details) {
			if (skipProcessing(details)) {
				return;
			}
			try {
				writeLoaderEntriesIfNecessary(details);
				if (details.isDirectory()) {
					processDirectory(details);
				}
				else {
					processFile(details);
				}
			}
			catch (IOException ex) {
				throw new GradleException("Failed to add " + details + " to " + BootZipCopyAction.this.output, ex);
			}
		}

		private boolean skipProcessing(FileCopyDetails details) {
			return BootZipCopyAction.this.exclusions.isSatisfiedBy(details)
					|| (this.writtenLoaderEntries != null && this.writtenLoaderEntries.isWrittenDirectory(details));
		}

		private void processDirectory(FileCopyDetails details) throws IOException {
			String name = details.getRelativePath().getPathString();
			ZipArchiveEntry entry = new ZipArchiveEntry(name + '/');
			prepareEntry(entry, name, getTime(details), getDirMode(details));
			this.out.putArchiveEntry(entry);
			this.out.closeArchiveEntry();
			this.writtenDirectories.add(name);
		}

		private void processFile(FileCopyDetails details) throws IOException {
			String name = details.getRelativePath().getPathString();
			ZipArchiveEntry entry = new ZipArchiveEntry(name);
			prepareEntry(entry, name, getTime(details), getFileMode(details));
			ZipCompression compression = BootZipCopyAction.this.compressionResolver.apply(details);
			if (compression == ZipCompression.STORED) {
				prepareStoredEntry(details, entry);
			}
			this.out.putArchiveEntry(entry);
			details.copyTo(this.out);
			this.out.closeArchiveEntry();
			if (BootZipCopyAction.this.librarySpec.isSatisfiedBy(details)) {
				this.writtenLibraries.put(name, details);
			}
			if (REACHABILITY_METADATA_PROPERTIES_LOCATION_PATTERN.matcher(name).matches()) {
				this.reachabilityMetadataProperties.put(name, details);
			}
			if (BootZipCopyAction.this.layerResolver != null) {
				Layer layer = BootZipCopyAction.this.layerResolver.getLayer(details);
				Assert.state(this.layerIndex != null, "'layerIndex' must not be null");
				Assert.state(layer != null, "'layer' must not be null");
				this.layerIndex.add(layer, name);
			}
		}

		private void writeParentDirectoriesIfNecessary(String name, @Nullable Long time) throws IOException {
			String parentDirectory = getParentDirectory(name);
			if (parentDirectory != null && this.writtenDirectories.add(parentDirectory)) {
				ZipArchiveEntry entry = new ZipArchiveEntry(parentDirectory + '/');
				prepareEntry(entry, parentDirectory, time, getDirMode());
				this.out.putArchiveEntry(entry);
				this.out.closeArchiveEntry();
			}
		}

		private @Nullable String getParentDirectory(String name) {
			int lastSlash = name.lastIndexOf('/');
			if (lastSlash == -1) {
				return null;
			}
			return name.substring(0, lastSlash);
		}

		void finish() throws IOException {
			writeLoaderEntriesIfNecessary(null);
			writeJarToolsIfNecessary();
			writeSignatureFileIfNecessary();
			writeClassPathIndexIfNecessary();
			writeNativeImageArgFileIfNecessary();
			// We must write the layer index last
			writeLayersIndexIfNecessary();
		}

		private void writeLoaderEntriesIfNecessary(@Nullable FileCopyDetails details) throws IOException {
			if (!BootZipCopyAction.this.includeDefaultLoader || this.writtenLoaderEntries != null) {
				return;
			}
			if (isInMetaInf(details)) {
				// Always write loader entries after META-INF directory (see gh-16698)
				return;
			}
			LoaderZipEntries loaderEntries = new LoaderZipEntries(getTime(), getDirMode(), getFileMode());
			this.writtenLoaderEntries = loaderEntries.writeTo(this.out);
			if (BootZipCopyAction.this.layerResolver != null) {
				for (String name : this.writtenLoaderEntries.getFiles()) {
					Layer layer = BootZipCopyAction.this.layerResolver.getLayer(name);
					Assert.state(this.layerIndex != null, "'layerIndex' must not be null");
					this.layerIndex.add(layer, name);
				}
			}
		}

		private boolean isInMetaInf(@Nullable FileCopyDetails details) {
			if (details == null) {
				return false;
			}
			String[] segments = details.getRelativePath().getSegments();
			return segments.length > 0 && "META-INF".equals(segments[0]);
		}

		private void writeJarToolsIfNecessary() throws IOException {
			if (BootZipCopyAction.this.jarmodeToolsLocation != null) {
				writeJarModeLibrary(BootZipCopyAction.this.jarmodeToolsLocation, JarModeLibrary.TOOLS);
			}
		}

		private void writeJarModeLibrary(String location, JarModeLibrary library) throws IOException {
			String name = location + library.getName();
			writeEntry(name, ZipEntryContentWriter.fromInputStream(library.openStream()), false,
					(entry) -> prepareStoredEntry(library::openStream, false, entry));
			if (BootZipCopyAction.this.layerResolver != null) {
				Layer layer = BootZipCopyAction.this.layerResolver.getLayer(library);
				Assert.state(this.layerIndex != null, "'layerIndex' must not be null");
				this.layerIndex.add(layer, name);
			}
		}

		private void writeSignatureFileIfNecessary() throws IOException {
			if (hasSignedLibrary()) {
				writeEntry("META-INF/BOOT.SF", (out) -> {
				}, false);
			}
		}

		private boolean hasSignedLibrary() throws IOException {
			for (FileCopyDetails writtenLibrary : this.writtenLibraries.values()) {
				if (FileUtils.isSignedJarFile(writtenLibrary.getFile())) {
					return true;
				}
			}
			return false;
		}

		private void writeClassPathIndexIfNecessary() throws IOException {
			Attributes manifestAttributes = BootZipCopyAction.this.manifest.getAttributes();
			String classPathIndex = (String) manifestAttributes.get("Spring-Boot-Classpath-Index");
			if (classPathIndex != null) {
				Set<String> libraryNames = this.writtenLibraries.keySet();
				List<String> lines = libraryNames.stream().map((line) -> "- \"" + line + "\"").toList();
				ZipEntryContentWriter writer = ZipEntryContentWriter.fromLines((BootZipCopyAction.this.encoding != null)
						? BootZipCopyAction.this.encoding : StandardCharsets.UTF_8.name(), lines);
				writeEntry(classPathIndex, writer, true);
			}
		}

		private void writeNativeImageArgFileIfNecessary() throws IOException {
			Set<String> excludes = new LinkedHashSet<>();
			for (Map.Entry<String, FileCopyDetails> entry : this.writtenLibraries.entrySet()) {
				DependencyDescriptor descriptor = BootZipCopyAction.this.resolvedDependencies
					.find(entry.getValue().getFile());
				LibraryCoordinates coordinates = (descriptor != null) ? descriptor.getCoordinates() : null;
				FileCopyDetails propertiesFile = (coordinates != null) ? this.reachabilityMetadataProperties
					.get(ReachabilityMetadataProperties.getLocation(coordinates)) : null;
				if (propertiesFile != null) {
					try (InputStream inputStream = propertiesFile.open()) {
						ReachabilityMetadataProperties properties = ReachabilityMetadataProperties
							.fromInputStream(inputStream);
						if (properties.isOverridden()) {
							excludes.add(entry.getKey());
						}
					}
				}
			}
			NativeImageArgFile argFile = new NativeImageArgFile(excludes);
			argFile.writeIfNecessary((lines) -> {
				ZipEntryContentWriter writer = ZipEntryContentWriter.fromLines((BootZipCopyAction.this.encoding != null)
						? BootZipCopyAction.this.encoding : StandardCharsets.UTF_8.name(), lines);
				writeEntry(NativeImageArgFile.LOCATION, writer, true);
			});
		}

		private void writeLayersIndexIfNecessary() throws IOException {
			if (BootZipCopyAction.this.layerResolver != null) {
				Attributes manifestAttributes = BootZipCopyAction.this.manifest.getAttributes();
				String name = (String) manifestAttributes.get("Spring-Boot-Layers-Index");
				Assert.state(StringUtils.hasText(name), "Missing layer index manifest attribute");
				Layer layer = BootZipCopyAction.this.layerResolver.getLayer(name);
				Assert.state(this.layerIndex != null, "'layerIndex' must not be null");
				this.layerIndex.add(layer, name);
				writeEntry(name, this.layerIndex::writeTo, false);
			}
		}

		private void writeEntry(String name, ZipEntryContentWriter entryWriter, boolean addToLayerIndex)
				throws IOException {
			writeEntry(name, entryWriter, addToLayerIndex, ZipEntryCustomizer.NONE);
		}

		private void writeEntry(String name, ZipEntryContentWriter entryWriter, boolean addToLayerIndex,
				ZipEntryCustomizer entryCustomizer) throws IOException {
			ZipArchiveEntry entry = new ZipArchiveEntry(name);
			prepareEntry(entry, name, getTime(), getFileMode());
			entryCustomizer.customize(entry);
			this.out.putArchiveEntry(entry);
			entryWriter.writeTo(this.out);
			this.out.closeArchiveEntry();
			if (addToLayerIndex && BootZipCopyAction.this.layerResolver != null) {
				Layer layer = BootZipCopyAction.this.layerResolver.getLayer(name);
				Assert.state(this.layerIndex != null, "'layerIndex' must not be null");
				this.layerIndex.add(layer, name);
			}
		}

		private void prepareEntry(ZipArchiveEntry entry, String name, @Nullable Long time, int mode)
				throws IOException {
			writeParentDirectoriesIfNecessary(name, time);
			entry.setUnixMode(mode);
			if (time != null) {
				entry.setTime(DefaultTimeZoneOffset.INSTANCE.removeFrom(time));
			}
		}

		private void prepareStoredEntry(FileCopyDetails details, ZipArchiveEntry archiveEntry) throws IOException {
			prepareStoredEntry(details::open, BootZipCopyAction.this.requiresUnpack.isSatisfiedBy(details),
					archiveEntry);
		}

		private void prepareStoredEntry(ThrowingSupplier<InputStream> input, boolean unpack,
				ZipArchiveEntry archiveEntry) throws IOException {
			new StoredEntryPreparator(input, unpack).prepareStoredEntry(archiveEntry);
		}

		private @Nullable Long getTime() {
			return getTime(null);
		}

		private @Nullable Long getTime(@Nullable FileCopyDetails details) {
			if (!BootZipCopyAction.this.preserveFileTimestamps) {
				return CONSTANT_TIME_FOR_ZIP_ENTRIES;
			}
			if (details != null) {
				return details.getLastModified();
			}
			return null;
		}

		private int getDirMode() {
			return (BootZipCopyAction.this.dirMode != null) ? BootZipCopyAction.this.dirMode
					: UnixStat.DEFAULT_DIR_PERM;
		}

		private int getFileMode() {
			return (BootZipCopyAction.this.fileMode != null) ? BootZipCopyAction.this.fileMode
					: UnixStat.DEFAULT_FILE_PERM;
		}

		private int getDirMode(FileCopyDetails details) {
			return (BootZipCopyAction.this.dirMode != null) ? BootZipCopyAction.this.dirMode : getPermissions(details);
		}

		private int getFileMode(FileCopyDetails details) {
			return (BootZipCopyAction.this.fileMode != null) ? BootZipCopyAction.this.fileMode
					: getPermissions(details);
		}

		private int getPermissions(FileCopyDetails details) {
			return (GradleVersion.current().compareTo(GradleVersion.version("8.3")) >= 0)
					? details.getPermissions().toUnixNumeric() : getMode(details);
		}

		private int getMode(FileCopyDetails details) {
			try {
				return (int) details.getClass().getMethod("getMode").invoke(details);
			}
			catch (Exception ex) {
				throw new RuntimeException("Failed to get mode from FileCopyDetails", ex);
			}
		}

	}

Analyze Your Own Codebase

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

Try Supermodel Free