View Javadoc
1   package org.eclipse.aether.util.filter;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Arrays;
23  import java.util.Collection;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Set;
27  
28  import org.eclipse.aether.artifact.Artifact;
29  import org.eclipse.aether.graph.Dependency;
30  import org.eclipse.aether.graph.DependencyFilter;
31  import org.eclipse.aether.graph.DependencyNode;
32  import org.eclipse.aether.version.InvalidVersionSpecificationException;
33  import org.eclipse.aether.version.Version;
34  import org.eclipse.aether.version.VersionRange;
35  import org.eclipse.aether.version.VersionScheme;
36  
37  /**
38   */
39  class AbstractPatternDependencyFilter
40      implements DependencyFilter
41  {
42  
43      private final Set<String> patterns = new HashSet<String>();
44  
45      private final VersionScheme versionScheme;
46  
47      /**
48       * Creates a new filter using the specified patterns.
49       * 
50       * @param patterns The include patterns, may be {@code null} or empty to include no artifacts.
51       */
52      public AbstractPatternDependencyFilter( final String... patterns )
53      {
54          this( null, patterns );
55      }
56  
57      /**
58       * Creates a new filter using the specified patterns.
59       * 
60       * @param versionScheme To be used for parsing versions/version ranges. If {@code null} and pattern specifies a
61       *            range no artifact will be included.
62       * @param patterns The include patterns, may be {@code null} or empty to include no artifacts.
63       */
64      public AbstractPatternDependencyFilter( final VersionScheme versionScheme, final String... patterns )
65      {
66          this( versionScheme, patterns == null ? null : Arrays.asList( patterns ) );
67      }
68  
69      /**
70       * Creates a new filter using the specified patterns.
71       * 
72       * @param patterns The include patterns, may be {@code null} or empty to include no artifacts.
73       */
74      public AbstractPatternDependencyFilter( final Collection<String> patterns )
75      {
76          this( null, patterns );
77      }
78  
79      /**
80       * Creates a new filter using the specified patterns and {@link VersionScheme} .
81       * 
82       * @param versionScheme To be used for parsing versions/version ranges. If {@code null} and pattern specifies a
83       *            range no artifact will be included.
84       * @param patterns The include patterns, may be {@code null} or empty to include no artifacts.
85       */
86      public AbstractPatternDependencyFilter( final VersionScheme versionScheme, final Collection<String> patterns )
87      {
88          if ( patterns != null )
89          {
90              this.patterns.addAll( patterns );
91          }
92          this.versionScheme = versionScheme;
93      }
94  
95      public boolean accept( final DependencyNode node, List<DependencyNode> parents )
96      {
97          final Dependency dependency = node.getDependency();
98          if ( dependency == null )
99          {
100             return true;
101         }
102         return accept( dependency.getArtifact() );
103     }
104 
105     protected boolean accept( final Artifact artifact )
106     {
107         for ( final String pattern : patterns )
108         {
109             final boolean matched = accept( artifact, pattern );
110             if ( matched )
111             {
112                 return true;
113             }
114         }
115         return false;
116     }
117 
118     private boolean accept( final Artifact artifact, final String pattern )
119     {
120         final String[] tokens =
121             new String[] { artifact.getGroupId(), artifact.getArtifactId(), artifact.getExtension(),
122                 artifact.getBaseVersion() };
123 
124         final String[] patternTokens = pattern.split( ":" );
125 
126         // fail immediately if pattern tokens outnumber tokens to match
127         boolean matched = ( patternTokens.length <= tokens.length );
128 
129         for ( int i = 0; matched && i < patternTokens.length; i++ )
130         {
131             matched = matches( tokens[i], patternTokens[i] );
132         }
133 
134         return matched;
135     }
136 
137     private boolean matches( final String token, final String pattern )
138     {
139         boolean matches;
140 
141         // support full wildcard and implied wildcard
142         if ( "*".equals( pattern ) || pattern.length() == 0 )
143         {
144             matches = true;
145         }
146         // support contains wildcard
147         else if ( pattern.startsWith( "*" ) && pattern.endsWith( "*" ) )
148         {
149             final String contains = pattern.substring( 1, pattern.length() - 1 );
150 
151             matches = ( token.contains( contains ) );
152         }
153         // support leading wildcard
154         else if ( pattern.startsWith( "*" ) )
155         {
156             final String suffix = pattern.substring( 1, pattern.length() );
157 
158             matches = token.endsWith( suffix );
159         }
160         // support trailing wildcard
161         else if ( pattern.endsWith( "*" ) )
162         {
163             final String prefix = pattern.substring( 0, pattern.length() - 1 );
164 
165             matches = token.startsWith( prefix );
166         }
167         // support versions range
168         else if ( pattern.startsWith( "[" ) || pattern.startsWith( "(" ) )
169         {
170             matches = isVersionIncludedInRange( token, pattern );
171         }
172         // support exact match
173         else
174         {
175             matches = token.equals( pattern );
176         }
177 
178         return matches;
179     }
180 
181     private boolean isVersionIncludedInRange( final String version, final String range )
182     {
183         if ( versionScheme == null )
184         {
185             return false;
186         }
187         else
188         {
189             try
190             {
191                 final Version parsedVersion = versionScheme.parseVersion( version );
192                 final VersionRange parsedRange = versionScheme.parseVersionRange( range );
193 
194                 return parsedRange.containsVersion( parsedVersion );
195             }
196             catch ( final InvalidVersionSpecificationException e )
197             {
198                 return false;
199             }
200         }
201     }
202 
203     @Override
204     public boolean equals( final Object obj )
205     {
206         if ( this == obj )
207         {
208             return true;
209         }
210 
211         if ( obj == null || !getClass().equals( obj.getClass() ) )
212         {
213             return false;
214         }
215 
216         final AbstractPatternDependencyFilter that = (AbstractPatternDependencyFilter) obj;
217 
218         return this.patterns.equals( that.patterns )
219             && ( this.versionScheme == null ? that.versionScheme == null
220                             : this.versionScheme.equals( that.versionScheme ) );
221     }
222 
223     @Override
224     public int hashCode()
225     {
226         int hash = 17;
227         hash = hash * 31 + patterns.hashCode();
228         hash = hash * 31 + ( ( versionScheme == null ) ? 0 : versionScheme.hashCode() );
229         return hash;
230     }
231 
232 }