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.internal.impl.collect.df;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.Collections;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.concurrent.atomic.AtomicReference;
29  
30  import org.eclipse.aether.RepositorySystemSession;
31  import org.eclipse.aether.RequestTrace;
32  import org.eclipse.aether.artifact.Artifact;
33  import org.eclipse.aether.collection.CollectRequest;
34  import org.eclipse.aether.collection.DependencyCollectionException;
35  import org.eclipse.aether.collection.DependencyManager;
36  import org.eclipse.aether.collection.DependencySelector;
37  import org.eclipse.aether.collection.DependencyTraverser;
38  import org.eclipse.aether.collection.VersionFilter;
39  import org.eclipse.aether.graph.DefaultDependencyNode;
40  import org.eclipse.aether.graph.Dependency;
41  import org.eclipse.aether.graph.DependencyNode;
42  import org.eclipse.aether.impl.ArtifactDescriptorReader;
43  import org.eclipse.aether.impl.RemoteRepositoryManager;
44  import org.eclipse.aether.impl.VersionRangeResolver;
45  import org.eclipse.aether.internal.impl.collect.DataPool;
46  import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollectionContext;
47  import org.eclipse.aether.internal.impl.collect.DefaultDependencyCycle;
48  import org.eclipse.aether.internal.impl.collect.DefaultVersionFilterContext;
49  import org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate;
50  import org.eclipse.aether.internal.impl.collect.PremanagedDependency;
51  import org.eclipse.aether.repository.RemoteRepository;
52  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
53  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
54  import org.eclipse.aether.resolution.VersionRangeRequest;
55  import org.eclipse.aether.resolution.VersionRangeResolutionException;
56  import org.eclipse.aether.resolution.VersionRangeResult;
57  import org.eclipse.aether.spi.artifact.decorator.ArtifactDecoratorFactory;
58  import org.eclipse.aether.util.ConfigUtils;
59  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
60  import org.eclipse.aether.version.Version;
61  
62  /**
63   * Depth-first {@link org.eclipse.aether.impl.DependencyCollector} (the "original" default). Originally
64   * this class was located a package higher (as "default" implementation).
65   *
66   * @since 1.8.0
67   */
68  @Singleton
69  @Named(DfDependencyCollector.NAME)
70  public class DfDependencyCollector extends DependencyCollectorDelegate {
71      public static final String NAME = "df";
72  
73      @Inject
74      public DfDependencyCollector(
75              RemoteRepositoryManager remoteRepositoryManager,
76              ArtifactDescriptorReader artifactDescriptorReader,
77              VersionRangeResolver versionRangeResolver,
78              Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories) {
79          super(remoteRepositoryManager, artifactDescriptorReader, versionRangeResolver, artifactDecoratorFactories);
80      }
81  
82      @SuppressWarnings("checkstyle:parameternumber")
83      @Override
84      protected void doCollectDependencies(
85              RepositorySystemSession session,
86              RequestTrace trace,
87              DataPool pool,
88              DefaultDependencyCollectionContext context,
89              DefaultVersionFilterContext versionContext,
90              CollectRequest request,
91              DependencyNode node,
92              List<RemoteRepository> repositories,
93              List<Dependency> dependencies,
94              List<Dependency> managedDependencies,
95              Results results)
96              throws DependencyCollectionException {
97          NodeStack nodes = new NodeStack();
98          nodes.push(node);
99  
100         Args args = new Args(session, pool, nodes, context, versionContext, request);
101 
102         process(
103                 args,
104                 trace,
105                 results,
106                 dependencies,
107                 repositories,
108                 session.getDependencySelector() != null
109                         ? session.getDependencySelector().deriveChildSelector(context)
110                         : null,
111                 session.getDependencyManager() != null
112                         ? session.getDependencyManager().deriveChildManager(context)
113                         : null,
114                 session.getDependencyTraverser() != null
115                         ? session.getDependencyTraverser().deriveChildTraverser(context)
116                         : null,
117                 session.getVersionFilter() != null ? session.getVersionFilter().deriveChildFilter(context) : null);
118 
119         if (args.interruptedException.get() != null) {
120             throw new DependencyCollectionException(
121                     results.getResult(), "Collection interrupted", args.interruptedException.get());
122         }
123     }
124 
125     @SuppressWarnings("checkstyle:parameternumber")
126     private void process(
127             final Args args,
128             RequestTrace trace,
129             Results results,
130             List<Dependency> dependencies,
131             List<RemoteRepository> repositories,
132             DependencySelector depSelector,
133             DependencyManager depManager,
134             DependencyTraverser depTraverser,
135             VersionFilter verFilter) {
136         if (Thread.interrupted()) {
137             args.interruptedException.set(new InterruptedException());
138         }
139         if (args.interruptedException.get() != null) {
140             return;
141         }
142         for (Dependency dependency : dependencies) {
143             processDependency(
144                     args, trace, results, repositories, depSelector, depManager, depTraverser, verFilter, dependency);
145         }
146     }
147 
148     @SuppressWarnings("checkstyle:parameternumber")
149     private void processDependency(
150             Args args,
151             RequestTrace trace,
152             Results results,
153             List<RemoteRepository> repositories,
154             DependencySelector depSelector,
155             DependencyManager depManager,
156             DependencyTraverser depTraverser,
157             VersionFilter verFilter,
158             Dependency dependency) {
159 
160         List<Artifact> relocations = Collections.emptyList();
161         processDependency(
162                 args,
163                 trace,
164                 results,
165                 repositories,
166                 depSelector,
167                 depManager,
168                 depTraverser,
169                 verFilter,
170                 dependency,
171                 relocations,
172                 false);
173     }
174 
175     @SuppressWarnings("checkstyle:parameternumber")
176     private void processDependency(
177             Args args,
178             RequestTrace parent,
179             Results results,
180             List<RemoteRepository> repositories,
181             DependencySelector depSelector,
182             DependencyManager depManager,
183             DependencyTraverser depTraverser,
184             VersionFilter verFilter,
185             Dependency dependency,
186             List<Artifact> relocations,
187             boolean disableVersionManagement) {
188         if (depSelector != null && !depSelector.selectDependency(dependency)) {
189             return;
190         }
191 
192         RequestTrace trace = collectStepTrace(parent, args.request.getRequestContext(), args.nodes.nodes, dependency);
193         PremanagedDependency preManaged =
194                 PremanagedDependency.create(depManager, dependency, disableVersionManagement, args.premanagedState);
195         dependency = preManaged.getManagedDependency();
196 
197         boolean noDescriptor = isLackingDescriptor(args.session, dependency.getArtifact());
198 
199         boolean traverse = !noDescriptor && (depTraverser == null || depTraverser.traverseDependency(dependency));
200 
201         List<? extends Version> versions;
202         VersionRangeResult rangeResult;
203         try {
204             VersionRangeRequest rangeRequest =
205                     createVersionRangeRequest(args.request.getRequestContext(), trace, repositories, dependency);
206 
207             rangeResult = cachedResolveRangeResult(rangeRequest, args.pool, args.session);
208 
209             versions = filterVersions(dependency, rangeResult, verFilter, args.versionContext);
210         } catch (VersionRangeResolutionException e) {
211             results.addException(dependency, e, args.nodes.nodes);
212             return;
213         }
214 
215         for (Version version : versions) {
216             Artifact originalArtifact = dependency.getArtifact().setVersion(version.toString());
217             Dependency d = dependency.setArtifact(originalArtifact);
218 
219             ArtifactDescriptorRequest descriptorRequest =
220                     createArtifactDescriptorRequest(args.request.getRequestContext(), trace, repositories, d);
221 
222             final ArtifactDescriptorResult descriptorResult =
223                     getArtifactDescriptorResult(args, results, noDescriptor, d, descriptorRequest);
224             if (descriptorResult != null) {
225                 d = d.setArtifact(descriptorResult.getArtifact());
226 
227                 DependencyNode node = args.nodes.top();
228 
229                 int cycleEntry = DefaultDependencyCycle.find(args.nodes.nodes, d.getArtifact());
230                 if (cycleEntry >= 0) {
231                     results.addCycle(args.nodes.nodes, cycleEntry, d);
232                     DependencyNode cycleNode = args.nodes.get(cycleEntry);
233                     if (cycleNode.getDependency() != null) {
234                         DefaultDependencyNode child = createDependencyNode(
235                                 relocations, preManaged, rangeResult, version, d, descriptorResult, cycleNode);
236                         node.getChildren().add(child);
237                         continue;
238                     }
239                 }
240 
241                 if (!descriptorResult.getRelocations().isEmpty()) {
242                     boolean disableVersionManagementSubsequently =
243                             originalArtifact.getGroupId().equals(d.getArtifact().getGroupId())
244                                     && originalArtifact
245                                             .getArtifactId()
246                                             .equals(d.getArtifact().getArtifactId());
247 
248                     processDependency(
249                             args,
250                             parent,
251                             results,
252                             repositories,
253                             depSelector,
254                             depManager,
255                             depTraverser,
256                             verFilter,
257                             d,
258                             descriptorResult.getRelocations(),
259                             disableVersionManagementSubsequently);
260                     return;
261                 } else {
262                     d = args.pool.intern(d.setArtifact(args.pool.intern(d.getArtifact())));
263 
264                     List<RemoteRepository> repos =
265                             getRemoteRepositories(rangeResult.getRepository(version), repositories);
266 
267                     DefaultDependencyNode child = createDependencyNode(
268                             relocations,
269                             preManaged,
270                             rangeResult,
271                             version,
272                             d,
273                             descriptorResult.getAliases(),
274                             repos,
275                             args.request.getRequestContext());
276 
277                     node.getChildren().add(child);
278 
279                     boolean recurse =
280                             traverse && !descriptorResult.getDependencies().isEmpty();
281                     if (recurse) {
282                         doRecurse(
283                                 args,
284                                 parent,
285                                 results,
286                                 repositories,
287                                 depSelector,
288                                 depManager,
289                                 depTraverser,
290                                 verFilter,
291                                 d,
292                                 descriptorResult,
293                                 child);
294                     }
295                 }
296             } else {
297                 DependencyNode node = args.nodes.top();
298                 List<RemoteRepository> repos = getRemoteRepositories(rangeResult.getRepository(version), repositories);
299                 DefaultDependencyNode child = createDependencyNode(
300                         relocations,
301                         preManaged,
302                         rangeResult,
303                         version,
304                         d,
305                         null,
306                         repos,
307                         args.request.getRequestContext());
308                 node.getChildren().add(child);
309             }
310         }
311     }
312 
313     @SuppressWarnings("checkstyle:parameternumber")
314     private void doRecurse(
315             Args args,
316             RequestTrace trace,
317             Results results,
318             List<RemoteRepository> repositories,
319             DependencySelector depSelector,
320             DependencyManager depManager,
321             DependencyTraverser depTraverser,
322             VersionFilter verFilter,
323             Dependency d,
324             ArtifactDescriptorResult descriptorResult,
325             DefaultDependencyNode child) {
326         DefaultDependencyCollectionContext context = args.collectionContext;
327         context.set(d, descriptorResult.getManagedDependencies());
328 
329         DependencySelector childSelector = depSelector != null ? depSelector.deriveChildSelector(context) : null;
330         DependencyManager childManager = depManager != null ? depManager.deriveChildManager(context) : null;
331         DependencyTraverser childTraverser = depTraverser != null ? depTraverser.deriveChildTraverser(context) : null;
332         VersionFilter childFilter = verFilter != null ? verFilter.deriveChildFilter(context) : null;
333 
334         final List<RemoteRepository> childRepos = args.ignoreRepos
335                 ? repositories
336                 : remoteRepositoryManager.aggregateRepositories(
337                         args.session, repositories, descriptorResult.getRepositories(), true);
338 
339         Object key =
340                 args.pool.toKey(d.getArtifact(), childRepos, childSelector, childManager, childTraverser, childFilter);
341 
342         List<DependencyNode> children = args.pool.getChildren(key);
343         if (children == null) {
344             args.pool.putChildren(key, child.getChildren());
345 
346             args.nodes.push(child);
347 
348             process(
349                     args,
350                     trace,
351                     results,
352                     descriptorResult.getDependencies(),
353                     childRepos,
354                     childSelector,
355                     childManager,
356                     childTraverser,
357                     childFilter);
358 
359             args.nodes.pop();
360         } else {
361             child.setChildren(children);
362         }
363     }
364 
365     private ArtifactDescriptorResult getArtifactDescriptorResult(
366             Args args,
367             Results results,
368             boolean noDescriptor,
369             Dependency d,
370             ArtifactDescriptorRequest descriptorRequest) {
371         return noDescriptor
372                 ? new ArtifactDescriptorResult(descriptorRequest)
373                 : resolveCachedArtifactDescriptor(
374                         args.pool, descriptorRequest, args.session, d, results, args.nodes.nodes);
375     }
376 
377     static class Args {
378 
379         final RepositorySystemSession session;
380 
381         final boolean ignoreRepos;
382 
383         final boolean premanagedState;
384 
385         final DataPool pool;
386 
387         final NodeStack nodes;
388 
389         final DefaultDependencyCollectionContext collectionContext;
390 
391         final DefaultVersionFilterContext versionContext;
392 
393         final CollectRequest request;
394 
395         final AtomicReference<InterruptedException> interruptedException;
396 
397         Args(
398                 RepositorySystemSession session,
399                 DataPool pool,
400                 NodeStack nodes,
401                 DefaultDependencyCollectionContext collectionContext,
402                 DefaultVersionFilterContext versionContext,
403                 CollectRequest request) {
404             this.session = session;
405             this.request = request;
406             this.ignoreRepos = session.isIgnoreArtifactDescriptorRepositories();
407             this.premanagedState = ConfigUtils.getBoolean(session, false, DependencyManagerUtils.CONFIG_PROP_VERBOSE);
408             this.pool = pool;
409             this.nodes = nodes;
410             this.collectionContext = collectionContext;
411             this.versionContext = versionContext;
412             this.interruptedException = new AtomicReference<>(null);
413         }
414     }
415 }