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