Skip to content

Commit e49e62d

Browse files
mbhavesnicoll
andcommitted
Add support for customizing layers in Maven
This commit adds an additional 'layers/configuration' property that can be used to refer to a separate layers configuration file. This separate file defines: * The layers and their order of precedence, * How libraries are handled using filters that match against the coordinates of each library, and * How classes are handled using filters that match against the location of the entry An XSD to validate the XML configuration file is available. Closes gh-20295 Co-authored-by: Stephane Nicoll <[email protected]>
1 parent 896d2c8 commit e49e62d

File tree

38 files changed

+2024
-37
lines changed

38 files changed

+2024
-37
lines changed

spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Library.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
* Encapsulates information about a single library that may be packed into the archive.
2626
*
2727
* @author Phillip Webb
28+
* @author Scott Frederick
2829
* @since 1.1.2
2930
* @see Libraries
3031
*/
@@ -38,6 +39,8 @@ public class Library {
3839

3940
private final boolean unpackRequired;
4041

42+
private final LibraryCoordinates coordinates;
43+
4144
/**
4245
* Create a new {@link Library}.
4346
* @param file the source file
@@ -66,10 +69,15 @@ public Library(File file, LibraryScope scope, boolean unpackRequired) {
6669
* @param unpackRequired if the library needs to be unpacked before it can be used
6770
*/
6871
public Library(String name, File file, LibraryScope scope, boolean unpackRequired) {
72+
this(name, file, scope, unpackRequired, null);
73+
}
74+
75+
public Library(String name, File file, LibraryScope scope, boolean unpackRequired, LibraryCoordinates coordinates) {
6976
this.name = (name != null) ? name : file.getName();
7077
this.file = file;
7178
this.scope = scope;
7279
this.unpackRequired = unpackRequired;
80+
this.coordinates = coordinates;
7381
}
7482

7583
/**
@@ -114,6 +122,14 @@ public boolean isUnpackRequired() {
114122
return this.unpackRequired;
115123
}
116124

125+
/**
126+
* Return the {@linkplain LibraryCoordinates coordinates} of the library.
127+
* @return the coordinates
128+
*/
129+
public LibraryCoordinates getCoordinates() {
130+
return this.coordinates;
131+
}
132+
117133
long getLastModified() {
118134
return this.file.lastModified();
119135
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.loader.tools;
18+
19+
import org.springframework.util.Assert;
20+
21+
/**
22+
* Encapsulates information about the Maven artifact coordinates of a library.
23+
*
24+
* @author Scott Frederick
25+
* @since 2.3.0
26+
*/
27+
public final class LibraryCoordinates {
28+
29+
private final String groupId;
30+
31+
private final String artifactId;
32+
33+
private final String version;
34+
35+
/**
36+
* Create a new instance from discrete elements.
37+
* @param groupId the group ID
38+
* @param artifactId the artifact ID
39+
* @param version the version
40+
*/
41+
public LibraryCoordinates(String groupId, String artifactId, String version) {
42+
this.groupId = groupId;
43+
this.artifactId = artifactId;
44+
this.version = version;
45+
}
46+
47+
/**
48+
* Create a new instance from a String value in the form
49+
* {@code groupId:artifactId:version} where the version is optional.
50+
* @param coordinates the coordinates
51+
*/
52+
public LibraryCoordinates(String coordinates) {
53+
String[] elements = coordinates.split(":");
54+
Assert.isTrue(elements.length >= 2, "Coordinates must contain at least 'groupId:artifactId'");
55+
this.groupId = elements[0];
56+
this.artifactId = elements[1];
57+
if (elements.length > 2) {
58+
this.version = elements[2];
59+
}
60+
else {
61+
this.version = null;
62+
}
63+
}
64+
65+
public String getGroupId() {
66+
return this.groupId;
67+
}
68+
69+
public String getArtifactId() {
70+
return this.artifactId;
71+
}
72+
73+
public String getVersion() {
74+
return this.version;
75+
}
76+
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.loader.tools.layer;
18+
19+
import java.util.ArrayList;
20+
import java.util.Iterator;
21+
import java.util.List;
22+
23+
import org.springframework.boot.loader.tools.Layer;
24+
import org.springframework.boot.loader.tools.Layers;
25+
import org.springframework.boot.loader.tools.Library;
26+
import org.springframework.boot.loader.tools.layer.classes.ResourceStrategy;
27+
import org.springframework.boot.loader.tools.layer.library.LibraryStrategy;
28+
29+
/**
30+
* Implementation of {@link Layers} representing user-provided layers.
31+
*
32+
* @author Madhura Bhave
33+
* @since 2.3.0
34+
*/
35+
public class CustomLayers implements Layers {
36+
37+
private final List<Layer> layers;
38+
39+
private final List<ResourceStrategy> resourceStrategies;
40+
41+
private final List<LibraryStrategy> libraryStrategies;
42+
43+
public CustomLayers(List<Layer> layers, List<ResourceStrategy> resourceStrategies,
44+
List<LibraryStrategy> libraryStrategies) {
45+
this.layers = new ArrayList<>(layers);
46+
this.resourceStrategies = new ArrayList<>(resourceStrategies);
47+
this.libraryStrategies = new ArrayList<>(libraryStrategies);
48+
}
49+
50+
@Override
51+
public Iterator<Layer> iterator() {
52+
return this.layers.iterator();
53+
}
54+
55+
@Override
56+
public Layer getLayer(String resourceName) {
57+
for (ResourceStrategy strategy : this.resourceStrategies) {
58+
Layer matchingLayer = strategy.getMatchingLayer(resourceName);
59+
if (matchingLayer != null) {
60+
return matchingLayer;
61+
}
62+
}
63+
throw new IllegalStateException("Resource '" + resourceName + "' did not match any layer.");
64+
}
65+
66+
@Override
67+
public Layer getLayer(Library library) {
68+
for (LibraryStrategy strategy : this.libraryStrategies) {
69+
Layer matchingLayer = strategy.getMatchingLayer(library);
70+
if (matchingLayer != null) {
71+
return matchingLayer;
72+
}
73+
}
74+
throw new IllegalStateException("Library '" + library.getName() + "' did not match any layer.");
75+
}
76+
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.loader.tools.layer.classes;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
/**
23+
* Abstract base class for {@link ResourceFilter} implementations.
24+
*
25+
* @author Madhura Bhave
26+
* @since 2.3.0
27+
*/
28+
public abstract class AbstractResourceFilter implements ResourceFilter {
29+
30+
private final List<String> includes = new ArrayList<>();
31+
32+
private final List<String> excludes = new ArrayList<>();
33+
34+
public AbstractResourceFilter(List<String> includes, List<String> excludes) {
35+
this.includes.addAll(includes);
36+
this.excludes.addAll(excludes);
37+
}
38+
39+
@Override
40+
public boolean isResourceIncluded(String resourceName) {
41+
return isMatch(resourceName, this.includes);
42+
}
43+
44+
@Override
45+
public boolean isResourceExcluded(String resourceName) {
46+
return isMatch(resourceName, this.excludes);
47+
}
48+
49+
protected abstract boolean isMatch(String resourceName, List<String> toMatch);
50+
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.loader.tools.layer.classes;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.springframework.boot.loader.tools.Layer;
23+
import org.springframework.util.Assert;
24+
25+
/**
26+
* A {@link ResourceStrategy} with custom filters.
27+
*
28+
* @author Madhura Bhave
29+
* @since 2.3.0
30+
*/
31+
public class FilteredResourceStrategy implements ResourceStrategy {
32+
33+
private final Layer layer;
34+
35+
private final List<ResourceFilter> filters = new ArrayList<>();
36+
37+
public FilteredResourceStrategy(String layer, List<ResourceFilter> filters) {
38+
Assert.notEmpty(filters, "Filters should not be empty for custom strategy.");
39+
this.layer = new Layer(layer);
40+
this.filters.addAll(filters);
41+
}
42+
43+
public Layer getLayer() {
44+
return this.layer;
45+
}
46+
47+
@Override
48+
public Layer getMatchingLayer(String resourceName) {
49+
boolean isIncluded = false;
50+
for (ResourceFilter filter : this.filters) {
51+
if (filter.isResourceExcluded(resourceName)) {
52+
return null;
53+
}
54+
if (!isIncluded && filter.isResourceIncluded(resourceName)) {
55+
isIncluded = true;
56+
}
57+
}
58+
return (isIncluded) ? this.layer : null;
59+
}
60+
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.loader.tools.layer.classes;
18+
19+
import java.util.List;
20+
21+
import org.springframework.util.AntPathMatcher;
22+
23+
/**
24+
* An implementation of {@link ResourceFilter} based on the resource location.
25+
*
26+
* @author Madhura Bhave
27+
* @since 2.3.0
28+
*/
29+
public class LocationFilter extends AbstractResourceFilter {
30+
31+
private static final AntPathMatcher MATCHER = new AntPathMatcher();
32+
33+
public LocationFilter(List<String> includes, List<String> excludes) {
34+
super(includes, excludes);
35+
}
36+
37+
@Override
38+
protected boolean isMatch(String resourceName, List<String> toMatch) {
39+
return toMatch.stream().anyMatch((pattern) -> MATCHER.match(pattern, resourceName));
40+
}
41+
42+
}

0 commit comments

Comments
 (0)