Add support for creating layered war files with Maven
See gh-22821
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -30,6 +30,7 @@ import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarInputStream;
|
||||
@@ -90,11 +91,11 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
|
||||
* @throws IOException if the entries cannot be written
|
||||
*/
|
||||
public void writeEntries(JarFile jarFile) throws IOException {
|
||||
writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER);
|
||||
writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER, (name) -> false);
|
||||
}
|
||||
|
||||
final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler)
|
||||
throws IOException {
|
||||
final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler,
|
||||
Predicate<String> libraryPredicate) throws IOException {
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarArchiveEntry entry = new JarArchiveEntry(entries.nextElement());
|
||||
@@ -103,7 +104,8 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
|
||||
EntryWriter entryWriter = new InputStreamEntryWriter(inputStream);
|
||||
JarArchiveEntry transformedEntry = entryTransformer.transform(entry);
|
||||
if (transformedEntry != null) {
|
||||
writeEntry(transformedEntry, entryWriter, unpackHandler, true);
|
||||
boolean updateLayerIndex = !libraryPredicate.test(entry.getName());
|
||||
writeEntry(transformedEntry, entryWriter, unpackHandler, updateLayerIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,28 @@ public interface Layout {
|
||||
*/
|
||||
String getClassesLocation();
|
||||
|
||||
/**
|
||||
* Returns the location of the classpath index file that should be written or
|
||||
* {@code null} if not index is required. The result should include the filename and
|
||||
* is relative to the root of the jar.
|
||||
* @return the classpath index file location
|
||||
* @since 2.5.0
|
||||
*/
|
||||
default String getClasspathIndexFileLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the layer index file that should be written or {@code null}
|
||||
* if not index is required. The result should include the filename and is relative to
|
||||
* the root of the jar.
|
||||
* @return the layer index file location
|
||||
* @since 2.5.0
|
||||
*/
|
||||
default String getLayersIndexFileLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if loader classes should be included to make the archive executable.
|
||||
* @return if the layout is executable
|
||||
|
||||
@@ -160,6 +160,16 @@ public final class Layouts {
|
||||
return "WEB-INF/classes/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClasspathIndexFileLocation() {
|
||||
return "WEB-INF/classpath.idx";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLayersIndexFileLocation() {
|
||||
return "WEB-INF/layers.idx";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecutable() {
|
||||
return true;
|
||||
|
||||
@@ -172,7 +172,7 @@ public abstract class Packager {
|
||||
}
|
||||
writer.writeManifest(buildManifest(sourceJar));
|
||||
writeLoaderClasses(writer);
|
||||
writer.writeEntries(sourceJar, getEntityTransformer(), writeableLibraries);
|
||||
writer.writeEntries(sourceJar, getEntityTransformer(), writeableLibraries, writeableLibraries::containsEntry);
|
||||
writeableLibraries.write(writer);
|
||||
if (isLayered()) {
|
||||
writeLayerIndex(writer);
|
||||
@@ -190,7 +190,7 @@ public abstract class Packager {
|
||||
}
|
||||
|
||||
private void writeLayerIndex(AbstractJarWriter writer) throws IOException {
|
||||
String name = ((RepackagingLayout) this.layout).getLayersIndexFileLocation();
|
||||
String name = this.layout.getLayersIndexFileLocation();
|
||||
if (StringUtils.hasLength(name)) {
|
||||
Layer layer = this.layers.getLayer(name);
|
||||
this.layersIndex.add(layer, name);
|
||||
@@ -318,17 +318,17 @@ public abstract class Packager {
|
||||
|
||||
private void addBootAttributes(Attributes attributes) {
|
||||
attributes.putValue(BOOT_VERSION_ATTRIBUTE, getClass().getPackage().getImplementationVersion());
|
||||
Layout layout = getLayout();
|
||||
if (layout instanceof RepackagingLayout) {
|
||||
addBootBootAttributesForRepackagingLayout(attributes, (RepackagingLayout) layout);
|
||||
}
|
||||
else {
|
||||
addBootBootAttributesForPlainLayout(attributes);
|
||||
}
|
||||
addBootAttributesForLayout(attributes);
|
||||
}
|
||||
|
||||
private void addBootBootAttributesForRepackagingLayout(Attributes attributes, RepackagingLayout layout) {
|
||||
attributes.putValue(BOOT_CLASSES_ATTRIBUTE, layout.getRepackagedClassesLocation());
|
||||
private void addBootAttributesForLayout(Attributes attributes) {
|
||||
Layout layout = getLayout();
|
||||
if (layout instanceof RepackagingLayout) {
|
||||
attributes.putValue(BOOT_CLASSES_ATTRIBUTE, ((RepackagingLayout) layout).getRepackagedClassesLocation());
|
||||
}
|
||||
else {
|
||||
attributes.putValue(BOOT_CLASSES_ATTRIBUTE, layout.getClassesLocation());
|
||||
}
|
||||
putIfHasLength(attributes, BOOT_LIB_ATTRIBUTE, getLayout().getLibraryLocation("", LibraryScope.COMPILE));
|
||||
putIfHasLength(attributes, BOOT_CLASSPATH_INDEX_ATTRIBUTE, layout.getClasspathIndexFileLocation());
|
||||
if (isLayered()) {
|
||||
@@ -336,11 +336,6 @@ public abstract class Packager {
|
||||
}
|
||||
}
|
||||
|
||||
private void addBootBootAttributesForPlainLayout(Attributes attributes) {
|
||||
attributes.putValue(BOOT_CLASSES_ATTRIBUTE, getLayout().getClassesLocation());
|
||||
putIfHasLength(attributes, BOOT_LIB_ATTRIBUTE, getLayout().getLibraryLocation("", LibraryScope.COMPILE));
|
||||
}
|
||||
|
||||
private void putIfHasLength(Attributes attributes, String name, String value) {
|
||||
if (StringUtils.hasLength(value)) {
|
||||
attributes.putValue(name, value);
|
||||
@@ -348,7 +343,7 @@ public abstract class Packager {
|
||||
}
|
||||
|
||||
private boolean isLayered() {
|
||||
return this.layers != null && getLayout() instanceof Layouts.Jar;
|
||||
return this.layers != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,6 +461,10 @@ public abstract class Packager {
|
||||
return Digest.sha1(library::openStream);
|
||||
}
|
||||
|
||||
boolean containsEntry(String name) {
|
||||
return this.libraries.containsKey(name);
|
||||
}
|
||||
|
||||
private void write(AbstractJarWriter writer) throws IOException {
|
||||
for (Entry<String, Library> entry : this.libraries.entrySet()) {
|
||||
String path = entry.getKey();
|
||||
@@ -473,12 +472,12 @@ public abstract class Packager {
|
||||
String location = path.substring(0, path.lastIndexOf('/') + 1);
|
||||
writer.writeNestedLibrary(location, library);
|
||||
}
|
||||
if (getLayout() instanceof RepackagingLayout) {
|
||||
writeClasspathIndex((RepackagingLayout) getLayout(), writer);
|
||||
if (Packager.this.layout instanceof RepackagingLayout) {
|
||||
writeClasspathIndex(getLayout(), writer);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeClasspathIndex(RepackagingLayout layout, AbstractJarWriter writer) throws IOException {
|
||||
private void writeClasspathIndex(Layout layout, AbstractJarWriter writer) throws IOException {
|
||||
List<String> names = this.libraries.keySet().stream().map((path) -> "- \"" + path + "\"")
|
||||
.collect(Collectors.toList());
|
||||
writer.writeIndexFile(layout.getClasspathIndexFileLocation(), names);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -31,26 +31,4 @@ public interface RepackagingLayout extends Layout {
|
||||
*/
|
||||
String getRepackagedClassesLocation();
|
||||
|
||||
/**
|
||||
* Returns the location of the classpath index file that should be written or
|
||||
* {@code null} if not index is required. The result should include the filename and
|
||||
* is relative to the root of the jar.
|
||||
* @return the classpath index file location
|
||||
* @since 2.3.0
|
||||
*/
|
||||
default String getClasspathIndexFileLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the layer index file that should be written or {@code null}
|
||||
* if not index is required. The result should include the filename and is relative to
|
||||
* the root of the jar.
|
||||
* @return the layer index file location
|
||||
* @since 2.3.0
|
||||
*/
|
||||
default String getLayersIndexFileLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user