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