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<Exclusion>( 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     private static class ExclusionComparator
194         implements Comparator<Exclusion>
195     {
196 
197         static final ExclusionComparator INSTANCE = new ExclusionComparator();
198 
199         public int compare( Exclusion e1, Exclusion e2 )
200         {
201             if ( e1 == null )
202             {
203                 return ( e2 == null ) ? 0 : 1;
204             }
205             else if ( e2 == null )
206             {
207                 return -1;
208             }
209             int rel = e1.getArtifactId().compareTo( e2.getArtifactId() );
210             if ( rel == 0 )
211             {
212                 rel = e1.getGroupId().compareTo( e2.getGroupId() );
213                 if ( rel == 0 )
214                 {
215                     rel = e1.getExtension().compareTo( e2.getExtension() );
216                     if ( rel == 0 )
217                     {
218                         rel = e1.getClassifier().compareTo( e2.getClassifier() );
219                     }
220                 }
221             }
222             return rel;
223         }
224 
225     }
226 
227 }