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