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