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.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 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      private final int hashCode;
63  
64      /**
65       * Creates a new dependency manager without any management information.
66       */
67      protected AbstractDependencyManager(int deriveUntil, int applyFrom) {
68          this(
69                  0,
70                  deriveUntil,
71                  applyFrom,
72                  Collections.emptyMap(),
73                  Collections.emptyMap(),
74                  Collections.emptyMap(),
75                  Collections.emptyMap(),
76                  Collections.emptyMap());
77      }
78  
79      @SuppressWarnings("checkstyle:ParameterNumber")
80      protected AbstractDependencyManager(
81              int depth,
82              int deriveUntil,
83              int applyFrom,
84              Map<Object, String> managedVersions,
85              Map<Object, String> managedScopes,
86              Map<Object, Boolean> managedOptionals,
87              Map<Object, String> managedLocalPaths,
88              Map<Object, Collection<Exclusion>> managedExclusions) {
89          this.depth = depth;
90          this.deriveUntil = deriveUntil;
91          this.applyFrom = applyFrom;
92          this.managedVersions = managedVersions;
93          this.managedScopes = managedScopes;
94          this.managedOptionals = managedOptionals;
95          this.managedLocalPaths = managedLocalPaths;
96          this.managedExclusions = managedExclusions;
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 = managedDependency.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null);
158             if (localPath != null && !managedLocalPaths.containsKey(key)) {
159                 if (managedLocalPaths == this.managedLocalPaths) {
160                     managedLocalPaths = new HashMap<>(this.managedLocalPaths);
161                 }
162                 managedLocalPaths.put(key, localPath);
163             }
164 
165             Collection<Exclusion> exclusions = managedDependency.getExclusions();
166             if (!exclusions.isEmpty()) {
167                 if (managedExclusions == this.managedExclusions) {
168                     managedExclusions = new HashMap<>(this.managedExclusions);
169                 }
170                 Collection<Exclusion> managed = managedExclusions.computeIfAbsent(key, k -> new LinkedHashSet<>());
171                 managed.addAll(exclusions);
172             }
173         }
174 
175         return newInstance(managedVersions, managedScopes, managedOptionals, managedLocalPaths, managedExclusions);
176     }
177 
178     @Override
179     public DependencyManagement manageDependency(Dependency dependency) {
180         requireNonNull(dependency, "dependency cannot be null");
181         DependencyManagement management = null;
182         Object key = new Key(dependency.getArtifact());
183 
184         if (depth >= applyFrom) {
185             String version = managedVersions.get(key);
186             if (version != null) {
187                 management = new DependencyManagement();
188                 management.setVersion(version);
189             }
190 
191             String scope = managedScopes.get(key);
192             if (scope != null) {
193                 if (management == null) {
194                     management = new DependencyManagement();
195                 }
196                 management.setScope(scope);
197 
198                 if (!JavaScopes.SYSTEM.equals(scope)
199                         && dependency.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) {
200                     Map<String, String> properties =
201                             new HashMap<>(dependency.getArtifact().getProperties());
202                     properties.remove(ArtifactProperties.LOCAL_PATH);
203                     management.setProperties(properties);
204                 }
205             }
206 
207             if ((JavaScopes.SYSTEM.equals(scope))
208                     || (scope == null && JavaScopes.SYSTEM.equals(dependency.getScope()))) {
209                 String localPath = managedLocalPaths.get(key);
210                 if (localPath != null) {
211                     if (management == null) {
212                         management = new DependencyManagement();
213                     }
214                     Map<String, String> properties =
215                             new HashMap<>(dependency.getArtifact().getProperties());
216                     properties.put(ArtifactProperties.LOCAL_PATH, localPath);
217                     management.setProperties(properties);
218                 }
219             }
220 
221             Boolean optional = managedOptionals.get(key);
222             if (optional != null) {
223                 if (management == null) {
224                     management = new DependencyManagement();
225                 }
226                 management.setOptional(optional);
227             }
228         }
229 
230         Collection<Exclusion> exclusions = managedExclusions.get(key);
231         if (exclusions != null) {
232             if (management == null) {
233                 management = new DependencyManagement();
234             }
235             Collection<Exclusion> result = new LinkedHashSet<>(dependency.getExclusions());
236             result.addAll(exclusions);
237             management.setExclusions(result);
238         }
239 
240         return management;
241     }
242 
243     @Override
244     public boolean equals(Object obj) {
245         if (this == obj) {
246             return true;
247         } else if (null == obj || !getClass().equals(obj.getClass())) {
248             return false;
249         }
250 
251         AbstractDependencyManager that = (AbstractDependencyManager) obj;
252         return depth == that.depth
253                 && deriveUntil == that.deriveUntil
254                 && applyFrom == that.applyFrom
255                 && managedVersions.equals(that.managedVersions)
256                 && managedScopes.equals(that.managedScopes)
257                 && managedOptionals.equals(that.managedOptionals)
258                 && managedExclusions.equals(that.managedExclusions);
259     }
260 
261     @Override
262     public int hashCode() {
263         return hashCode;
264     }
265 
266     protected static class Key {
267 
268         private final Artifact artifact;
269 
270         private final int hashCode;
271 
272         Key(Artifact artifact) {
273             this.artifact = artifact;
274             this.hashCode = Objects.hash(artifact.getGroupId(), artifact.getArtifactId());
275         }
276 
277         @Override
278         public boolean equals(Object obj) {
279             if (obj == this) {
280                 return true;
281             } else if (!(obj instanceof Key)) {
282                 return false;
283             }
284             Key that = (Key) obj;
285             return artifact.getArtifactId().equals(that.artifact.getArtifactId())
286                     && artifact.getGroupId().equals(that.artifact.getGroupId())
287                     && artifact.getExtension().equals(that.artifact.getExtension())
288                     && artifact.getClassifier().equals(that.artifact.getClassifier());
289         }
290 
291         @Override
292         public int hashCode() {
293             return hashCode;
294         }
295     }
296 }