Skip to content

Commit

Permalink
Polish loader and loader-tools
Browse files Browse the repository at this point in the history
Polish and refactor `spring-boot-loader` and `spring-boot-loader-tools`
to make it easier to add indexing and layering support.

Closes gh-19766
  • Loading branch information
philwebb committed Jan 16, 2020
1 parent 56e3025 commit ad72f86
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 182 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -56,12 +56,14 @@
*/
public class JarWriter implements LoaderClassesWriter, AutoCloseable {

private static final UnpackHandler NEVER_UNPACK = new NeverUnpackHandler();

private static final String NESTED_LOADER_JAR = "META-INF/loader/spring-boot-loader.jar";

private static final int BUFFER_SIZE = 32 * 1024;

private static final int UNIX_FILE_MODE = UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM;

private static final int UNIX_DIR_MODE = UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM;

private final JarArchiveOutputStream jarOutput;

private final Set<String> writtenEntries = new HashSet<>();
Expand Down Expand Up @@ -121,11 +123,11 @@ public void writeManifest(Manifest manifest) throws IOException {
* @throws IOException if the entries cannot be written
*/
public void writeEntries(JarFile jarFile) throws IOException {
this.writeEntries(jarFile, new IdentityEntryTransformer(), NEVER_UNPACK);
this.writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER);
}

void writeEntries(JarFile jarFile, UnpackHandler unpackHandler) throws IOException {
this.writeEntries(jarFile, new IdentityEntryTransformer(), unpackHandler);
this.writeEntries(jarFile, EntryTransformer.NONE, unpackHandler);
}

void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler)
Expand Down Expand Up @@ -244,7 +246,7 @@ public void close() throws IOException {
}

private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter) throws IOException {
writeEntry(entry, entryWriter, NEVER_UNPACK);
writeEntry(entry, entryWriter, UnpackHandler.NEVER);
}

/**
Expand All @@ -257,22 +259,10 @@ private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter) throws I
*/
private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter, UnpackHandler unpackHandler)
throws IOException {
String parent = entry.getName();
if (parent.endsWith("/")) {
parent = parent.substring(0, parent.length() - 1);
entry.setUnixMode(UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM);
}
else {
entry.setUnixMode(UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM);
}
if (parent.lastIndexOf('/') != -1) {
parent = parent.substring(0, parent.lastIndexOf('/') + 1);
if (!parent.isEmpty()) {
writeEntry(new JarArchiveEntry(parent), null, unpackHandler);
}
}

if (this.writtenEntries.add(entry.getName())) {
String name = entry.getName();
writeParentFolderEntries(name);
if (this.writtenEntries.add(name)) {
entry.setUnixMode(name.endsWith("/") ? UNIX_DIR_MODE : UNIX_FILE_MODE);
entryWriter = addUnpackCommentIfNecessary(entry, entryWriter, unpackHandler);
this.jarOutput.putArchiveEntry(entry);
if (entryWriter != null) {
Expand All @@ -282,6 +272,16 @@ private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter, UnpackHa
}
}

private void writeParentFolderEntries(String name) throws IOException {
String parent = name.endsWith("/") ? name.substring(0, name.length() - 1) : name;
while (parent.lastIndexOf('/') != -1) {
parent = parent.substring(0, parent.lastIndexOf('/'));
if (!parent.isEmpty()) {
writeEntry(new JarArchiveEntry(parent + "/"), null, UnpackHandler.NEVER);
}
}
}

private EntryWriter addUnpackCommentIfNecessary(JarArchiveEntry entry, EntryWriter entryWriter,
UnpackHandler unpackHandler) throws IOException {
if (entryWriter == null || !unpackHandler.requiresUnpack(entry.getName())) {
Expand Down Expand Up @@ -444,21 +444,15 @@ void setupStoredEntry(JarArchiveEntry entry) {
* An {@code EntryTransformer} enables the transformation of {@link JarEntry jar
* entries} during the writing process.
*/
@FunctionalInterface
interface EntryTransformer {

JarArchiveEntry transform(JarArchiveEntry jarEntry);

}

/**
* An {@code EntryTransformer} that returns the entry unchanged.
*/
private static final class IdentityEntryTransformer implements EntryTransformer {
/**
* No-op entity transformer.
*/
EntryTransformer NONE = (jarEntry) -> jarEntry;

@Override
public JarArchiveEntry transform(JarArchiveEntry jarEntry) {
return jarEntry;
}
JarArchiveEntry transform(JarArchiveEntry jarEntry);

}

Expand All @@ -468,23 +462,23 @@ public JarArchiveEntry transform(JarArchiveEntry jarEntry) {
*/
interface UnpackHandler {

boolean requiresUnpack(String name);
UnpackHandler NEVER = new UnpackHandler() {

String sha1Hash(String name) throws IOException;
@Override
public boolean requiresUnpack(String name) {
return false;
}

}
@Override
public String sha1Hash(String name) throws IOException {
throw new UnsupportedOperationException();
}

private static final class NeverUnpackHandler implements UnpackHandler {
};

@Override
public boolean requiresUnpack(String name) {
return false;
}
boolean requiresUnpack(String name);

@Override
public String sha1Hash(String name) {
throw new UnsupportedOperationException();
}
String sha1Hash(String name) throws IOException;

}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,13 +35,26 @@ public interface Layout {
*/
String getLauncherClassName();

/**
* Returns the destination path for a given library.
* @param libraryName the name of the library (excluding any path)
* @param scope the scope of the library
* @return the location of the library relative to the root of the archive (should end
* with '/') or {@code null} if the library should not be included.
*/
default String getLibraryLocation(String libraryName, LibraryScope scope) {
return getLibraryDestination(libraryName, scope);
}

/**
* Returns the destination path for a given library.
* @param libraryName the name of the library (excluding any path)
* @param scope the scope of the library
* @return the destination relative to the root of the archive (should end with '/')
* or {@code null} if the library should not be included.
* @deprecated since 2.3.0 in favor of {@link #getLibraryLocation}
*/
@Deprecated
String getLibraryDestination(String libraryName, LibraryScope scope);

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -67,6 +67,12 @@ public String getLauncherClassName() {
return "org.springframework.boot.loader.JarLauncher";
}

@Override
public String getLibraryLocation(String libraryName, LibraryScope scope) {
return "BOOT-INF/lib/";
}

@Deprecated
@Override
public String getLibraryDestination(String libraryName, LibraryScope scope) {
return "BOOT-INF/lib/";
Expand Down Expand Up @@ -123,25 +129,31 @@ public boolean isExecutable() {
*/
public static class War implements Layout {

private static final Map<LibraryScope, String> SCOPE_DESTINATIONS;
private static final Map<LibraryScope, String> SCOPE_LOCATION;

static {
Map<LibraryScope, String> map = new HashMap<>();
map.put(LibraryScope.COMPILE, "WEB-INF/lib/");
map.put(LibraryScope.CUSTOM, "WEB-INF/lib/");
map.put(LibraryScope.RUNTIME, "WEB-INF/lib/");
map.put(LibraryScope.PROVIDED, "WEB-INF/lib-provided/");
SCOPE_DESTINATIONS = Collections.unmodifiableMap(map);
Map<LibraryScope, String> locations = new HashMap<>();
locations.put(LibraryScope.COMPILE, "WEB-INF/lib/");
locations.put(LibraryScope.CUSTOM, "WEB-INF/lib/");
locations.put(LibraryScope.RUNTIME, "WEB-INF/lib/");
locations.put(LibraryScope.PROVIDED, "WEB-INF/lib-provided/");
SCOPE_LOCATION = Collections.unmodifiableMap(locations);
}

@Override
public String getLauncherClassName() {
return "org.springframework.boot.loader.WarLauncher";
}

@Override
public String getLibraryLocation(String libraryName, LibraryScope scope) {
return SCOPE_LOCATION.get(scope);
}

@Deprecated
@Override
public String getLibraryDestination(String libraryName, LibraryScope scope) {
return SCOPE_DESTINATIONS.get(scope);
return SCOPE_LOCATION.get(scope);
}

@Override
Expand Down
Loading

0 comments on commit ad72f86

Please sign in to comment.