View Javadoc
1   package org.eclipse.aether.util.graph.manager;
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.Collection;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.LinkedHashSet;
26  import java.util.Map;
27  
28  import org.eclipse.aether.artifact.Artifact;
29  import org.eclipse.aether.artifact.ArtifactProperties;
30  import org.eclipse.aether.collection.DependencyCollectionContext;
31  import org.eclipse.aether.collection.DependencyManagement;
32  import org.eclipse.aether.collection.DependencyManager;
33  import org.eclipse.aether.graph.Dependency;
34  import org.eclipse.aether.graph.Exclusion;
35  import org.eclipse.aether.util.artifact.JavaScopes;
36  
37  import static java.util.Objects.requireNonNull;
38  
39  /**
40   * A dependency manager that mimics the way Maven 2.x works.
41   */
42  public final class ClassicDependencyManager
43      implements DependencyManager
44  {
45  
46      private final int depth;
47  
48      private final Map<Object, String> managedVersions;
49  
50      private final Map<Object, String> managedScopes;
51  
52      private final Map<Object, Boolean> managedOptionals;
53  
54      private final Map<Object, String> managedLocalPaths;
55  
56      private final Map<Object, Collection<Exclusion>> managedExclusions;
57  
58      private int hashCode;
59  
60      /**
61       * Creates a new dependency manager without any management information.
62       */
63      public ClassicDependencyManager()
64      {
65          this( 0, Collections.<Object, String>emptyMap(), Collections.<Object, String>emptyMap(),
66                Collections.<Object, Boolean>emptyMap(), Collections.<Object, String>emptyMap(),
67                Collections.<Object, Collection<Exclusion>>emptyMap() );
68      }
69  
70      private ClassicDependencyManager( int depth, Map<Object, String> managedVersions,
71                                        Map<Object, String> managedScopes, Map<Object, Boolean> managedOptionals,
72                                        Map<Object, String> managedLocalPaths,
73                                        Map<Object, Collection<Exclusion>> managedExclusions )
74      {
75          this.depth = depth;
76          this.managedVersions = managedVersions;
77          this.managedScopes = managedScopes;
78          this.managedOptionals = managedOptionals;
79          this.managedLocalPaths = managedLocalPaths;
80          this.managedExclusions = managedExclusions;
81      }
82  
83      public DependencyManager deriveChildManager( DependencyCollectionContext context )
84      {
85          requireNonNull( context, "context cannot be null" );
86          if ( depth >= 2 )
87          {
88              return this;
89          }
90          else if ( depth == 1 )
91          {
92              return new ClassicDependencyManager( depth + 1, managedVersions, managedScopes, managedOptionals,
93                                                   managedLocalPaths, managedExclusions );
94          }
95  
96          Map<Object, String> managedVersions = this.managedVersions;
97          Map<Object, String> managedScopes = this.managedScopes;
98          Map<Object, Boolean> managedOptionals = this.managedOptionals;
99          Map<Object, String> managedLocalPaths = this.managedLocalPaths;
100         Map<Object, Collection<Exclusion>> managedExclusions = this.managedExclusions;
101 
102         for ( Dependency managedDependency : context.getManagedDependencies() )
103         {
104             Artifact artifact = managedDependency.getArtifact();
105             Object key = getKey( artifact );
106 
107             String version = artifact.getVersion();
108             if ( version.length() > 0 && !managedVersions.containsKey( key ) )
109             {
110                 if ( managedVersions == this.managedVersions )
111                 {
112                     managedVersions = new HashMap<>( this.managedVersions );
113                 }
114                 managedVersions.put( key, version );
115             }
116 
117             String scope = managedDependency.getScope();
118             if ( scope.length() > 0 && !managedScopes.containsKey( key ) )
119             {
120                 if ( managedScopes == this.managedScopes )
121                 {
122                     managedScopes = new HashMap<>( this.managedScopes );
123                 }
124                 managedScopes.put( key, scope );
125             }
126 
127             Boolean optional = managedDependency.getOptional();
128             if ( optional != null && !managedOptionals.containsKey( key ) )
129             {
130                 if ( managedOptionals == this.managedOptionals )
131                 {
132                     managedOptionals = new HashMap<>( this.managedOptionals );
133                 }
134                 managedOptionals.put( key, optional );
135             }
136 
137             String localPath = managedDependency.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null );
138             if ( localPath != null && !managedLocalPaths.containsKey( key ) )
139             {
140                 if ( managedLocalPaths == this.managedLocalPaths )
141                 {
142                     managedLocalPaths = new HashMap<>( this.managedLocalPaths );
143                 }
144                 managedLocalPaths.put( key, localPath );
145             }
146 
147             Collection<Exclusion> exclusions = managedDependency.getExclusions();
148             if ( !exclusions.isEmpty() )
149             {
150                 if ( managedExclusions == this.managedExclusions )
151                 {
152                     managedExclusions = new HashMap<>( this.managedExclusions );
153                 }
154                 Collection<Exclusion> managed = managedExclusions.computeIfAbsent( key, k -> new LinkedHashSet<>() );
155                 managed.addAll( exclusions );
156             }
157         }
158 
159         return new ClassicDependencyManager( depth + 1, managedVersions, managedScopes, managedOptionals,
160                                              managedLocalPaths, managedExclusions );
161     }
162 
163     public DependencyManagement manageDependency( Dependency dependency )
164     {
165         requireNonNull( dependency, "dependency cannot be null" );
166         DependencyManagement management = null;
167 
168         Object key = getKey( dependency.getArtifact() );
169 
170         if ( depth >= 2 )
171         {
172             String version = managedVersions.get( key );
173             if ( version != null )
174             {
175                 management = new DependencyManagement();
176                 management.setVersion( version );
177             }
178 
179             String scope = managedScopes.get( key );
180             if ( scope != null )
181             {
182                 if ( management == null )
183                 {
184                     management = new DependencyManagement();
185                 }
186                 management.setScope( scope );
187 
188                 if ( !JavaScopes.SYSTEM.equals( scope )
189                     && dependency.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) != null )
190                 {
191                     Map<String, String> properties =
192                         new HashMap<>( dependency.getArtifact().getProperties() );
193                     properties.remove( ArtifactProperties.LOCAL_PATH );
194                     management.setProperties( properties );
195                 }
196             }
197 
198             if ( ( JavaScopes.SYSTEM.equals( scope ) )
199                 || ( scope == null && JavaScopes.SYSTEM.equals( dependency.getScope() ) ) )
200             {
201                 String localPath = managedLocalPaths.get( key );
202                 if ( localPath != null )
203                 {
204                     if ( management == null )
205                     {
206                         management = new DependencyManagement();
207                     }
208                     Map<String, String> properties =
209                         new HashMap<>( dependency.getArtifact().getProperties() );
210                     properties.put( ArtifactProperties.LOCAL_PATH, localPath );
211                     management.setProperties( properties );
212                 }
213             }
214 
215             Boolean optional = managedOptionals.get( key );
216             if ( optional != null )
217             {
218                 if ( management == null )
219                 {
220                     management = new DependencyManagement();
221                 }
222                 management.setOptional( optional );
223             }
224         }
225 
226         Collection<Exclusion> exclusions = managedExclusions.get( key );
227         if ( exclusions != null )
228         {
229             if ( management == null )
230             {
231                 management = new DependencyManagement();
232             }
233             Collection<Exclusion> result = new LinkedHashSet<>( dependency.getExclusions() );
234             result.addAll( exclusions );
235             management.setExclusions( result );
236         }
237 
238         return management;
239     }
240 
241     private Object getKey( Artifact a )
242     {
243         return new Key( a );
244     }
245 
246     @Override
247     public boolean equals( Object obj )
248     {
249         if ( this == obj )
250         {
251             return true;
252         }
253         else if ( null == obj || !getClass().equals( obj.getClass() ) )
254         {
255             return false;
256         }
257 
258         ClassicDependencyManager that = (ClassicDependencyManager) obj;
259         return depth == that.depth && managedVersions.equals( that.managedVersions )
260             && managedScopes.equals( that.managedScopes ) && managedOptionals.equals( that.managedOptionals )
261             && managedExclusions.equals( that.managedExclusions );
262     }
263 
264     @Override
265     public int hashCode()
266     {
267         if ( hashCode == 0 )
268         {
269             int hash = 17;
270             hash = hash * 31 + depth;
271             hash = hash * 31 + managedVersions.hashCode();
272             hash = hash * 31 + managedScopes.hashCode();
273             hash = hash * 31 + managedOptionals.hashCode();
274             hash = hash * 31 + managedExclusions.hashCode();
275             hashCode = hash;
276         }
277         return hashCode;
278     }
279 
280     static class Key
281     {
282 
283         private final Artifact artifact;
284 
285         private final int hashCode;
286 
287         Key( Artifact artifact )
288         {
289             this.artifact = artifact;
290 
291             int hash = 17;
292             hash = hash * 31 + artifact.getGroupId().hashCode();
293             hash = hash * 31 + artifact.getArtifactId().hashCode();
294             hashCode = hash;
295         }
296 
297         @Override
298         public boolean equals( Object obj )
299         {
300             if ( obj == this )
301             {
302                 return true;
303             }
304             else if ( !( obj instanceof Key ) )
305             {
306                 return false;
307             }
308             Key that = (Key) obj;
309             return artifact.getArtifactId().equals( that.artifact.getArtifactId() )
310                 && artifact.getGroupId().equals( that.artifact.getGroupId() )
311                 && artifact.getExtension().equals( that.artifact.getExtension() )
312                 && artifact.getClassifier().equals( that.artifact.getClassifier() );
313         }
314 
315         @Override
316         public int hashCode()
317         {
318             return hashCode;
319         }
320 
321     }
322 
323 }