Refine layer customization for Maven and Gradle
Simplify layer customization logic for both Maven and Gradle and refactor some internals of the Gradle plugin. Both Maven and Gradle now use a simpler customization format that consists of `application`, `dependencies` and `layer order` sections. The `application`, `dependencies` configurations support one or more `into` blocks that are used to select content for a specific layer. Closes gh-20526
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools;
|
||||
|
||||
/**
|
||||
* Encapsulates information about the artifact coordinates of a library.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class DefaultLibraryCoordinates implements LibraryCoordinates {
|
||||
|
||||
private final String groupId;
|
||||
|
||||
private final String artifactId;
|
||||
|
||||
private final String version;
|
||||
|
||||
/**
|
||||
* Create a new instance from discrete elements.
|
||||
* @param groupId the group ID
|
||||
* @param artifactId the artifact ID
|
||||
* @param version the version
|
||||
*/
|
||||
DefaultLibraryCoordinates(String groupId, String artifactId, String version) {
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the group ID of the coordinates.
|
||||
* @return the group ID
|
||||
*/
|
||||
@Override
|
||||
public String getGroupId() {
|
||||
return this.groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the artifact ID of the coordinates.
|
||||
* @return the artifact ID
|
||||
*/
|
||||
@Override
|
||||
public String getArtifactId() {
|
||||
return this.artifactId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the version of the coordinates.
|
||||
* @return the version
|
||||
*/
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the coordinates in the form {@code groupId:artifactId:version}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return LibraryCoordinates.toStandardNotationString(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,23 +22,48 @@ import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link Library} implementation for internal jarmode jars.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.3.0
|
||||
*/
|
||||
class JarModeLibrary extends Library {
|
||||
public class JarModeLibrary extends Library {
|
||||
|
||||
static final JarModeLibrary LAYER_TOOLS = new JarModeLibrary("spring-boot-jarmode-layertools.jar");
|
||||
/**
|
||||
* {@link JarModeLibrary} for layer tools.
|
||||
*/
|
||||
public static final JarModeLibrary LAYER_TOOLS = new JarModeLibrary("spring-boot-jarmode-layertools");
|
||||
|
||||
JarModeLibrary(String name) {
|
||||
super(name, null, LibraryScope.RUNTIME, false);
|
||||
JarModeLibrary(String artifactId) {
|
||||
this(createCoordinates(artifactId));
|
||||
}
|
||||
|
||||
public JarModeLibrary(LibraryCoordinates coordinates) {
|
||||
super(getJarName(coordinates), null, LibraryScope.RUNTIME, coordinates, false);
|
||||
}
|
||||
|
||||
private static LibraryCoordinates createCoordinates(String artifactId) {
|
||||
String version = JarModeLibrary.class.getPackage().getImplementationVersion();
|
||||
return LibraryCoordinates.of("org.springframework.boot", artifactId, version);
|
||||
}
|
||||
|
||||
private static String getJarName(LibraryCoordinates coordinates) {
|
||||
String version = coordinates.getVersion();
|
||||
StringBuilder jarName = new StringBuilder(coordinates.getArtifactId());
|
||||
if (StringUtils.hasText(version)) {
|
||||
jarName.append('-');
|
||||
jarName.append(version);
|
||||
}
|
||||
jarName.append(".jar");
|
||||
return jarName.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
InputStream openStream() throws IOException {
|
||||
String path = "META-INF/jarmode/" + getName();
|
||||
public InputStream openStream() throws IOException {
|
||||
String path = "META-INF/jarmode/" + getCoordinates().getArtifactId() + ".jar";
|
||||
URL resource = getClass().getClassLoader().getResource(path);
|
||||
Assert.state(resource != null, "Unable to find resource " + path);
|
||||
return resource.openStream();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.boot.loader.tools;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
@@ -29,7 +28,7 @@ import org.springframework.util.Assert;
|
||||
* @since 2.3.0
|
||||
* @see Layers
|
||||
*/
|
||||
public class Layer implements Serializable {
|
||||
public class Layer {
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9-]+$");
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.loader.tools;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Interface to provide information about layers to the {@link Repackager}.
|
||||
@@ -36,16 +37,25 @@ public interface Layers extends Iterable<Layer> {
|
||||
/**
|
||||
* Return the jar layers in the order that they should be added (starting with the
|
||||
* least frequently changed layer).
|
||||
* @return the layers iterator
|
||||
*/
|
||||
@Override
|
||||
Iterator<Layer> iterator();
|
||||
|
||||
/**
|
||||
* Return a stream of the jar layers in the order that they should be added (starting
|
||||
* with the least frequently changed layer).
|
||||
* @return the layers stream
|
||||
*/
|
||||
Stream<Layer> stream();
|
||||
|
||||
/**
|
||||
* Return the layer that contains the given resource name.
|
||||
* @param resourceName the name of the resource (for example a {@code .class} file).
|
||||
* @param applicationResource the name of an application resource (for example a
|
||||
* {@code .class} file).
|
||||
* @return the layer that contains the resource (must never be {@code null})
|
||||
*/
|
||||
Layer getLayer(String resourceName);
|
||||
Layer getLayer(String applicationResource);
|
||||
|
||||
/**
|
||||
* Return the layer that contains the given library.
|
||||
|
||||
@@ -16,82 +16,60 @@
|
||||
|
||||
package org.springframework.boot.loader.tools;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Encapsulates information about the Maven artifact coordinates of a library.
|
||||
* Encapsulates information about the artifact coordinates of a library.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Phillip Webb
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public final class LibraryCoordinates {
|
||||
|
||||
private final String groupId;
|
||||
|
||||
private final String artifactId;
|
||||
|
||||
private final String version;
|
||||
|
||||
/**
|
||||
* Create a new instance from discrete elements.
|
||||
* @param groupId the group ID
|
||||
* @param artifactId the artifact ID
|
||||
* @param version the version
|
||||
*/
|
||||
public LibraryCoordinates(String groupId, String artifactId, String version) {
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from a String value in the form
|
||||
* {@code groupId:artifactId:version} where the version is optional.
|
||||
* @param coordinates the coordinates
|
||||
*/
|
||||
public LibraryCoordinates(String coordinates) {
|
||||
String[] elements = coordinates.split(":");
|
||||
Assert.isTrue(elements.length >= 2, "Coordinates must contain at least 'groupId:artifactId'");
|
||||
this.groupId = elements[0];
|
||||
this.artifactId = elements[1];
|
||||
this.version = (elements.length > 2) ? elements[2] : null;
|
||||
}
|
||||
public interface LibraryCoordinates {
|
||||
|
||||
/**
|
||||
* Return the group ID of the coordinates.
|
||||
* @return the group ID
|
||||
*/
|
||||
public String getGroupId() {
|
||||
return this.groupId;
|
||||
}
|
||||
String getGroupId();
|
||||
|
||||
/**
|
||||
* Return the artifact ID of the coordinates.
|
||||
* @return the artifact ID
|
||||
*/
|
||||
public String getArtifactId() {
|
||||
return this.artifactId;
|
||||
}
|
||||
String getArtifactId();
|
||||
|
||||
/**
|
||||
* Return the version of the coordinates.
|
||||
* @return the version
|
||||
*/
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
String getVersion();
|
||||
|
||||
/**
|
||||
* Factory method to create {@link LibraryCoordinates} with the specified values.
|
||||
* @param groupId the group ID
|
||||
* @param artifactId the artifact ID
|
||||
* @param version the version
|
||||
* @return a new {@link LibraryCoordinates} instance
|
||||
*/
|
||||
static LibraryCoordinates of(String groupId, String artifactId, String version) {
|
||||
return new DefaultLibraryCoordinates(groupId, artifactId, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the coordinates in the form {@code groupId:artifactId:version}.
|
||||
* Utility method that returns the given coordinates using the standard
|
||||
* {@code group:artifact:version} form.
|
||||
* @param coordinates the coordinates to convert (may be {@code null})
|
||||
* @return the standard notation form or {@code "::"} when the coordinates are null
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
static String toStandardNotationString(LibraryCoordinates coordinates) {
|
||||
if (coordinates == null) {
|
||||
return "::";
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append((this.groupId != null) ? this.groupId : "");
|
||||
builder.append((coordinates.getGroupId() != null) ? coordinates.getGroupId() : "");
|
||||
builder.append(":");
|
||||
builder.append((this.artifactId != null) ? this.artifactId : "");
|
||||
builder.append((coordinates.getArtifactId() != null) ? coordinates.getArtifactId() : "");
|
||||
builder.append(":");
|
||||
builder.append((this.version != null) ? this.version : "");
|
||||
builder.append((coordinates.getVersion() != null) ? coordinates.getVersion() : "");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Base class for the standard set of {@link Layers}. Defines the following layers:
|
||||
@@ -64,4 +65,9 @@ public abstract class StandardLayers implements Layers {
|
||||
return LAYERS.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Layer> stream() {
|
||||
return LAYERS.stream();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,29 +14,33 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.application;
|
||||
|
||||
import java.util.List;
|
||||
package org.springframework.boot.loader.tools.layer;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An implementation of {@link ResourceFilter} based on the resource location.
|
||||
* {@link ContentFilter} that matches application items based on an Ant-style path
|
||||
* pattern.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class LocationFilter extends AbstractResourceFilter {
|
||||
public class ApplicationContentFilter implements ContentFilter<String> {
|
||||
|
||||
private static final AntPathMatcher MATCHER = new AntPathMatcher();
|
||||
|
||||
public LocationFilter(List<String> includes, List<String> excludes) {
|
||||
super(includes, excludes);
|
||||
private final String pattern;
|
||||
|
||||
public ApplicationContentFilter(String pattern) {
|
||||
Assert.hasText(pattern, "Pattern must not be empty");
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isMatch(String resourceName, List<String> toMatch) {
|
||||
return toMatch.stream().anyMatch((pattern) -> MATCHER.match(pattern, resourceName));
|
||||
public boolean matches(String path) {
|
||||
return MATCHER.match(this.pattern, path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,8 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer;
|
||||
|
||||
/**
|
||||
* Support for custom layers for everything in BOOT-INF/classes.
|
||||
* Callback interface that can be used to filter layer contents.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @param <T> the content type
|
||||
* @since 2.3.0
|
||||
*/
|
||||
package org.springframework.boot.loader.tools.layer.application;
|
||||
@FunctionalInterface
|
||||
public interface ContentFilter<T> {
|
||||
|
||||
/**
|
||||
* Return if the filter matches the specified item.
|
||||
* @param item the item to test
|
||||
* @return if the filter matches
|
||||
*/
|
||||
boolean matches(T item);
|
||||
|
||||
}
|
||||
@@ -14,27 +14,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.library;
|
||||
|
||||
import java.io.Serializable;
|
||||
package org.springframework.boot.loader.tools.layer;
|
||||
|
||||
import org.springframework.boot.loader.tools.Layer;
|
||||
import org.springframework.boot.loader.tools.Library;
|
||||
|
||||
/**
|
||||
* A strategy used to match a library to a layer.
|
||||
* Strategy used by {@link CustomLayers} to select the layer of an item.
|
||||
*
|
||||
* @param <T> the content type
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.3.0
|
||||
* @see IncludeExcludeContentSelector
|
||||
*/
|
||||
public interface LibraryStrategy extends Serializable {
|
||||
public interface ContentSelector<T> {
|
||||
|
||||
/**
|
||||
* Return a {@link Layer} for the given {@link Library}. If no matching layer is
|
||||
* found, {@code null} is returned.
|
||||
* @param library the library
|
||||
* @return the matching layer or {@code null}
|
||||
* Return the {@link Layer} that the selector represents.
|
||||
* @return the named layer
|
||||
*/
|
||||
Layer getMatchingLayer(Library library);
|
||||
Layer getLayer();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified item is contained in this selection.
|
||||
* @param item the item to test
|
||||
* @return if the item is contained
|
||||
*/
|
||||
boolean contains(T item);
|
||||
|
||||
}
|
||||
@@ -19,32 +19,52 @@ package org.springframework.boot.loader.tools.layer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.boot.loader.tools.Layer;
|
||||
import org.springframework.boot.loader.tools.Layers;
|
||||
import org.springframework.boot.loader.tools.Library;
|
||||
import org.springframework.boot.loader.tools.layer.application.ResourceStrategy;
|
||||
import org.springframework.boot.loader.tools.layer.library.LibraryStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Layers} representing user-provided layers.
|
||||
* Custom {@link Layers} implementation where layer content is selected by the user.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class CustomLayers implements Layers {
|
||||
|
||||
private final List<Layer> layers;
|
||||
|
||||
private final List<ResourceStrategy> resourceStrategies;
|
||||
private final List<ContentSelector<String>> applicationSelectors;
|
||||
|
||||
private final List<LibraryStrategy> libraryStrategies;
|
||||
private final List<ContentSelector<Library>> librarySelectors;
|
||||
|
||||
public CustomLayers(List<Layer> layers, List<ResourceStrategy> resourceStrategies,
|
||||
List<LibraryStrategy> libraryStrategies) {
|
||||
public CustomLayers(List<Layer> layers, List<ContentSelector<String>> applicationSelectors,
|
||||
List<ContentSelector<Library>> librarySelectors) {
|
||||
Assert.notNull(layers, "Layers must not be null");
|
||||
Assert.notNull(applicationSelectors, "ApplicationSelectors must not be null");
|
||||
validateSelectorLayers(applicationSelectors, layers);
|
||||
Assert.notNull(librarySelectors, "LibrarySelectors must not be null");
|
||||
validateSelectorLayers(librarySelectors, layers);
|
||||
this.layers = new ArrayList<>(layers);
|
||||
this.resourceStrategies = new ArrayList<>(resourceStrategies);
|
||||
this.libraryStrategies = new ArrayList<>(libraryStrategies);
|
||||
this.applicationSelectors = new ArrayList<>(applicationSelectors);
|
||||
this.librarySelectors = new ArrayList<>(librarySelectors);
|
||||
}
|
||||
|
||||
private static <T> void validateSelectorLayers(List<ContentSelector<T>> selectors, List<Layer> layers) {
|
||||
for (ContentSelector<?> selector : selectors) {
|
||||
validateSelectorLayers(selector, layers);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateSelectorLayers(ContentSelector<?> selector, List<Layer> layers) {
|
||||
Layer layer = selector.getLayer();
|
||||
Assert.state(layer != null, "Missing content selector layer");
|
||||
Assert.state(layers.contains(layer),
|
||||
"Content selector layer '" + selector.getLayer() + "' not found in " + layers);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,35 +72,28 @@ public class CustomLayers implements Layers {
|
||||
return this.layers.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Layer> stream() {
|
||||
return this.layers.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Layer getLayer(String resourceName) {
|
||||
for (ResourceStrategy strategy : this.resourceStrategies) {
|
||||
Layer matchingLayer = strategy.getMatchingLayer(resourceName);
|
||||
if (matchingLayer != null) {
|
||||
validateLayerName(matchingLayer, "Resource '" + resourceName + "'");
|
||||
return matchingLayer;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Resource '" + resourceName + "' did not match any layer.");
|
||||
return selectLayer(resourceName, this.applicationSelectors, () -> "Resource '" + resourceName + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Layer getLayer(Library library) {
|
||||
for (LibraryStrategy strategy : this.libraryStrategies) {
|
||||
Layer matchingLayer = strategy.getMatchingLayer(library);
|
||||
if (matchingLayer != null) {
|
||||
validateLayerName(matchingLayer, "Library '" + library.getName() + "'");
|
||||
return matchingLayer;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Library '" + library.getName() + "' did not match any layer.");
|
||||
return selectLayer(library, this.librarySelectors, () -> "Library '" + library.getName() + "'");
|
||||
}
|
||||
|
||||
private void validateLayerName(Layer layer, String nameText) {
|
||||
if (!this.layers.contains(layer)) {
|
||||
throw new IllegalStateException(nameText + " matched a layer '" + layer
|
||||
+ "' that is not included in the configured layers " + this.layers + ".");
|
||||
private <T> Layer selectLayer(T item, List<ContentSelector<T>> selectors, Supplier<String> name) {
|
||||
for (ContentSelector<T> selector : selectors) {
|
||||
if (selector.contains(item)) {
|
||||
return selector.getLayer();
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(name.get() + " did not match any layer");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.loader.tools.Layer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ContentSelector} backed by {@code include}/{@code exclude} {@link ContentFilter
|
||||
* filters}.
|
||||
*
|
||||
* @param <T> the content type
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class IncludeExcludeContentSelector<T> implements ContentSelector<T> {
|
||||
|
||||
private final Layer layer;
|
||||
|
||||
private final List<ContentFilter<T>> includes;
|
||||
|
||||
private final List<ContentFilter<T>> excludes;
|
||||
|
||||
public IncludeExcludeContentSelector(Layer layer, List<ContentFilter<T>> includes,
|
||||
List<ContentFilter<T>> excludes) {
|
||||
this(layer, includes, excludes, Function.identity());
|
||||
}
|
||||
|
||||
public <S> IncludeExcludeContentSelector(Layer layer, List<S> includes, List<S> excludes,
|
||||
Function<S, ContentFilter<T>> filterFactory) {
|
||||
Assert.notNull(layer, "Layer must not be null");
|
||||
Assert.notNull(filterFactory, "FilterFactory must not be null");
|
||||
this.layer = layer;
|
||||
this.includes = (includes != null) ? adapt(includes, filterFactory) : Collections.emptyList();
|
||||
this.excludes = (excludes != null) ? adapt(excludes, filterFactory) : Collections.emptyList();
|
||||
}
|
||||
|
||||
private <S> List<ContentFilter<T>> adapt(List<S> list, Function<S, ContentFilter<T>> mapper) {
|
||||
return list.stream().map(mapper).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Layer getLayer() {
|
||||
return this.layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T item) {
|
||||
return isIncluded(item) && !isExcluded(item);
|
||||
}
|
||||
|
||||
private boolean isIncluded(T item) {
|
||||
if (this.includes.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (ContentFilter<T> include : this.includes) {
|
||||
if (include.matches(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isExcluded(T item) {
|
||||
if (this.excludes.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (ContentFilter<T> exclude : this.excludes) {
|
||||
if (exclude.matches(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.boot.loader.tools.Library;
|
||||
import org.springframework.boot.loader.tools.LibraryCoordinates;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ContentFilter} that matches {@link Library} items based on a coordinates
|
||||
* pattern.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Scott Frederick
|
||||
* @author Phillip Webb
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class LibraryContentFilter implements ContentFilter<Library> {
|
||||
|
||||
private final Pattern pattern;
|
||||
|
||||
public LibraryContentFilter(String coordinatesPattern) {
|
||||
Assert.hasText(coordinatesPattern, "CoordinatesPattern must not be empty");
|
||||
StringBuilder regex = new StringBuilder();
|
||||
for (int i = 0; i < coordinatesPattern.length(); i++) {
|
||||
char c = coordinatesPattern.charAt(i);
|
||||
if (c == '.') {
|
||||
regex.append("\\.");
|
||||
}
|
||||
else if (c == '*') {
|
||||
regex.append(".*");
|
||||
}
|
||||
else {
|
||||
regex.append(c);
|
||||
}
|
||||
}
|
||||
this.pattern = Pattern.compile(regex.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Library library) {
|
||||
return this.pattern.matcher(LibraryCoordinates.toStandardNotationString(library.getCoordinates())).matches();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.application;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link ResourceFilter} implementations.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public abstract class AbstractResourceFilter implements ResourceFilter {
|
||||
|
||||
private final List<String> includes = new ArrayList<>();
|
||||
|
||||
private final List<String> excludes = new ArrayList<>();
|
||||
|
||||
public AbstractResourceFilter(List<String> includes, List<String> excludes) {
|
||||
this.includes.addAll(includes);
|
||||
this.excludes.addAll(excludes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResourceIncluded(String resourceName) {
|
||||
return isMatch(resourceName, this.includes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResourceExcluded(String resourceName) {
|
||||
return isMatch(resourceName, this.excludes);
|
||||
}
|
||||
|
||||
protected abstract boolean isMatch(String resourceName, List<String> toMatch);
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.application;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.loader.tools.Layer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ResourceStrategy} with custom filters.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class FilteredResourceStrategy implements ResourceStrategy {
|
||||
|
||||
private final Layer layer;
|
||||
|
||||
private final List<ResourceFilter> filters = new ArrayList<>();
|
||||
|
||||
public FilteredResourceStrategy(String layer, List<ResourceFilter> filters) {
|
||||
Assert.notEmpty(filters, "Filters should not be empty for custom strategy.");
|
||||
this.layer = new Layer(layer);
|
||||
this.filters.addAll(filters);
|
||||
}
|
||||
|
||||
public Layer getLayer() {
|
||||
return this.layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Layer getMatchingLayer(String resourceName) {
|
||||
boolean isIncluded = false;
|
||||
for (ResourceFilter filter : this.filters) {
|
||||
if (filter.isResourceExcluded(resourceName)) {
|
||||
return null;
|
||||
}
|
||||
if (!isIncluded && filter.isResourceIncluded(resourceName)) {
|
||||
isIncluded = true;
|
||||
}
|
||||
}
|
||||
return (isIncluded) ? this.layer : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.application;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A filter that can tell if a resource has been included or excluded.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public interface ResourceFilter extends Serializable {
|
||||
|
||||
/**
|
||||
* Return true if the resource is included by the filter.
|
||||
* @param resourceName the resource name
|
||||
* @return true if the resource is included
|
||||
*/
|
||||
boolean isResourceIncluded(String resourceName);
|
||||
|
||||
/**
|
||||
* Return true if the resource is included by the filter.
|
||||
* @param resourceName the resource name
|
||||
* @return true if the resource is excluded
|
||||
*/
|
||||
boolean isResourceExcluded(String resourceName);
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.application;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.boot.loader.tools.Layer;
|
||||
|
||||
/**
|
||||
* A strategy used to match a resource to a layer.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public interface ResourceStrategy extends Serializable {
|
||||
|
||||
/**
|
||||
* Return a {@link Layer} for the given resource. If no matching layer is found,
|
||||
* {@code null} is returned.
|
||||
* @param resourceName the name of the resource
|
||||
* @return the matching layer or {@code null}
|
||||
*/
|
||||
Layer getMatchingLayer(String resourceName);
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.library;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.loader.tools.Library;
|
||||
import org.springframework.boot.loader.tools.LibraryCoordinates;
|
||||
|
||||
/**
|
||||
* An implementation of {@link LibraryFilter} based on the library's coordinates.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Scott Frederick
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class CoordinateFilter implements LibraryFilter {
|
||||
|
||||
private static final String EMPTY_COORDINATES = "::";
|
||||
|
||||
private final List<Pattern> includes;
|
||||
|
||||
private final List<Pattern> excludes;
|
||||
|
||||
public CoordinateFilter(List<String> includes, List<String> excludes) {
|
||||
this.includes = includes.stream().map(this::asPattern).collect(Collectors.toList());
|
||||
this.excludes = excludes.stream().map(this::asPattern).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Pattern asPattern(String string) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
char c = string.charAt(i);
|
||||
if (c == '.') {
|
||||
builder.append("\\.");
|
||||
}
|
||||
else if (c == '*') {
|
||||
builder.append(".*");
|
||||
}
|
||||
else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
return Pattern.compile(builder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLibraryIncluded(Library library) {
|
||||
return isMatch(library, this.includes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLibraryExcluded(Library library) {
|
||||
return isMatch(library, this.excludes);
|
||||
}
|
||||
|
||||
private boolean isMatch(Library library, List<Pattern> patterns) {
|
||||
LibraryCoordinates coordinates = library.getCoordinates();
|
||||
String input = (coordinates != null) ? coordinates.toString() : EMPTY_COORDINATES;
|
||||
for (Pattern pattern : patterns) {
|
||||
if (pattern.matcher(input).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.library;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.loader.tools.Layer;
|
||||
import org.springframework.boot.loader.tools.Library;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link LibraryStrategy} with custom filters.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class FilteredLibraryStrategy implements LibraryStrategy {
|
||||
|
||||
private final Layer layer;
|
||||
|
||||
private final List<LibraryFilter> filters = new ArrayList<>();
|
||||
|
||||
public FilteredLibraryStrategy(String layer, List<LibraryFilter> filters) {
|
||||
Assert.notEmpty(filters, "Filters should not be empty for custom strategy.");
|
||||
this.layer = new Layer(layer);
|
||||
this.filters.addAll(filters);
|
||||
}
|
||||
|
||||
public Layer getLayer() {
|
||||
return this.layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Layer getMatchingLayer(Library library) {
|
||||
boolean isIncluded = false;
|
||||
for (LibraryFilter filter : this.filters) {
|
||||
if (filter.isLibraryExcluded(library)) {
|
||||
return null;
|
||||
}
|
||||
if (!isIncluded && filter.isLibraryIncluded(library)) {
|
||||
isIncluded = true;
|
||||
}
|
||||
}
|
||||
return (isIncluded) ? this.layer : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.tools.layer.library;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.boot.loader.tools.Library;
|
||||
|
||||
/**
|
||||
* A filter that can tell if a {@link Library} has been included or excluded.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public interface LibraryFilter extends Serializable {
|
||||
|
||||
/**
|
||||
* Return true if the {@link Library} is included by the filter.
|
||||
* @param library the library
|
||||
* @return true if the library is included
|
||||
*/
|
||||
boolean isLibraryIncluded(Library library);
|
||||
|
||||
/**
|
||||
* Return true if the {@link Library} is excluded by the filter.
|
||||
* @param library the library
|
||||
* @return true if the library is excluded
|
||||
*/
|
||||
boolean isLibraryExcluded(Library library);
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for custom layers for everything in BOOT-INF/lib.
|
||||
*
|
||||
*/
|
||||
package org.springframework.boot.loader.tools.layer.library;
|
||||
Reference in New Issue
Block a user