View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.util.graph.manager;
20  
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.LinkedHashSet;
25  import java.util.Map;
26  import java.util.Objects;
27  
28  import org.eclipse.aether.artifact.Artifact;
29  import org.eclipse.aether.collection.DependencyCollectionContext;
30  import org.eclipse.aether.collection.DependencyManagement;
31  import org.eclipse.aether.collection.DependencyManager;
32  import org.eclipse.aether.graph.Dependency;
33  import org.eclipse.aether.graph.Exclusion;
34  import org.eclipse.aether.scope.ScopeManager;
35  import org.eclipse.aether.scope.SystemDependencyScope;
36  
37  import static java.util.Objects.requireNonNull;
38  
39  /**
40   * A dependency manager support class.
41   *
42   * @since 2.0.0
43   */
44  public abstract class AbstractDependencyManager implements DependencyManager {
45  
46      protected final int depth;
47  
48      protected final int deriveUntil;
49  
50      protected final int applyFrom;
51  
52      protected final Map<Object, String> managedVersions;
53  
54      protected final Map<Object, String> managedScopes;
55  
56      protected final Map<Object, Boolean> managedOptionals;
57  
58      protected final Map<Object, String> managedLocalPaths;
59  
60      protected final Map<Object, Collection<Exclusion>> managedExclusions;
61  
62      protected final SystemDependencyScope systemDependencyScope;
63  
64      private final int hashCode;
65  
66      protected AbstractDependencyManager(int deriveUntil, int applyFrom, ScopeManager scopeManager) {
67          this(
68                  0,
69                  deriveUntil,
70                  applyFrom,
71                  Collections.emptyMap(),
72                  Collections.emptyMap(),
73                  Collections.emptyMap(),
74                  Collections.emptyMap(),
75                  Collections.emptyMap(),
76                  scopeManager != null
77                          ? scopeManager.getSystemDependencyScope().orElse(null)
78                          : SystemDependencyScope.LEGACY);
79      }
80  
81      @SuppressWarnings("checkstyle:ParameterNumber")
82      protected AbstractDependencyManager(
83              int depth,
84              int deriveUntil,
85              int applyFrom,
86              Map<Object, String> managedVersions,
87              Map<Object, String> managedScopes,
88              Map<Object, Boolean> managedOptionals,
89              Map<Object, String> managedLocalPaths,
90              Map<Object, Collection<Exclusion>> managedExclusions,
91              SystemDependencyScope systemDependencyScope) {
92          this.depth = depth;
93          this.deriveUntil = deriveUntil;
94          this.applyFrom = applyFrom;
95          this.managedVersions = requireNonNull(managedVersions);
96          this.managedScopes = requireNonNull(managedScopes);
97          this.managedOptionals = requireNonNull(managedOptionals);
98          this.managedLocalPaths = requireNonNull(managedLocalPaths);
99          this.managedExclusions = requireNonNull(managedExclusions);
100         // nullable: if using scope manager, but there is no system scope defined
101         this.systemDependencyScope = systemDependencyScope;
102 
103         this.hashCode = Objects.hash(
104                 depth,
105                 deriveUntil,
106                 applyFrom,
107                 managedVersions,
108                 managedScopes,
109                 managedOptionals,
110                 managedLocalPaths,
111                 managedExclusions);
112     }
113 
114     protected abstract DependencyManager newInstance(
115             Map<Object, String> managedVersions,
116             Map<Object, String> managedScopes,
117             Map<Object, Boolean> managedOptionals,
118             Map<Object, String> managedLocalPaths,
119             Map<Object, Collection<Exclusion>> managedExclusions);
120 
121     @Override
122     public DependencyManager deriveChildManager(DependencyCollectionContext context) {
123         requireNonNull(context, "context cannot be null");
124         if (depth >= deriveUntil) {
125             return this;
126         }
127 
128         Map<Object, String> managedVersions = this.managedVersions;
129         Map<Object, String> managedScopes = this.managedScopes;
130         Map<Object, Boolean> managedOptionals = this.managedOptionals;
131         Map<Object, String> managedLocalPaths = this.managedLocalPaths;
132         Map<Object, Collection<Exclusion>> managedExclusions = this.managedExclusions;
133 
134         for (Dependency managedDependency : context.getManagedDependencies()) {
135             Artifact artifact = managedDependency.getArtifact();
136             Object key = new Key(artifact);
137 
138             String version = artifact.getVersion();
139             if (!version.isEmpty() && !managedVersions.containsKey(key)) {
140                 if (managedVersions == this.managedVersions) {
141                     managedVersions = new HashMap<>(this.managedVersions);
142                 }
143                 managedVersions.put(key, version);
144             }
145 
146             String scope = managedDependency.getScope();
147             if (!scope.isEmpty() && !managedScopes.containsKey(key)) {
148                 if (managedScopes == this.managedScopes) {
149                     managedScopes = new HashMap<>(this.managedScopes);
150                 }
151                 managedScopes.put(key, scope);
152             }
153 
154             Boolean optional = managedDependency.getOptional();
155             if (optional != null && !managedOptionals.containsKey(key)) {
156                 if (managedOptionals == this.managedOptionals) {
157                     managedOptionals = new HashMap<>(this.managedOptionals);
158                 }
159                 managedOptionals.put(key, optional);
160             }
161 
162             String localPath = systemDependencyScope == null
163                     ? null
164                     : systemDependencyScope.getSystemPath(managedDependency.getArtifact());
165             if (localPath != null && !managedLocalPaths.containsKey(key)) {
166                 if (managedLocalPaths == this.managedLocalPaths) {
167                     managedLocalPaths = new HashMap<>(this.managedLocalPaths);
168                 }
169                 managedLocalPaths.put(key, localPath);
170             }
171 
172             Collection<Exclusion> exclusions = managedDependency.getExclusions();
173             if (!exclusions.isEmpty()) {
174                 if (managedExclusions == this.managedExclusions) {
175                     managedExclusions = new HashMap<>(this.managedExclusions);
176                 }
177                 Collection<Exclusion> managed = managedExclusions.computeIfAbsent(key, k -> new LinkedHashSet<>());
178                 managed.addAll(exclusions);
179             }
180         }
181 
182         return newInstance(managedVersions, managedScopes, managedOptionals, managedLocalPaths, managedExclusions);
183     }
184 
185     @Override
186     public DependencyManagement manageDependency(Dependency dependency) {
187         requireNonNull(dependency, "dependency cannot be null");
188         DependencyManagement management = null;
189         Object key = new Key(dependency.getArtifact());
190 
191         if (depth >= applyFrom) {
192             String version = managedVersions.get(key);
193             if (version != null) {
194                 management = new DependencyManagement();
195                 management.setVersion(version);
196             }
197 
198             String scope = managedScopes.get(key);
199             if (scope != null) {
200                 if (management == null) {
201                     management = new DependencyManagement();
202                 }
203                 management.setScope(scope);
204 
205                 if (systemDependencyScope != null
206                         && !systemDependencyScope.is(scope)
207                         && systemDependencyScope.getSystemPath(dependency.getArtifact()) != null) {
208                     Map<String, String> properties =
209                             new HashMap<>(dependency.getArtifact().getProperties());
210                     systemDependencyScope.setSystemPath(properties, null);
211                     management.setProperties(properties);
212                 }
213             }
214 
215             if (systemDependencyScope != null
216                     && (systemDependencyScope.is(scope)
217                             || (scope == null && systemDependencyScope.is(dependency.getScope())))) {
218                 String localPath = managedLocalPaths.get(key);
219                 if (localPath != null) {
220                     if (management == null) {
221                         management = new DependencyManagement();
222                     }
223                     Map<String, String> properties =
224                             new HashMap<>(dependency.getArtifact().getProperties());
225                     systemDependencyScope.setSystemPath(properties, localPath);
226                     management.setProperties(properties);
227                 }
228             }
229 
230             Boolean optional = managedOptionals.get(key);
231             if (optional != null) {
232                 if (management == null) {
233                     management = new DependencyManagement();
234                 }
235                 management.setOptional(optional);
236             }
237         }
238 
239         Collection<Exclusion> exclusions = managedExclusions.get(key);
240         if (exclusions != null) {
241             if (management == null) {
242                 management = new DependencyManagement();
243             }
244             Collection<Exclusion> result = new LinkedHashSet<>(dependency.getExclusions());
245             result.addAll(exclusions);
246             management.setExclusions(result);
247         }
248 
249         return management;
250     }
251 
252     @Override
253     public boolean equals(Object obj) {
254         if (this == obj) {
255             return true;
256         } else if (null == obj || !getClass().equals(obj.getClass())) {
257             return false;
258         }
259 
260         AbstractDependencyManager that = (AbstractDependencyManager) obj;
261         return depth == that.depth
262                 && deriveUntil == that.deriveUntil
263                 && applyFrom == that.applyFrom
264                 && managedVersions.equals(that.managedVersions)
265                 && managedScopes.equals(that.managedScopes)
266                 && managedOptionals.equals(that.managedOptionals)
267                 && managedExclusions.equals(that.managedExclusions);
268     }
269 
270     @Override
271     public int hashCode() {
272         return hashCode;
273     }
274 
275     protected static class Key {
276 
277         private final Artifact artifact;
278 
279         private final int hashCode;
280 
281         Key(Artifact artifact) {
282             this.artifact = artifact;
283             this.hashCode = Objects.hash(artifact.getGroupId(), artifact.getArtifactId());
284         }
285 
286         @Override
287         public boolean equals(Object obj) {
288             if (obj == this) {
289                 return true;
290             } else if (!(obj instanceof Key)) {
291                 return false;
292             }
293             Key that = (Key) obj;
294             return artifact.getArtifactId().equals(that.artifact.getArtifactId())
295                     && artifact.getGroupId().equals(that.artifact.getGroupId())
296                     && artifact.getExtension().equals(that.artifact.getExtension())
297                     && artifact.getClassifier().equals(that.artifact.getClassifier());
298         }
299 
300         @Override
301         public int hashCode() {
302             return hashCode;
303         }
304 
305         @Override
306         public String toString() {
307             return String.valueOf(artifact);
308         }
309     }
310 }