View Javadoc
1   package org.eclipse.aether.util.graph.selector;
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.Comparator;
25  import java.util.TreeSet;
26  
27  import org.eclipse.aether.artifact.Artifact;
28  import org.eclipse.aether.collection.DependencyCollectionContext;
29  import org.eclipse.aether.collection.DependencySelector;
30  import org.eclipse.aether.graph.Dependency;
31  import org.eclipse.aether.graph.Exclusion;
32  
33  /**
34   * A dependency selector that applies exclusions based on artifact coordinates.
35   * 
36   * @see Dependency#getExclusions()
37   */
38  public final class ExclusionDependencySelector
39      implements DependencySelector
40  {
41  
42      // sorted and dupe-free array, faster to iterate than LinkedHashSet
43      private final Exclusion[] exclusions;
44  
45      private int hashCode;
46  
47      /**
48       * Creates a new selector without any exclusions.
49       */
50      public ExclusionDependencySelector()
51      {
52          this.exclusions = new Exclusion[0];
53      }
54  
55      /**
56       * Creates a new selector with the specified exclusions.
57       * 
58       * @param exclusions The exclusions, may be {@code null}.
59       */
60      public ExclusionDependencySelector( Collection<Exclusion> exclusions )
61      {
62          if ( exclusions != null && !exclusions.isEmpty() )
63          {
64              TreeSet<Exclusion> sorted = new TreeSet<>( ExclusionComparator.INSTANCE );
65              sorted.addAll( exclusions );
66              this.exclusions = sorted.toArray( new Exclusion[sorted.size()] );
67          }
68          else
69          {
70              this.exclusions = new Exclusion[0];
71          }
72      }
73  
74      private ExclusionDependencySelector( Exclusion[] exclusions )
75      {
76          this.exclusions = exclusions;
77      }
78  
79      public boolean selectDependency( Dependency dependency )
80      {
81          Artifact artifact = dependency.getArtifact();
82          for ( Exclusion exclusion : exclusions )
83          {
84              if ( matches( exclusion, artifact ) )
85              {
86                  return false;
87              }
88          }
89          return true;
90      }
91  
92      private boolean matches( Exclusion exclusion, Artifact artifact )
93      {
94          if ( !matches( exclusion.getArtifactId(), artifact.getArtifactId() ) )
95          {
96              return false;
97          }
98          if ( !matches( exclusion.getGroupId(), artifact.getGroupId() ) )
99          {
100             return false;
101         }
102         if ( !matches( exclusion.getExtension(), artifact.getExtension() ) )
103         {
104             return false;
105         }
106         if ( !matches( exclusion.getClassifier(), artifact.getClassifier() ) )
107         {
108             return false;
109         }
110         return true;
111     }
112 
113     private boolean matches( String pattern, String value )
114     {
115         return "*".equals( pattern ) || pattern.equals( value );
116     }
117 
118     public DependencySelector deriveChildSelector( DependencyCollectionContext context )
119     {
120         Dependency dependency = context.getDependency();
121         Collection<Exclusion> exclusions = ( dependency != null ) ? dependency.getExclusions() : null;
122         if ( exclusions == null || exclusions.isEmpty() )
123         {
124             return this;
125         }
126 
127         Exclusion[] merged = this.exclusions;
128         int count = merged.length;
129         for ( Exclusion exclusion : exclusions )
130         {
131             int index = Arrays.binarySearch( merged, exclusion, ExclusionComparator.INSTANCE );
132             if ( index < 0 )
133             {
134                 index = -( index + 1 );
135                 if ( count >= merged.length )
136                 {
137                     Exclusion[] tmp = new Exclusion[merged.length + exclusions.size()];
138                     System.arraycopy( merged, 0, tmp, 0, index );
139                     tmp[index] = exclusion;
140                     System.arraycopy( merged, index, tmp, index + 1, count - index );
141                     merged = tmp;
142                 }
143                 else
144                 {
145                     System.arraycopy( merged, index, merged, index + 1, count - index );
146                     merged[index] = exclusion;
147                 }
148                 count++;
149             }
150         }
151         if ( merged == this.exclusions )
152         {
153             return this;
154         }
155         if ( merged.length != count )
156         {
157             Exclusion[] tmp = new Exclusion[count];
158             System.arraycopy( merged, 0, tmp, 0, count );
159             merged = tmp;
160         }
161 
162         return new ExclusionDependencySelector( merged );
163     }
164 
165     @Override
166     public boolean equals( Object obj )
167     {
168         if ( this == obj )
169         {
170             return true;
171         }
172         else if ( null == obj || !getClass().equals( obj.getClass() ) )
173         {
174             return false;
175         }
176 
177         ExclusionDependencySelector that = (ExclusionDependencySelector) obj;
178         return Arrays.equals( exclusions, that.exclusions );
179     }
180 
181     @Override
182     public int hashCode()
183     {
184         if ( hashCode == 0 )
185         {
186             int hash = getClass().hashCode();
187             hash = hash * 31 + Arrays.hashCode( exclusions );
188             hashCode = hash;
189         }
190         return hashCode;
191     }
192 
193     @Override
194     public String toString()
195     {
196         StringBuilder builder = new StringBuilder().append( this.getClass().getSimpleName() ).append( '(' );
197         for ( int i = 0; i < this.exclusions.length; i++ )
198         {
199             builder.append( this.exclusions[i] );
200             if ( i < this.exclusions.length - 1 )
201             {
202                 builder.append( ", " );
203             }
204         }
205         return builder.append( ')' ).toString();
206     }
207 
208     private static class ExclusionComparator
209         implements Comparator<Exclusion>
210     {
211 
212         static final ExclusionComparator INSTANCE = new ExclusionComparator();
213 
214         public int compare( Exclusion e1, Exclusion e2 )
215         {
216             if ( e1 == null )
217             {
218                 return ( e2 == null ) ? 0 : 1;
219             }
220             else if ( e2 == null )
221             {
222                 return -1;
223             }
224             int rel = e1.getArtifactId().compareTo( e2.getArtifactId() );
225             if ( rel == 0 )
226             {
227                 rel = e1.getGroupId().compareTo( e2.getGroupId() );
228                 if ( rel == 0 )
229                 {
230                     rel = e1.getExtension().compareTo( e2.getExtension() );
231                     if ( rel == 0 )
232                     {
233                         rel = e1.getClassifier().compareTo( e2.getClassifier() );
234                     }
235                 }
236             }
237             return rel;
238         }
239 
240     }
241 
242 }