1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.artifact.filter;
20
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26
27 import org.apache.maven.artifact.Artifact;
28 import org.apache.maven.artifact.ArtifactUtils;
29 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
30 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
31 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
32 import org.apache.maven.artifact.versioning.VersionRange;
33 import org.slf4j.Logger;
34
35
36
37
38
39
40
41 public class OldPatternIncludesArtifactFilter implements ArtifactFilter, StatisticsReportingArtifactFilter {
42 private final List<String> positivePatterns;
43
44 private final List<String> negativePatterns;
45
46 private final boolean actTransitively;
47
48 private final Set<String> patternsTriggered = new HashSet<>();
49
50 private final List<String> filteredArtifactIds = new ArrayList<>();
51
52
53
54
55 public OldPatternIncludesArtifactFilter(final Collection<String> patterns) {
56 this(patterns, false);
57 }
58
59
60
61
62
63 public OldPatternIncludesArtifactFilter(final Collection<String> patterns, final boolean actTransitively) {
64 this.actTransitively = actTransitively;
65 final List<String> pos = new ArrayList<>();
66 final List<String> neg = new ArrayList<>();
67 if (patterns != null && !patterns.isEmpty()) {
68 for (String pattern : patterns) {
69 if (pattern.startsWith("!")) {
70 neg.add(pattern.substring(1));
71 } else {
72 pos.add(pattern);
73 }
74 }
75 }
76
77 positivePatterns = pos;
78 negativePatterns = neg;
79 }
80
81
82 public boolean include(final Artifact artifact) {
83 final boolean shouldInclude = patternMatches(artifact);
84
85 if (!shouldInclude) {
86 addFilteredArtifactId(artifact.getId());
87 }
88
89 return shouldInclude;
90 }
91
92
93
94
95
96 protected boolean patternMatches(final Artifact artifact) {
97 return positiveMatch(artifact) == Boolean.TRUE || negativeMatch(artifact) == Boolean.FALSE;
98 }
99
100
101
102
103 protected void addFilteredArtifactId(final String artifactId) {
104 filteredArtifactIds.add(artifactId);
105 }
106
107 private Boolean negativeMatch(final Artifact artifact) {
108 if (negativePatterns == null || negativePatterns.isEmpty()) {
109 return null;
110 } else {
111 return match(artifact, negativePatterns);
112 }
113 }
114
115
116
117
118
119 protected Boolean positiveMatch(final Artifact artifact) {
120 if (positivePatterns == null || positivePatterns.isEmpty()) {
121 return null;
122 } else {
123 return match(artifact, positivePatterns);
124 }
125 }
126
127 private boolean match(final Artifact artifact, final List<String> patterns) {
128 final String shortId = ArtifactUtils.versionlessKey(artifact);
129 final String id = artifact.getDependencyConflictId();
130 final String wholeId = artifact.getId();
131
132 if (matchAgainst(wholeId, patterns, false)) {
133 return true;
134 }
135
136 if (matchAgainst(id, patterns, false)) {
137 return true;
138 }
139
140 if (matchAgainst(shortId, patterns, false)) {
141 return true;
142 }
143
144 if (actTransitively) {
145 final List<String> depTrail = artifact.getDependencyTrail();
146
147 if (depTrail != null && depTrail.size() > 1) {
148 for (String trailItem : depTrail) {
149 if (matchAgainst(trailItem, patterns, true)) {
150 return true;
151 }
152 }
153 }
154 }
155
156 return false;
157 }
158
159 private boolean matchAgainst(final String value, final List<String> patterns, final boolean regionMatch) {
160 final String[] tokens = value.split(":");
161 for (String pattern : patterns) {
162 String[] patternTokens = pattern.split(":");
163
164 if (patternTokens.length == 5 && tokens.length < 5) {
165
166 if (!"*".equals(patternTokens[3])) {
167
168 return false;
169 }
170 patternTokens = new String[] {patternTokens[0], patternTokens[1], patternTokens[2], patternTokens[4]};
171 }
172
173
174 boolean matched = patternTokens.length <= tokens.length;
175
176 for (int i = 0; matched && i < patternTokens.length; i++) {
177 matched = matches(tokens[i], patternTokens[i]);
178 }
179
180
181
182 if (!matched && patternTokens.length < tokens.length && isFirstPatternWildcard(patternTokens)) {
183 matched = true;
184 int tokenOffset = tokens.length - patternTokens.length;
185 for (int i = 0; matched && i < patternTokens.length; i++) {
186 matched = matches(tokens[i + tokenOffset], patternTokens[i]);
187 }
188 }
189
190 if (matched) {
191 patternsTriggered.add(pattern);
192 return true;
193 }
194
195 if (regionMatch && value.contains(pattern)) {
196 patternsTriggered.add(pattern);
197 return true;
198 }
199 }
200 return false;
201 }
202
203 private boolean isFirstPatternWildcard(String[] patternTokens) {
204 return patternTokens.length > 0 && "*".equals(patternTokens[0]);
205 }
206
207
208
209
210
211
212
213
214 private boolean matches(final String token, final String pattern) {
215 boolean matches;
216
217
218 if ("*".equals(pattern) || pattern.length() == 0) {
219 matches = true;
220 }
221
222 else if (pattern.startsWith("*") && pattern.endsWith("*")) {
223 final String contains = pattern.substring(1, pattern.length() - 1);
224
225 matches = token.contains(contains);
226 }
227
228 else if (pattern.startsWith("*")) {
229 final String suffix = pattern.substring(1);
230
231 matches = token.endsWith(suffix);
232 }
233
234 else if (pattern.endsWith("*")) {
235 final String prefix = pattern.substring(0, pattern.length() - 1);
236
237 matches = token.startsWith(prefix);
238 }
239
240 else if (pattern.indexOf('*') > -1) {
241 String[] parts = pattern.split("\\*");
242 int lastPartEnd = -1;
243 boolean match = true;
244
245 for (String part : parts) {
246 int idx = token.indexOf(part);
247 if (idx <= lastPartEnd) {
248 match = false;
249 break;
250 }
251
252 lastPartEnd = idx + part.length();
253 }
254
255 matches = match;
256 }
257
258 else if (pattern.startsWith("[") || pattern.startsWith("(")) {
259 matches = isVersionIncludedInRange(token, pattern);
260 }
261
262 else {
263 matches = token.equals(pattern);
264 }
265
266 return matches;
267 }
268
269 private boolean isVersionIncludedInRange(final String version, final String range) {
270 try {
271 return VersionRange.createFromVersionSpec(range).containsVersion(new DefaultArtifactVersion(version));
272 } catch (final InvalidVersionSpecificationException e) {
273 return false;
274 }
275 }
276
277
278 public void reportMissedCriteria(final Logger logger) {
279
280 if (!positivePatterns.isEmpty() || !negativePatterns.isEmpty()) {
281 final List<String> missed = new ArrayList<>();
282 missed.addAll(positivePatterns);
283 missed.addAll(negativePatterns);
284
285 missed.removeAll(patternsTriggered);
286
287 if (!missed.isEmpty() && logger.isWarnEnabled()) {
288 final StringBuilder buffer = new StringBuilder();
289
290 buffer.append("The following patterns were never triggered in this ");
291 buffer.append(getFilterDescription());
292 buffer.append(':');
293
294 for (String pattern : missed) {
295 buffer.append("\no '").append(pattern).append("'");
296 }
297
298 buffer.append("\n");
299
300 logger.warn(buffer.toString());
301 }
302 }
303 }
304
305 @Override
306 public String toString() {
307 return "Includes filter:" + getPatternsAsString();
308 }
309
310
311
312
313 protected String getPatternsAsString() {
314 final StringBuilder buffer = new StringBuilder();
315 for (String pattern : positivePatterns) {
316 buffer.append("\no '").append(pattern).append("'");
317 }
318
319 return buffer.toString();
320 }
321
322
323
324
325 protected String getFilterDescription() {
326 return "artifact inclusion filter";
327 }
328
329
330 public void reportFilteredArtifacts(final Logger logger) {
331 if (!filteredArtifactIds.isEmpty() && logger.isDebugEnabled()) {
332 final StringBuilder buffer =
333 new StringBuilder("The following artifacts were removed by this " + getFilterDescription() + ": ");
334
335 for (String artifactId : filteredArtifactIds) {
336 buffer.append('\n').append(artifactId);
337 }
338
339 logger.debug(buffer.toString());
340 }
341 }
342
343
344 public boolean hasMissedCriteria() {
345
346 if (!positivePatterns.isEmpty() || !negativePatterns.isEmpty()) {
347 final List<String> missed = new ArrayList<>();
348 missed.addAll(positivePatterns);
349 missed.addAll(negativePatterns);
350
351 missed.removeAll(patternsTriggered);
352
353 return !missed.isEmpty();
354 }
355
356 return false;
357 }
358 }