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