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.apache.maven.repository.legacy.resolver;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.Iterator;
28  import java.util.LinkedHashMap;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  
34  import org.apache.maven.artifact.Artifact;
35  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
36  import org.apache.maven.artifact.metadata.ResolutionGroup;
37  import org.apache.maven.artifact.repository.ArtifactRepository;
38  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
39  import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
40  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
41  import org.apache.maven.artifact.resolver.CyclicDependencyException;
42  import org.apache.maven.artifact.resolver.ResolutionListener;
43  import org.apache.maven.artifact.resolver.ResolutionListenerForDepMgmt;
44  import org.apache.maven.artifact.resolver.ResolutionNode;
45  import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
46  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
47  import org.apache.maven.artifact.versioning.ArtifactVersion;
48  import org.apache.maven.artifact.versioning.ManagedVersionMap;
49  import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
50  import org.apache.maven.artifact.versioning.VersionRange;
51  import org.apache.maven.execution.MavenSession;
52  import org.apache.maven.plugin.LegacySupport;
53  import org.apache.maven.repository.legacy.metadata.ArtifactMetadataRetrievalException;
54  import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
55  import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
56  import org.apache.maven.repository.legacy.resolver.conflict.ConflictResolver;
57  import org.codehaus.plexus.logging.Logger;
58  
59  /**
60   */
61  @Named
62  @Singleton
63  @Deprecated
64  public class DefaultLegacyArtifactCollector implements LegacyArtifactCollector {
65  
66      @Inject
67      @Named("nearest")
68      private ConflictResolver defaultConflictResolver;
69  
70      @Inject
71      private Logger logger;
72  
73      @Inject
74      private LegacySupport legacySupport;
75  
76      private void injectSession(ArtifactResolutionRequest request) {
77          MavenSession session = legacySupport.getSession();
78  
79          if (session != null) {
80              request.setOffline(session.isOffline());
81              request.setForceUpdate(session.getRequest().isUpdateSnapshots());
82              request.setServers(session.getRequest().getServers());
83              request.setMirrors(session.getRequest().getMirrors());
84              request.setProxies(session.getRequest().getProxies());
85          }
86      }
87  
88      @SuppressWarnings("checkstyle:parameternumber")
89      public ArtifactResolutionResult collect(
90              Set<Artifact> artifacts,
91              Artifact originatingArtifact,
92              Map<String, Artifact> managedVersions,
93              ArtifactRepository localRepository,
94              List<ArtifactRepository> remoteRepositories,
95              ArtifactMetadataSource source,
96              ArtifactFilter filter,
97              List<ResolutionListener> listeners,
98              List<ConflictResolver> conflictResolvers) {
99          ArtifactResolutionRequest request = new ArtifactResolutionRequest();
100         request.setLocalRepository(localRepository);
101         request.setRemoteRepositories(remoteRepositories);
102         injectSession(request);
103         return collect(
104                 artifacts, originatingArtifact, managedVersions, request, source, filter, listeners, conflictResolvers);
105     }
106 
107     @SuppressWarnings("checkstyle:parameternumber")
108     public ArtifactResolutionResult collect(
109             Set<Artifact> artifacts,
110             Artifact originatingArtifact,
111             Map<String, Artifact> managedVersions,
112             ArtifactResolutionRequest repositoryRequest,
113             ArtifactMetadataSource source,
114             ArtifactFilter filter,
115             List<ResolutionListener> listeners,
116             List<ConflictResolver> conflictResolvers) {
117         ArtifactResolutionResult result = new ArtifactResolutionResult();
118 
119         result.setOriginatingArtifact(originatingArtifact);
120 
121         if (conflictResolvers == null) {
122             conflictResolvers = Collections.singletonList(defaultConflictResolver);
123         }
124 
125         Map<Object, List<ResolutionNode>> resolvedArtifacts = new LinkedHashMap<>();
126 
127         ResolutionNode root = new ResolutionNode(originatingArtifact, repositoryRequest.getRemoteRepositories());
128 
129         try {
130             root.addDependencies(artifacts, repositoryRequest.getRemoteRepositories(), filter);
131         } catch (CyclicDependencyException e) {
132             result.addCircularDependencyException(e);
133 
134             return result;
135         } catch (OverConstrainedVersionException e) {
136             result.addVersionRangeViolation(e);
137 
138             return result;
139         }
140 
141         ManagedVersionMap versionMap = getManagedVersionsMap(originatingArtifact, managedVersions);
142 
143         try {
144             recurse(
145                     result,
146                     root,
147                     resolvedArtifacts,
148                     versionMap,
149                     repositoryRequest,
150                     source,
151                     filter,
152                     listeners,
153                     conflictResolvers);
154         } catch (CyclicDependencyException e) {
155             logger.debug("While recursing: " + e.getMessage(), e);
156             result.addCircularDependencyException(e);
157         } catch (OverConstrainedVersionException e) {
158             logger.debug("While recursing: " + e.getMessage(), e);
159             result.addVersionRangeViolation(e);
160         } catch (ArtifactResolutionException e) {
161             logger.debug("While recursing: " + e.getMessage(), e);
162             result.addErrorArtifactException(e);
163         }
164 
165         Set<ResolutionNode> set = new LinkedHashSet<>();
166 
167         for (List<ResolutionNode> nodes : resolvedArtifacts.values()) {
168             for (ResolutionNode node : nodes) {
169                 if (!node.equals(root) && node.isActive()) {
170                     Artifact artifact = node.getArtifact();
171 
172                     try {
173                         if (node.filterTrail(filter)) {
174                             // If it was optional and not a direct dependency,
175                             // we don't add it or its children, just allow the update of the version and artifactScope
176                             if (node.isChildOfRootNode() || !artifact.isOptional()) {
177                                 artifact.setDependencyTrail(node.getDependencyTrail());
178 
179                                 set.add(node);
180 
181                                 // This is required right now.
182                                 result.addArtifact(artifact);
183                             }
184                         }
185                     } catch (OverConstrainedVersionException e) {
186                         result.addVersionRangeViolation(e);
187                     }
188                 }
189             }
190         }
191 
192         result.setArtifactResolutionNodes(set);
193 
194         return result;
195     }
196 
197     /**
198      * Get the map of managed versions, removing the originating artifact if it is also in managed versions
199      *
200      * @param originatingArtifact artifact we are processing
201      * @param managedVersions original managed versions
202      */
203     private ManagedVersionMap getManagedVersionsMap(
204             Artifact originatingArtifact, Map<String, Artifact> managedVersions) {
205         ManagedVersionMap versionMap;
206         if (managedVersions instanceof ManagedVersionMap) {
207             versionMap = (ManagedVersionMap) managedVersions;
208         } else {
209             versionMap = new ManagedVersionMap(managedVersions);
210         }
211 
212         // remove the originating artifact if it is also in managed versions to avoid being modified during resolution
213         Artifact managedOriginatingArtifact = versionMap.get(originatingArtifact.getDependencyConflictId());
214 
215         if (managedOriginatingArtifact != null) {
216             // TODO we probably want to warn the user that he is building an artifact with
217             // different values than in dependencyManagement
218             if (managedVersions instanceof ManagedVersionMap) {
219                 /* avoid modifying the managedVersions parameter creating a new map */
220                 versionMap = new ManagedVersionMap(managedVersions);
221             }
222             versionMap.remove(originatingArtifact.getDependencyConflictId());
223         }
224 
225         return versionMap;
226     }
227 
228     @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:methodlength"})
229     private void recurse(
230             ArtifactResolutionResult result,
231             ResolutionNode node,
232             Map<Object, List<ResolutionNode>> resolvedArtifacts,
233             ManagedVersionMap managedVersions,
234             ArtifactResolutionRequest request,
235             ArtifactMetadataSource source,
236             ArtifactFilter filter,
237             List<ResolutionListener> listeners,
238             List<ConflictResolver> conflictResolvers)
239             throws ArtifactResolutionException {
240         fireEvent(ResolutionListener.TEST_ARTIFACT, listeners, node);
241 
242         Object key = node.getKey();
243 
244         // TODO Does this check need to happen here? Had to add the same call
245         // below when we iterate on child nodes -- will that suffice?
246         if (managedVersions.containsKey(key)) {
247             manageArtifact(node, managedVersions, listeners);
248         }
249 
250         List<ResolutionNode> previousNodes = resolvedArtifacts.get(key);
251 
252         if (previousNodes != null) {
253             for (ResolutionNode previous : previousNodes) {
254                 try {
255                     if (previous.isActive()) {
256                         // Version mediation
257                         VersionRange previousRange = previous.getArtifact().getVersionRange();
258                         VersionRange currentRange = node.getArtifact().getVersionRange();
259 
260                         if ((previousRange != null) && (currentRange != null)) {
261                             // TODO shouldn't need to double up on this work, only done for simplicity of handling
262                             // recommended
263                             // version but the restriction is identical
264                             VersionRange newRange = previousRange.restrict(currentRange);
265                             // TODO ick. this forces the OCE that should have come from the previous call. It is still
266                             // correct
267                             if (newRange.isSelectedVersionKnown(previous.getArtifact())) {
268                                 fireEvent(
269                                         ResolutionListener.RESTRICT_RANGE,
270                                         listeners,
271                                         node,
272                                         previous.getArtifact(),
273                                         newRange);
274                             }
275                             previous.getArtifact().setVersionRange(newRange);
276                             node.getArtifact().setVersionRange(currentRange.restrict(previousRange));
277 
278                             // Select an appropriate available version from the (now restricted) range
279                             // Note this version was selected before to get the appropriate POM
280                             // But it was reset by the call to setVersionRange on restricting the version
281                             ResolutionNode[] resetNodes = {previous, node};
282                             for (int j = 0; j < 2; j++) {
283                                 Artifact resetArtifact = resetNodes[j].getArtifact();
284 
285                                 // MNG-2123: if the previous node was not a range, then it wouldn't have any available
286                                 // versions. We just clobbered the selected version above. (why? I have no idea.)
287                                 // So since we are here and this is ranges we must go figure out the version (for a
288                                 // third time...)
289                                 if (resetArtifact.getVersion() == null && resetArtifact.getVersionRange() != null) {
290 
291                                     // go find the version. This is a total hack. See previous comment.
292                                     List<ArtifactVersion> versions = resetArtifact.getAvailableVersions();
293                                     if (versions == null) {
294                                         try {
295                                             MetadataResolutionRequest metadataRequest =
296                                                     new DefaultMetadataResolutionRequest(request);
297 
298                                             metadataRequest.setArtifact(resetArtifact);
299                                             versions = source.retrieveAvailableVersions(metadataRequest);
300                                             resetArtifact.setAvailableVersions(versions);
301                                         } catch (ArtifactMetadataRetrievalException e) {
302                                             resetArtifact.setDependencyTrail(node.getDependencyTrail());
303                                             throw new ArtifactResolutionException(
304                                                     "Unable to get dependency information: " + e.getMessage(),
305                                                     resetArtifact,
306                                                     request.getRemoteRepositories(),
307                                                     e);
308                                         }
309                                     }
310                                     // end hack
311 
312                                     // MNG-2861: match version can return null
313                                     ArtifactVersion selectedVersion = resetArtifact
314                                             .getVersionRange()
315                                             .matchVersion(resetArtifact.getAvailableVersions());
316 
317                                     if (selectedVersion != null) {
318                                         resetArtifact.selectVersion(selectedVersion.toString());
319                                     } else {
320                                         throw new OverConstrainedVersionException(
321                                                 "Unable to find a version in " + resetArtifact.getAvailableVersions()
322                                                         + " to match the range " + resetArtifact.getVersionRange(),
323                                                 resetArtifact);
324                                     }
325 
326                                     fireEvent(ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, resetNodes[j]);
327                                 }
328                             }
329                         }
330 
331                         // Conflict Resolution
332                         ResolutionNode resolved = null;
333                         for (Iterator<ConflictResolver> j = conflictResolvers.iterator();
334                                 resolved == null && j.hasNext(); ) {
335                             ConflictResolver conflictResolver = j.next();
336 
337                             resolved = conflictResolver.resolveConflict(previous, node);
338                         }
339 
340                         if (resolved == null) {
341                             // TODO add better exception that can detail the two conflicting artifacts
342                             ArtifactResolutionException are = new ArtifactResolutionException(
343                                     "Cannot resolve artifact version conflict between "
344                                             + previous.getArtifact().getVersion() + " and "
345                                             + node.getArtifact().getVersion(),
346                                     previous.getArtifact());
347 
348                             result.addVersionRangeViolation(are);
349                         }
350 
351                         if ((resolved != previous) && (resolved != node)) {
352                             // TODO add better exception
353                             result.addVersionRangeViolation(new ArtifactResolutionException(
354                                     "Conflict resolver returned unknown resolution node: ", resolved.getArtifact()));
355                         }
356 
357                         // TODO should this be part of mediation?
358                         // previous one is more dominant
359                         ResolutionNode nearest;
360                         ResolutionNode farthest;
361 
362                         if (resolved == previous) {
363                             nearest = previous;
364                             farthest = node;
365                         } else {
366                             nearest = node;
367                             farthest = previous;
368                         }
369 
370                         if (checkScopeUpdate(farthest, nearest, listeners)) {
371                             // if we need to update artifactScope of nearest to use farthest artifactScope, use the
372                             // nearest version, but farthest artifactScope
373                             nearest.disable();
374                             farthest.getArtifact()
375                                     .setVersion(nearest.getArtifact().getVersion());
376                             fireEvent(ResolutionListener.OMIT_FOR_NEARER, listeners, nearest, farthest.getArtifact());
377                         } else {
378                             farthest.disable();
379                             fireEvent(ResolutionListener.OMIT_FOR_NEARER, listeners, farthest, nearest.getArtifact());
380                         }
381                     }
382                 } catch (OverConstrainedVersionException e) {
383                     result.addVersionRangeViolation(e);
384                 }
385             }
386         } else {
387             previousNodes = new ArrayList<>();
388 
389             resolvedArtifacts.put(key, previousNodes);
390         }
391         previousNodes.add(node);
392 
393         if (node.isActive()) {
394             fireEvent(ResolutionListener.INCLUDE_ARTIFACT, listeners, node);
395         }
396 
397         // don't pull in the transitive deps of a system-scoped dependency.
398         if (node.isActive() && !Artifact.SCOPE_SYSTEM.equals(node.getArtifact().getScope())) {
399             fireEvent(ResolutionListener.PROCESS_CHILDREN, listeners, node);
400 
401             Artifact parentArtifact = node.getArtifact();
402 
403             for (Iterator<ResolutionNode> i = node.getChildrenIterator(); i.hasNext(); ) {
404                 ResolutionNode child = i.next();
405 
406                 try {
407 
408                     // We leave in optional ones, but don't pick up its dependencies
409                     if (!child.isResolved() && (!child.getArtifact().isOptional() || child.isChildOfRootNode())) {
410                         Artifact artifact = child.getArtifact();
411                         artifact.setDependencyTrail(node.getDependencyTrail());
412                         List<ArtifactRepository> childRemoteRepositories = child.getRemoteRepositories();
413 
414                         MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest(request);
415                         metadataRequest.setArtifact(artifact);
416                         metadataRequest.setRemoteRepositories(childRemoteRepositories);
417 
418                         try {
419                             ResolutionGroup rGroup;
420 
421                             Object childKey;
422                             do {
423                                 childKey = child.getKey();
424 
425                                 if (managedVersions.containsKey(childKey)) {
426                                     // If this child node is a managed dependency, ensure
427                                     // we are using the dependency management version
428                                     // of this child if applicable b/c we want to use the
429                                     // managed version's POM, *not* any other version's POM.
430                                     // We retrieve the POM below in the retrieval step.
431                                     manageArtifact(child, managedVersions, listeners);
432 
433                                     // Also, we need to ensure that any exclusions it presents are
434                                     // added to the artifact before we retrieve the metadata
435                                     // for the artifact; otherwise we may end up with unwanted
436                                     // dependencies.
437                                     Artifact ma = managedVersions.get(childKey);
438                                     ArtifactFilter managedExclusionFilter = ma.getDependencyFilter();
439                                     if (null != managedExclusionFilter) {
440                                         if (null != artifact.getDependencyFilter()) {
441                                             AndArtifactFilter aaf = new AndArtifactFilter();
442                                             aaf.add(artifact.getDependencyFilter());
443                                             aaf.add(managedExclusionFilter);
444                                             artifact.setDependencyFilter(aaf);
445                                         } else {
446                                             artifact.setDependencyFilter(managedExclusionFilter);
447                                         }
448                                     }
449                                 }
450 
451                                 if (artifact.getVersion() == null) {
452                                     // set the recommended version
453                                     // TODO maybe its better to just pass the range through to retrieval and use a
454                                     // transformation?
455                                     ArtifactVersion version;
456                                     if (!artifact.isSelectedVersionKnown()) {
457                                         List<ArtifactVersion> versions = artifact.getAvailableVersions();
458                                         if (versions == null) {
459                                             versions = source.retrieveAvailableVersions(metadataRequest);
460                                             artifact.setAvailableVersions(versions);
461                                         }
462 
463                                         Collections.sort(versions);
464 
465                                         VersionRange versionRange = artifact.getVersionRange();
466 
467                                         version = versionRange.matchVersion(versions);
468 
469                                         if (version == null) {
470                                             if (versions.isEmpty()) {
471                                                 throw new OverConstrainedVersionException(
472                                                         "No versions are present in the repository for the artifact"
473                                                                 + " with a range " + versionRange,
474                                                         artifact,
475                                                         childRemoteRepositories);
476                                             }
477 
478                                             throw new OverConstrainedVersionException(
479                                                     "Couldn't find a version in " + versions + " to match range "
480                                                             + versionRange,
481                                                     artifact,
482                                                     childRemoteRepositories);
483                                         }
484                                     } else {
485                                         version = artifact.getSelectedVersion();
486                                     }
487 
488                                     artifact.selectVersion(version.toString());
489                                     fireEvent(ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, child);
490                                 }
491 
492                                 rGroup = source.retrieve(metadataRequest);
493 
494                                 if (rGroup == null) {
495                                     break;
496                                 }
497                             } while (!childKey.equals(child.getKey()));
498 
499                             if (parentArtifact != null
500                                     && parentArtifact.getDependencyFilter() != null
501                                     && !parentArtifact.getDependencyFilter().include(artifact)) {
502                                 // MNG-3769: the [probably relocated] artifact is excluded.
503                                 // We could process exclusions on relocated artifact details in the
504                                 // MavenMetadataSource.createArtifacts(..) step, BUT that would
505                                 // require resolving the POM from the repository very early on in
506                                 // the build.
507                                 continue;
508                             }
509 
510                             // TODO might be better to have source.retrieve() throw a specific exception for this
511                             // situation
512                             // and catch here rather than have it return null
513                             if (rGroup == null) {
514                                 // relocated dependency artifact is declared excluded, no need to add and recurse
515                                 // further
516                                 continue;
517                             }
518 
519                             child.addDependencies(rGroup.getArtifacts(), rGroup.getResolutionRepositories(), filter);
520 
521                         } catch (CyclicDependencyException e) {
522                             // would like to throw this, but we have crappy stuff in the repo
523 
524                             fireEvent(
525                                     ResolutionListener.OMIT_FOR_CYCLE,
526                                     listeners,
527                                     new ResolutionNode(e.getArtifact(), childRemoteRepositories, child));
528                         } catch (ArtifactMetadataRetrievalException e) {
529                             artifact.setDependencyTrail(node.getDependencyTrail());
530 
531                             throw new ArtifactResolutionException(
532                                     "Unable to get dependency information for " + artifact.getId() + ": "
533                                             + e.getMessage(),
534                                     artifact,
535                                     childRemoteRepositories,
536                                     e);
537                         }
538 
539                         ArtifactResolutionRequest subRequest = new ArtifactResolutionRequest(metadataRequest);
540                         subRequest.setServers(request.getServers());
541                         subRequest.setMirrors(request.getMirrors());
542                         subRequest.setProxies(request.getProxies());
543                         recurse(
544                                 result,
545                                 child,
546                                 resolvedArtifacts,
547                                 managedVersions,
548                                 subRequest,
549                                 source,
550                                 filter,
551                                 listeners,
552                                 conflictResolvers);
553                     }
554                 } catch (OverConstrainedVersionException e) {
555                     result.addVersionRangeViolation(e);
556                 } catch (ArtifactResolutionException e) {
557                     result.addMetadataResolutionException(e);
558                 }
559             }
560 
561             fireEvent(ResolutionListener.FINISH_PROCESSING_CHILDREN, listeners, node);
562         }
563     }
564 
565     private void manageArtifact(
566             ResolutionNode node, ManagedVersionMap managedVersions, List<ResolutionListener> listeners) {
567         Artifact artifact = managedVersions.get(node.getKey());
568 
569         // Before we update the version of the artifact, we need to know
570         // whether we are working on a transitive dependency or not. This
571         // allows depMgmt to always override transitive dependencies, while
572         // explicit child override depMgmt (viz. depMgmt should only
573         // provide defaults to children, but should override transitives).
574         // We can do this by calling isChildOfRootNode on the current node.
575         if ((artifact.getVersion() != null)
576                 && (!node.isChildOfRootNode() || node.getArtifact().getVersion() == null)) {
577             fireEvent(ResolutionListener.MANAGE_ARTIFACT_VERSION, listeners, node, artifact);
578             node.getArtifact().setVersion(artifact.getVersion());
579         }
580 
581         if ((artifact.getScope() != null)
582                 && (!node.isChildOfRootNode() || node.getArtifact().getScope() == null)) {
583             fireEvent(ResolutionListener.MANAGE_ARTIFACT_SCOPE, listeners, node, artifact);
584             node.getArtifact().setScope(artifact.getScope());
585         }
586 
587         if (Artifact.SCOPE_SYSTEM.equals(node.getArtifact().getScope())
588                 && (node.getArtifact().getFile() == null)
589                 && (artifact.getFile() != null)) {
590             fireEvent(ResolutionListener.MANAGE_ARTIFACT_SYSTEM_PATH, listeners, node, artifact);
591             node.getArtifact().setFile(artifact.getFile());
592         }
593     }
594 
595     /**
596      * Check if the artifactScope needs to be updated. <a
597      * href="http://docs.codehaus.org/x/IGU#DependencyMediationandConflictResolution-Scoperesolution">More info</a>.
598      *
599      * @param farthest farthest resolution node
600      * @param nearest nearest resolution node
601      * @param listeners
602      */
603     boolean checkScopeUpdate(ResolutionNode farthest, ResolutionNode nearest, List<ResolutionListener> listeners) {
604         boolean updateScope = false;
605         Artifact farthestArtifact = farthest.getArtifact();
606         Artifact nearestArtifact = nearest.getArtifact();
607 
608         /* farthest is runtime and nearest has lower priority, change to runtime */
609         if (Artifact.SCOPE_RUNTIME.equals(farthestArtifact.getScope())
610                 && (Artifact.SCOPE_TEST.equals(nearestArtifact.getScope())
611                         || Artifact.SCOPE_PROVIDED.equals(nearestArtifact.getScope()))) {
612             updateScope = true;
613         }
614 
615         /* farthest is compile and nearest is not (has lower priority), change to compile */
616         if (Artifact.SCOPE_COMPILE.equals(farthestArtifact.getScope())
617                 && !Artifact.SCOPE_COMPILE.equals(nearestArtifact.getScope())) {
618             updateScope = true;
619         }
620 
621         /* current POM rules all, if nearest is in current pom, do not update its artifactScope */
622         if ((nearest.getDepth() < 2) && updateScope) {
623             updateScope = false;
624 
625             fireEvent(ResolutionListener.UPDATE_SCOPE_CURRENT_POM, listeners, nearest, farthestArtifact);
626         }
627 
628         if (updateScope) {
629             fireEvent(ResolutionListener.UPDATE_SCOPE, listeners, nearest, farthestArtifact);
630 
631             // previously we cloned the artifact, but it is more efficient to just update the artifactScope
632             // if problems are later discovered that the original object needs its original artifactScope value,
633             // cloning may
634             // again be appropriate
635             nearestArtifact.setScope(farthestArtifact.getScope());
636         }
637 
638         return updateScope;
639     }
640 
641     private void fireEvent(int event, List<ResolutionListener> listeners, ResolutionNode node) {
642         fireEvent(event, listeners, node, null);
643     }
644 
645     private void fireEvent(int event, List<ResolutionListener> listeners, ResolutionNode node, Artifact replacement) {
646         fireEvent(event, listeners, node, replacement, null);
647     }
648 
649     private void fireEvent(
650             int event,
651             List<ResolutionListener> listeners,
652             ResolutionNode node,
653             Artifact replacement,
654             VersionRange newRange) {
655         for (ResolutionListener listener : listeners) {
656             switch (event) {
657                 case ResolutionListener.TEST_ARTIFACT:
658                     listener.testArtifact(node.getArtifact());
659                     break;
660                 case ResolutionListener.PROCESS_CHILDREN:
661                     listener.startProcessChildren(node.getArtifact());
662                     break;
663                 case ResolutionListener.FINISH_PROCESSING_CHILDREN:
664                     listener.endProcessChildren(node.getArtifact());
665                     break;
666                 case ResolutionListener.INCLUDE_ARTIFACT:
667                     listener.includeArtifact(node.getArtifact());
668                     break;
669                 case ResolutionListener.OMIT_FOR_NEARER:
670                     listener.omitForNearer(node.getArtifact(), replacement);
671                     break;
672                 case ResolutionListener.OMIT_FOR_CYCLE:
673                     listener.omitForCycle(node.getArtifact());
674                     break;
675                 case ResolutionListener.UPDATE_SCOPE:
676                     listener.updateScope(node.getArtifact(), replacement.getScope());
677                     break;
678                 case ResolutionListener.UPDATE_SCOPE_CURRENT_POM:
679                     listener.updateScopeCurrentPom(node.getArtifact(), replacement.getScope());
680                     break;
681                 case ResolutionListener.MANAGE_ARTIFACT_VERSION:
682                     if (listener instanceof ResolutionListenerForDepMgmt) {
683                         ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
684                         asImpl.manageArtifactVersion(node.getArtifact(), replacement);
685                     } else {
686                         listener.manageArtifact(node.getArtifact(), replacement);
687                     }
688                     break;
689                 case ResolutionListener.MANAGE_ARTIFACT_SCOPE:
690                     if (listener instanceof ResolutionListenerForDepMgmt) {
691                         ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
692                         asImpl.manageArtifactScope(node.getArtifact(), replacement);
693                     } else {
694                         listener.manageArtifact(node.getArtifact(), replacement);
695                     }
696                     break;
697                 case ResolutionListener.MANAGE_ARTIFACT_SYSTEM_PATH:
698                     if (listener instanceof ResolutionListenerForDepMgmt) {
699                         ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
700                         asImpl.manageArtifactSystemPath(node.getArtifact(), replacement);
701                     } else {
702                         listener.manageArtifact(node.getArtifact(), replacement);
703                     }
704                     break;
705                 case ResolutionListener.SELECT_VERSION_FROM_RANGE:
706                     listener.selectVersionFromRange(node.getArtifact());
707                     break;
708                 case ResolutionListener.RESTRICT_RANGE:
709                     if (node.getArtifact().getVersionRange().hasRestrictions()
710                             || replacement.getVersionRange().hasRestrictions()) {
711                         listener.restrictRange(node.getArtifact(), replacement, newRange);
712                     }
713                     break;
714                 default:
715                     throw new IllegalStateException("Unknown event: " + event);
716             }
717         }
718     }
719 
720     @SuppressWarnings("checkstyle:parameternumber")
721     public ArtifactResolutionResult collect(
722             Set<Artifact> artifacts,
723             Artifact originatingArtifact,
724             Map<String, Artifact> managedVersions,
725             ArtifactRepository localRepository,
726             List<ArtifactRepository> remoteRepositories,
727             ArtifactMetadataSource source,
728             ArtifactFilter filter,
729             List<ResolutionListener> listeners) {
730         return collect(
731                 artifacts,
732                 originatingArtifact,
733                 managedVersions,
734                 localRepository,
735                 remoteRepositories,
736                 source,
737                 filter,
738                 listeners,
739                 null);
740     }
741 
742     public ArtifactResolutionResult collect(
743             Set<Artifact> artifacts,
744             Artifact originatingArtifact,
745             ArtifactRepository localRepository,
746             List<ArtifactRepository> remoteRepositories,
747             ArtifactMetadataSource source,
748             ArtifactFilter filter,
749             List<ResolutionListener> listeners) {
750         return collect(
751                 artifacts, originatingArtifact, null, localRepository, remoteRepositories, source, filter, listeners);
752     }
753 }