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