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