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