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.Objects;
27  import java.util.Set;
28  
29  import org.eclipse.aether.artifact.Artifact;
30  import org.eclipse.aether.graph.Dependency;
31  import org.eclipse.aether.graph.DependencyFilter;
32  import org.eclipse.aether.graph.DependencyNode;
33  import org.eclipse.aether.version.InvalidVersionSpecificationException;
34  import org.eclipse.aether.version.Version;
35  import org.eclipse.aether.version.VersionRange;
36  import org.eclipse.aether.version.VersionScheme;
37  
38  /**
39   */
40  class AbstractPatternDependencyFilter
41      implements DependencyFilter
42  {
43  
44      private final Set<String> patterns = new HashSet<>();
45  
46      private final VersionScheme versionScheme;
47  
48      /**
49       * Creates a new filter using the specified patterns.
50       * 
51       * @param patterns The include patterns, may be {@code null} or empty to include no artifacts.
52       */
53      AbstractPatternDependencyFilter( final String... patterns )
54      {
55          this( null, patterns );
56      }
57  
58      /**
59       * Creates a new filter using the specified patterns.
60       * 
61       * @param versionScheme To be used for parsing versions/version ranges. If {@code null} and pattern specifies a
62       *            range no artifact will be included.
63       * @param patterns The include patterns, may be {@code null} or empty to include no artifacts.
64       */
65      AbstractPatternDependencyFilter( final VersionScheme versionScheme, final String... patterns )
66      {
67          this( versionScheme, patterns == null ? null : Arrays.asList( patterns ) );
68      }
69  
70      /**
71       * Creates a new filter using the specified patterns.
72       * 
73       * @param patterns The include patterns, may be {@code null} or empty to include no artifacts.
74       */
75      AbstractPatternDependencyFilter( final Collection<String> patterns )
76      {
77          this( null, patterns );
78      }
79  
80      /**
81       * Creates a new filter using the specified patterns and {@link VersionScheme} .
82       * 
83       * @param versionScheme To be used for parsing versions/version ranges. If {@code null} and pattern specifies a
84       *            range no artifact will be included.
85       * @param patterns The include patterns, may be {@code null} or empty to include no artifacts.
86       */
87      AbstractPatternDependencyFilter( final VersionScheme versionScheme, final Collection<String> patterns )
88      {
89          if ( patterns != null )
90          {
91              this.patterns.addAll( patterns );
92          }
93          this.versionScheme = versionScheme;
94      }
95  
96      public boolean accept( final DependencyNode node, List<DependencyNode> parents )
97      {
98          final Dependency dependency = node.getDependency();
99          if ( dependency == null )
100         {
101             return true;
102         }
103         return accept( dependency.getArtifact() );
104     }
105 
106     protected boolean accept( final Artifact artifact )
107     {
108         for ( final String pattern : patterns )
109         {
110             final boolean matched = accept( artifact, pattern );
111             if ( matched )
112             {
113                 return true;
114             }
115         }
116         return false;
117     }
118 
119     private boolean accept( final Artifact artifact, final String pattern )
120     {
121         final String[] tokens =
122             new String[] { artifact.getGroupId(), artifact.getArtifactId(), artifact.getExtension(),
123                 artifact.getBaseVersion() };
124 
125         final String[] patternTokens = pattern.split( ":" );
126 
127         // fail immediately if pattern tokens outnumber tokens to match
128         boolean matched = ( patternTokens.length <= tokens.length );
129 
130         for ( int i = 0; matched && i < patternTokens.length; i++ )
131         {
132             matched = matches( tokens[i], patternTokens[i] );
133         }
134 
135         return matched;
136     }
137 
138     private boolean matches( final String token, final String pattern )
139     {
140         boolean matches;
141 
142         // support full wildcard and implied wildcard
143         if ( "*".equals( pattern ) || pattern.length() == 0 )
144         {
145             matches = true;
146         }
147         // support contains wildcard
148         else if ( pattern.startsWith( "*" ) && pattern.endsWith( "*" ) )
149         {
150             final String contains = pattern.substring( 1, pattern.length() - 1 );
151 
152             matches = ( token.contains( contains ) );
153         }
154         // support leading wildcard
155         else if ( pattern.startsWith( "*" ) )
156         {
157             final String suffix = pattern.substring( 1 );
158 
159             matches = token.endsWith( suffix );
160         }
161         // support trailing wildcard
162         else if ( pattern.endsWith( "*" ) )
163         {
164             final String prefix = pattern.substring( 0, pattern.length() - 1 );
165 
166             matches = token.startsWith( prefix );
167         }
168         // support versions range
169         else if ( pattern.startsWith( "[" ) || pattern.startsWith( "(" ) )
170         {
171             matches = isVersionIncludedInRange( token, pattern );
172         }
173         // support exact match
174         else
175         {
176             matches = token.equals( pattern );
177         }
178 
179         return matches;
180     }
181 
182     private boolean isVersionIncludedInRange( final String version, final String range )
183     {
184         if ( versionScheme == null )
185         {
186             return false;
187         }
188         else
189         {
190             try
191             {
192                 final Version parsedVersion = versionScheme.parseVersion( version );
193                 final VersionRange parsedRange = versionScheme.parseVersionRange( range );
194 
195                 return parsedRange.containsVersion( parsedVersion );
196             }
197             catch ( final InvalidVersionSpecificationException e )
198             {
199                 return false;
200             }
201         }
202     }
203 
204     @Override
205     public boolean equals( final Object obj )
206     {
207         if ( this == obj )
208         {
209             return true;
210         }
211 
212         if ( obj == null || !getClass().equals( obj.getClass() ) )
213         {
214             return false;
215         }
216 
217         final AbstractPatternDependencyFilter that = (AbstractPatternDependencyFilter) obj;
218 
219         return Objects.equals( this.patterns, that.patterns )
220             && Objects.equals( this.versionScheme, 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 }