1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.enforcer.rules.utils;
20
21 import java.util.Collection;
22 import java.util.HashSet;
23 import java.util.Objects;
24 import java.util.function.Function;
25
26 import org.apache.maven.artifact.Artifact;
27 import org.apache.maven.artifact.versioning.ArtifactVersion;
28 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
29 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
30 import org.apache.maven.artifact.versioning.VersionRange;
31 import org.apache.maven.model.Dependency;
32 import org.codehaus.plexus.util.StringUtils;
33
34 import static java.util.Optional.ofNullable;
35
36
37
38
39
40
41 public final class ArtifactMatcher {
42
43
44
45
46 public static class Pattern {
47 private String pattern;
48
49 private String[] parts;
50
51 public Pattern(String pattern) {
52 if (pattern == null) {
53 throw new NullPointerException("pattern");
54 }
55
56 this.pattern = pattern;
57
58 parts = pattern.split(":", 7);
59
60 if (parts.length == 7) {
61 throw new IllegalArgumentException("Pattern contains too many delimiters.");
62 }
63
64 for (String part : parts) {
65 if ("".equals(part)) {
66 throw new IllegalArgumentException("Pattern or its part is empty.");
67 }
68 }
69 }
70
71 public boolean match(Artifact artifact) {
72 Objects.requireNonNull(artifact, "artifact must not be null");
73 try {
74 return match(
75 artifact.getGroupId(),
76 artifact.getArtifactId(),
77 artifact.getVersion(),
78 artifact.getType(),
79 artifact.getScope(),
80 artifact.getClassifier());
81 } catch (InvalidVersionSpecificationException e) {
82 throw new IllegalArgumentException(e);
83 }
84 }
85
86 public boolean match(Dependency dependency) {
87 Objects.requireNonNull(dependency, "dependency must not be null");
88 try {
89 return match(
90 dependency.getGroupId(),
91 dependency.getArtifactId(),
92 dependency.getVersion(),
93 dependency.getType(),
94 dependency.getScope(),
95 dependency.getClassifier());
96 } catch (InvalidVersionSpecificationException e) {
97 throw new IllegalArgumentException(e);
98 }
99 }
100
101 private boolean match(
102 String groupId, String artifactId, String version, String type, String scope, String classifier)
103 throws InvalidVersionSpecificationException {
104 switch (parts.length) {
105 case 6:
106 if (!matches(parts[5], classifier)) {
107 return false;
108 }
109 case 5:
110 if (scope == null || scope.equals("")) {
111 scope = Artifact.SCOPE_COMPILE;
112 }
113
114 if (!matches(parts[4], scope)) {
115 return false;
116 }
117 case 4:
118 if (type == null || type.equals("")) {
119 type = "jar";
120 }
121
122 if (!matches(parts[3], type)) {
123 return false;
124 }
125
126 case 3:
127 if (!matches(parts[2], version)) {
128 if (!containsVersion(
129 VersionRange.createFromVersionSpec(parts[2]), new DefaultArtifactVersion(version))) {
130 return false;
131 }
132 }
133
134 case 2:
135 if (!matches(parts[1], artifactId)) {
136 return false;
137 }
138 case 1:
139 return matches(parts[0], groupId);
140 default:
141 throw new AssertionError();
142 }
143 }
144
145 private boolean matches(String expression, String input) {
146 String regex = expression
147 .replace(".", "\\.")
148 .replace("*", ".*")
149 .replace(":", "\\:")
150 .replace('?', '.')
151 .replace("[", "\\[")
152 .replace("]", "\\]")
153 .replace("(", "\\(")
154 .replace(")", "\\)");
155
156
157 if (input == null) {
158 input = "";
159 }
160
161 return java.util.regex.Pattern.matches(regex, input);
162 }
163
164 @Override
165 public String toString() {
166 return pattern;
167 }
168 }
169
170 private final Collection<Pattern> excludePatterns = new HashSet<>();
171
172 private final Collection<Pattern> includePatterns = new HashSet<>();
173
174
175
176
177
178
179
180
181 public ArtifactMatcher(final Collection<String> excludeStrings, final Collection<String> includeStrings) {
182 ofNullable(excludeStrings).ifPresent(excludes -> excludes.stream()
183 .filter(StringUtils::isNotEmpty)
184 .map(Pattern::new)
185 .forEach(excludePatterns::add));
186 ofNullable(includeStrings).ifPresent(includes -> includes.stream()
187 .filter(StringUtils::isNotEmpty)
188 .map(Pattern::new)
189 .forEach(includePatterns::add));
190 }
191
192 private boolean match(Function<Pattern, Boolean> matcher) {
193 return excludePatterns.stream().anyMatch(matcher::apply)
194 && includePatterns.stream().noneMatch(matcher::apply);
195 }
196
197
198
199
200
201
202
203
204 public boolean match(Artifact artifact) {
205 return match(p -> p.match(artifact));
206 }
207
208
209
210
211
212
213
214
215 public boolean match(Dependency dependency) {
216 return match(p -> p.match(dependency));
217 }
218
219
220
221
222
223
224
225
226
227
228 public static boolean containsVersion(VersionRange allowedRange, ArtifactVersion theVersion) {
229 ArtifactVersion recommendedVersion = allowedRange.getRecommendedVersion();
230 if (recommendedVersion == null) {
231 return allowedRange.containsVersion(theVersion);
232 } else {
233
234 int compareTo = recommendedVersion.compareTo(theVersion);
235 return (compareTo <= 0);
236 }
237 }
238 }