View Javadoc
1   package org.eclipse.aether.internal.impl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.Iterator;
28  import java.util.List;
29  import static java.util.Objects.requireNonNull;
30  import java.util.concurrent.atomic.AtomicBoolean;
31  
32  import javax.inject.Inject;
33  import javax.inject.Named;
34  import javax.inject.Singleton;
35  
36  import org.eclipse.aether.RepositoryEvent;
37  import org.eclipse.aether.RepositoryEvent.EventType;
38  import org.eclipse.aether.RepositorySystemSession;
39  import org.eclipse.aether.RequestTrace;
40  import org.eclipse.aether.SyncContext;
41  import org.eclipse.aether.artifact.Artifact;
42  import org.eclipse.aether.artifact.ArtifactProperties;
43  import org.eclipse.aether.impl.ArtifactResolver;
44  import org.eclipse.aether.impl.OfflineController;
45  import org.eclipse.aether.impl.RemoteRepositoryManager;
46  import org.eclipse.aether.impl.RepositoryConnectorProvider;
47  import org.eclipse.aether.impl.RepositoryEventDispatcher;
48  import org.eclipse.aether.spi.synccontext.SyncContextFactory;
49  import org.eclipse.aether.impl.UpdateCheck;
50  import org.eclipse.aether.impl.UpdateCheckManager;
51  import org.eclipse.aether.impl.VersionResolver;
52  import org.eclipse.aether.repository.ArtifactRepository;
53  import org.eclipse.aether.repository.LocalArtifactRegistration;
54  import org.eclipse.aether.repository.LocalArtifactRequest;
55  import org.eclipse.aether.repository.LocalArtifactResult;
56  import org.eclipse.aether.repository.LocalRepository;
57  import org.eclipse.aether.repository.LocalRepositoryManager;
58  import org.eclipse.aether.repository.RemoteRepository;
59  import org.eclipse.aether.repository.RepositoryPolicy;
60  import org.eclipse.aether.repository.WorkspaceReader;
61  import org.eclipse.aether.resolution.ArtifactRequest;
62  import org.eclipse.aether.resolution.ArtifactResolutionException;
63  import org.eclipse.aether.resolution.ArtifactResult;
64  import org.eclipse.aether.resolution.ResolutionErrorPolicy;
65  import org.eclipse.aether.resolution.VersionRequest;
66  import org.eclipse.aether.resolution.VersionResolutionException;
67  import org.eclipse.aether.resolution.VersionResult;
68  import org.eclipse.aether.spi.connector.ArtifactDownload;
69  import org.eclipse.aether.spi.connector.RepositoryConnector;
70  import org.eclipse.aether.spi.io.FileProcessor;
71  import org.eclipse.aether.spi.locator.Service;
72  import org.eclipse.aether.spi.locator.ServiceLocator;
73  import org.eclipse.aether.transfer.ArtifactNotFoundException;
74  import org.eclipse.aether.transfer.ArtifactTransferException;
75  import org.eclipse.aether.transfer.NoRepositoryConnectorException;
76  import org.eclipse.aether.transfer.RepositoryOfflineException;
77  import org.eclipse.aether.util.ConfigUtils;
78  import org.slf4j.Logger;
79  import org.slf4j.LoggerFactory;
80  
81  /**
82   */
83  @Singleton
84  @Named
85  public class DefaultArtifactResolver
86      implements ArtifactResolver, Service
87  {
88  
89      private static final String CONFIG_PROP_SNAPSHOT_NORMALIZATION = "aether.artifactResolver.snapshotNormalization";
90  
91      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultArtifactResolver.class );
92  
93      private FileProcessor fileProcessor;
94  
95      private RepositoryEventDispatcher repositoryEventDispatcher;
96  
97      private VersionResolver versionResolver;
98  
99      private UpdateCheckManager updateCheckManager;
100 
101     private RepositoryConnectorProvider repositoryConnectorProvider;
102 
103     private RemoteRepositoryManager remoteRepositoryManager;
104 
105     private SyncContextFactory syncContextFactory;
106 
107     private OfflineController offlineController;
108 
109     public DefaultArtifactResolver()
110     {
111         // enables default constructor
112     }
113 
114     @SuppressWarnings( "checkstyle:parameternumber" )
115     @Inject
116     DefaultArtifactResolver( FileProcessor fileProcessor, RepositoryEventDispatcher repositoryEventDispatcher,
117                              VersionResolver versionResolver, UpdateCheckManager updateCheckManager,
118                              RepositoryConnectorProvider repositoryConnectorProvider,
119                              RemoteRepositoryManager remoteRepositoryManager, SyncContextFactory syncContextFactory,
120                              OfflineController offlineController )
121     {
122         setFileProcessor( fileProcessor );
123         setRepositoryEventDispatcher( repositoryEventDispatcher );
124         setVersionResolver( versionResolver );
125         setUpdateCheckManager( updateCheckManager );
126         setRepositoryConnectorProvider( repositoryConnectorProvider );
127         setRemoteRepositoryManager( remoteRepositoryManager );
128         setSyncContextFactory( syncContextFactory );
129         setOfflineController( offlineController );
130     }
131 
132     public void initService( ServiceLocator locator )
133     {
134         setFileProcessor( locator.getService( FileProcessor.class ) );
135         setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) );
136         setVersionResolver( locator.getService( VersionResolver.class ) );
137         setUpdateCheckManager( locator.getService( UpdateCheckManager.class ) );
138         setRepositoryConnectorProvider( locator.getService( RepositoryConnectorProvider.class ) );
139         setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
140         setSyncContextFactory( locator.getService( SyncContextFactory.class ) );
141         setOfflineController( locator.getService( OfflineController.class ) );
142     }
143 
144     /**
145      * @deprecated not used any more since MRESOLVER-36 move to slf4j, added back in MRESOLVER-64 for compatibility
146      */
147     @Deprecated
148     public DefaultArtifactResolver setLoggerFactory( org.eclipse.aether.spi.log.LoggerFactory loggerFactory )
149     {
150         // this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() );
151         return this;
152     }
153 
154     public DefaultArtifactResolver setFileProcessor( FileProcessor fileProcessor )
155     {
156         this.fileProcessor = requireNonNull( fileProcessor, "file processor cannot be null" );
157         return this;
158     }
159 
160     public DefaultArtifactResolver setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher )
161     {
162         this.repositoryEventDispatcher = requireNonNull( repositoryEventDispatcher,
163                 "repository event dispatcher cannot be null" );
164         return this;
165     }
166 
167     public DefaultArtifactResolver setVersionResolver( VersionResolver versionResolver )
168     {
169         this.versionResolver = requireNonNull( versionResolver, "version resolver cannot be null" );
170         return this;
171     }
172 
173     public DefaultArtifactResolver setUpdateCheckManager( UpdateCheckManager updateCheckManager )
174     {
175         this.updateCheckManager = requireNonNull( updateCheckManager, "update check manager cannot be null" );
176         return this;
177     }
178 
179     public DefaultArtifactResolver setRepositoryConnectorProvider(
180             RepositoryConnectorProvider repositoryConnectorProvider )
181     {
182         this.repositoryConnectorProvider = requireNonNull( repositoryConnectorProvider,
183                 "repository connector provider cannot be null" );
184         return this;
185     }
186 
187     public DefaultArtifactResolver setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
188     {
189         this.remoteRepositoryManager = requireNonNull( remoteRepositoryManager,
190                 "remote repository provider cannot be null" );
191         return this;
192     }
193 
194     public DefaultArtifactResolver setSyncContextFactory( SyncContextFactory syncContextFactory )
195     {
196         this.syncContextFactory = requireNonNull( syncContextFactory, "sync context factory cannot be null" );
197         return this;
198     }
199 
200     public DefaultArtifactResolver setOfflineController( OfflineController offlineController )
201     {
202         this.offlineController = requireNonNull( offlineController, "offline controller cannot be null" );
203         return this;
204     }
205 
206     public ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest request )
207         throws ArtifactResolutionException
208     {
209         requireNonNull( session, "session cannot be null" );
210         requireNonNull( session, "session cannot be null" );
211 
212         return resolveArtifacts( session, Collections.singleton( request ) ).get( 0 );
213     }
214 
215     public List<ArtifactResult> resolveArtifacts( RepositorySystemSession session,
216                                                   Collection<? extends ArtifactRequest> requests )
217         throws ArtifactResolutionException
218     {
219         requireNonNull( session, "session cannot be null" );
220         requireNonNull( session, "session cannot be null" );
221         try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) )
222         {
223             Collection<Artifact> artifacts = new ArrayList<>( requests.size() );
224             for ( ArtifactRequest request : requests )
225             {
226                 if ( request.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) != null )
227                 {
228                     continue;
229                 }
230                 artifacts.add( request.getArtifact() );
231             }
232 
233             syncContext.acquire( artifacts, null );
234 
235             return resolve( session, requests );
236         }
237     }
238 
239     @SuppressWarnings( "checkstyle:methodlength" )
240     private List<ArtifactResult> resolve( RepositorySystemSession session,
241                                           Collection<? extends ArtifactRequest> requests )
242         throws ArtifactResolutionException
243     {
244         List<ArtifactResult> results = new ArrayList<>( requests.size() );
245         boolean failures = false;
246 
247         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
248         WorkspaceReader workspace = session.getWorkspaceReader();
249 
250         List<ResolutionGroup> groups = new ArrayList<>();
251 
252         for ( ArtifactRequest request : requests )
253         {
254             RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
255 
256             ArtifactResult result = new ArtifactResult( request );
257             results.add( result );
258 
259             Artifact artifact = request.getArtifact();
260             List<RemoteRepository> repos = request.getRepositories();
261 
262             artifactResolving( session, trace, artifact );
263 
264             String localPath = artifact.getProperty( ArtifactProperties.LOCAL_PATH, null );
265             if ( localPath != null )
266             {
267                 // unhosted artifact, just validate file
268                 File file = new File( localPath );
269                 if ( !file.isFile() )
270                 {
271                     failures = true;
272                     result.addException( new ArtifactNotFoundException( artifact, null ) );
273                 }
274                 else
275                 {
276                     artifact = artifact.setFile( file );
277                     result.setArtifact( artifact );
278                     artifactResolved( session, trace, artifact, null, result.getExceptions() );
279                 }
280                 continue;
281             }
282 
283             VersionResult versionResult;
284             try
285             {
286                 VersionRequest versionRequest = new VersionRequest( artifact, repos, request.getRequestContext() );
287                 versionRequest.setTrace( trace );
288                 versionResult = versionResolver.resolveVersion( session, versionRequest );
289             }
290             catch ( VersionResolutionException e )
291             {
292                 result.addException( e );
293                 continue;
294             }
295 
296             artifact = artifact.setVersion( versionResult.getVersion() );
297 
298             if ( versionResult.getRepository() != null )
299             {
300                 if ( versionResult.getRepository() instanceof RemoteRepository )
301                 {
302                     repos = Collections.singletonList( (RemoteRepository) versionResult.getRepository() );
303                 }
304                 else
305                 {
306                     repos = Collections.emptyList();
307                 }
308             }
309 
310             if ( workspace != null )
311             {
312                 File file = workspace.findArtifact( artifact );
313                 if ( file != null )
314                 {
315                     artifact = artifact.setFile( file );
316                     result.setArtifact( artifact );
317                     result.setRepository( workspace.getRepository() );
318                     artifactResolved( session, trace, artifact, result.getRepository(), null );
319                     continue;
320                 }
321             }
322 
323             LocalArtifactResult local =
324                 lrm.find( session, new LocalArtifactRequest( artifact, repos, request.getRequestContext() ) );
325             if ( isLocallyInstalled( local, versionResult ) )
326             {
327                 if ( local.getRepository() != null )
328                 {
329                     result.setRepository( local.getRepository() );
330                 }
331                 else
332                 {
333                     result.setRepository( lrm.getRepository() );
334                 }
335                 try
336                 {
337                     artifact = artifact.setFile( getFile( session, artifact, local.getFile() ) );
338                     result.setArtifact( artifact );
339                     artifactResolved( session, trace, artifact, result.getRepository(), null );
340                 }
341                 catch ( ArtifactTransferException e )
342                 {
343                     result.addException( e );
344                 }
345                 if ( !local.isAvailable() )
346                 {
347                     /*
348                      * NOTE: Interop with simple local repository: An artifact installed by a simple local repo manager
349                      * will not show up in the repository tracking file of the enhanced local repository. If however the
350                      * maven-metadata-local.xml tells us the artifact was installed locally, we sync the repository
351                      * tracking file.
352                      */
353                     lrm.add( session, new LocalArtifactRegistration( artifact ) );
354                 }
355                 continue;
356             }
357             else if ( local.getFile() != null )
358             {
359                 LOGGER.debug( "Verifying availability of {} from {}", local.getFile(), repos );
360             }
361 
362             LOGGER.debug( "Resolving artifact {} from {}", artifact, repos );
363             AtomicBoolean resolved = new AtomicBoolean( false );
364             Iterator<ResolutionGroup> groupIt = groups.iterator();
365             for ( RemoteRepository repo : repos )
366             {
367                 if ( !repo.getPolicy( artifact.isSnapshot() ).isEnabled() )
368                 {
369                     continue;
370                 }
371 
372                 try
373                 {
374                     Utils.checkOffline( session, offlineController, repo );
375                 }
376                 catch ( RepositoryOfflineException e )
377                 {
378                     Exception exception =
379                         new ArtifactNotFoundException( artifact, repo, "Cannot access " + repo.getId() + " ("
380                             + repo.getUrl() + ") in offline mode and the artifact " + artifact
381                             + " has not been downloaded from it before.", e );
382                     result.addException( exception );
383                     continue;
384                 }
385 
386                 ResolutionGroup group = null;
387                 while ( groupIt.hasNext() )
388                 {
389                     ResolutionGroup t = groupIt.next();
390                     if ( t.matches( repo ) )
391                     {
392                         group = t;
393                         break;
394                     }
395                 }
396                 if ( group == null )
397                 {
398                     group = new ResolutionGroup( repo );
399                     groups.add( group );
400                     groupIt = Collections.<ResolutionGroup>emptyList().iterator();
401                 }
402                 group.items.add( new ResolutionItem( trace, artifact, resolved, result, local, repo ) );
403             }
404         }
405 
406         for ( ResolutionGroup group : groups )
407         {
408             performDownloads( session, group );
409         }
410 
411         for ( ArtifactResult result : results )
412         {
413             ArtifactRequest request = result.getRequest();
414 
415             Artifact artifact = result.getArtifact();
416             if ( artifact == null || artifact.getFile() == null )
417             {
418                 failures = true;
419                 if ( result.getExceptions().isEmpty() )
420                 {
421                     Exception exception = new ArtifactNotFoundException( request.getArtifact(), null );
422                     result.addException( exception );
423                 }
424                 RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
425                 artifactResolved( session, trace, request.getArtifact(), null, result.getExceptions() );
426             }
427         }
428 
429         if ( failures )
430         {
431             throw new ArtifactResolutionException( results );
432         }
433 
434         return results;
435     }
436 
437     private boolean isLocallyInstalled( LocalArtifactResult lar, VersionResult vr )
438     {
439         if ( lar.isAvailable() )
440         {
441             return true;
442         }
443         if ( lar.getFile() != null )
444         {
445             if ( vr.getRepository() instanceof LocalRepository )
446             {
447                 // resolution of (snapshot) version found locally installed artifact
448                 return true;
449             }
450             else if ( vr.getRepository() == null && lar.getRequest().getRepositories().isEmpty() )
451             {
452                 // resolution of version range found locally installed artifact
453                 return true;
454             }
455         }
456         return false;
457     }
458 
459     private File getFile( RepositorySystemSession session, Artifact artifact, File file )
460         throws ArtifactTransferException
461     {
462         if ( artifact.isSnapshot() && !artifact.getVersion().equals( artifact.getBaseVersion() )
463             && ConfigUtils.getBoolean( session, true, CONFIG_PROP_SNAPSHOT_NORMALIZATION ) )
464         {
465             String name = file.getName().replace( artifact.getVersion(), artifact.getBaseVersion() );
466             File dst = new File( file.getParent(), name );
467 
468             boolean copy = dst.length() != file.length() || dst.lastModified() != file.lastModified();
469             if ( copy )
470             {
471                 try
472                 {
473                     fileProcessor.copy( file, dst );
474                     dst.setLastModified( file.lastModified() );
475                 }
476                 catch ( IOException e )
477                 {
478                     throw new ArtifactTransferException( artifact, null, e );
479                 }
480             }
481 
482             file = dst;
483         }
484 
485         return file;
486     }
487 
488     private void performDownloads( RepositorySystemSession session, ResolutionGroup group )
489     {
490         List<ArtifactDownload> downloads = gatherDownloads( session, group );
491         if ( downloads.isEmpty() )
492         {
493             return;
494         }
495 
496         for ( ArtifactDownload download : downloads )
497         {
498             artifactDownloading( session, download.getTrace(), download.getArtifact(), group.repository );
499         }
500 
501         try
502         {
503             RemoteRepository repo = group.repository;
504             if ( repo.isBlocked() )
505             {
506                 if ( repo.getMirroredRepositories().isEmpty() )
507                 {
508                     throw new NoRepositoryConnectorException( repo, "Blocked repository: " + repo );
509                 }
510                 else
511                 {
512                     throw new NoRepositoryConnectorException( repo, "Blocked mirror for repositories: "
513                         + repo.getMirroredRepositories() );
514                 }
515             }
516 
517             try ( RepositoryConnector connector =
518                           repositoryConnectorProvider.newRepositoryConnector( session, group.repository ) )
519             {
520                 connector.get( downloads, null );
521             }
522         }
523         catch ( NoRepositoryConnectorException e )
524         {
525             for ( ArtifactDownload download : downloads )
526             {
527                 download.setException( new ArtifactTransferException( download.getArtifact(), group.repository, e ) );
528             }
529         }
530 
531         evaluateDownloads( session, group );
532     }
533 
534     private List<ArtifactDownload> gatherDownloads( RepositorySystemSession session, ResolutionGroup group )
535     {
536         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
537         List<ArtifactDownload> downloads = new ArrayList<>();
538 
539         for ( ResolutionItem item : group.items )
540         {
541             Artifact artifact = item.artifact;
542 
543             if ( item.resolved.get() )
544             {
545                 // resolved in previous resolution group
546                 continue;
547             }
548 
549             ArtifactDownload download = new ArtifactDownload();
550             download.setArtifact( artifact );
551             download.setRequestContext( item.request.getRequestContext() );
552             download.setListener( SafeTransferListener.wrap( session ) );
553             download.setTrace( item.trace );
554             if ( item.local.getFile() != null )
555             {
556                 download.setFile( item.local.getFile() );
557                 download.setExistenceCheck( true );
558             }
559             else
560             {
561                 String path =
562                     lrm.getPathForRemoteArtifact( artifact, group.repository, item.request.getRequestContext() );
563                 download.setFile( new File( lrm.getRepository().getBasedir(), path ) );
564             }
565 
566             boolean snapshot = artifact.isSnapshot();
567             RepositoryPolicy policy =
568                 remoteRepositoryManager.getPolicy( session, group.repository, !snapshot, snapshot );
569 
570             int errorPolicy = Utils.getPolicy( session, artifact, group.repository );
571             if ( ( errorPolicy & ResolutionErrorPolicy.CACHE_ALL ) != 0 )
572             {
573                 UpdateCheck<Artifact, ArtifactTransferException> check = new UpdateCheck<>();
574                 check.setItem( artifact );
575                 check.setFile( download.getFile() );
576                 check.setFileValid( false );
577                 check.setRepository( group.repository );
578                 check.setPolicy( policy.getUpdatePolicy() );
579                 item.updateCheck = check;
580                 updateCheckManager.checkArtifact( session, check );
581                 if ( !check.isRequired() )
582                 {
583                     item.result.addException( check.getException() );
584                     continue;
585                 }
586             }
587 
588             download.setChecksumPolicy( policy.getChecksumPolicy() );
589             download.setRepositories( item.repository.getMirroredRepositories() );
590             downloads.add( download );
591             item.download = download;
592         }
593 
594         return downloads;
595     }
596 
597     private void evaluateDownloads( RepositorySystemSession session, ResolutionGroup group )
598     {
599         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
600 
601         for ( ResolutionItem item : group.items )
602         {
603             ArtifactDownload download = item.download;
604             if ( download == null )
605             {
606                 continue;
607             }
608 
609             Artifact artifact = download.getArtifact();
610             if ( download.getException() == null )
611             {
612                 item.resolved.set( true );
613                 item.result.setRepository( group.repository );
614                 try
615                 {
616                     artifact = artifact.setFile( getFile( session, artifact, download.getFile() ) );
617                     item.result.setArtifact( artifact );
618 
619                     lrm.add( session, new LocalArtifactRegistration(
620                             artifact, group.repository, download.getSupportedContexts() ) );
621                 }
622                 catch ( ArtifactTransferException e )
623                 {
624                     download.setException( e );
625                     item.result.addException( e );
626                 }
627             }
628             else
629             {
630                 item.result.addException( download.getException() );
631             }
632 
633             /*
634              * NOTE: Touch after registration with local repo to ensure concurrent resolution is not rejected with
635              * "already updated" via session data when actual update to local repo is still pending.
636              */
637             if ( item.updateCheck != null )
638             {
639                 item.updateCheck.setException( download.getException() );
640                 updateCheckManager.touchArtifact( session, item.updateCheck );
641             }
642 
643             artifactDownloaded( session, download.getTrace(), artifact, group.repository, download.getException() );
644             if ( download.getException() == null )
645             {
646                 artifactResolved( session, download.getTrace(), artifact, group.repository, null );
647             }
648         }
649     }
650 
651     private void artifactResolving( RepositorySystemSession session, RequestTrace trace, Artifact artifact )
652     {
653         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_RESOLVING );
654         event.setTrace( trace );
655         event.setArtifact( artifact );
656 
657         repositoryEventDispatcher.dispatch( event.build() );
658     }
659 
660     private void artifactResolved( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
661                                    ArtifactRepository repository, List<Exception> exceptions )
662     {
663         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_RESOLVED );
664         event.setTrace( trace );
665         event.setArtifact( artifact );
666         event.setRepository( repository );
667         event.setExceptions( exceptions );
668         if ( artifact != null )
669         {
670             event.setFile( artifact.getFile() );
671         }
672 
673         repositoryEventDispatcher.dispatch( event.build() );
674     }
675 
676     private void artifactDownloading( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
677                                       RemoteRepository repository )
678     {
679         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DOWNLOADING );
680         event.setTrace( trace );
681         event.setArtifact( artifact );
682         event.setRepository( repository );
683 
684         repositoryEventDispatcher.dispatch( event.build() );
685     }
686 
687     private void artifactDownloaded( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
688                                      RemoteRepository repository, Exception exception )
689     {
690         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DOWNLOADED );
691         event.setTrace( trace );
692         event.setArtifact( artifact );
693         event.setRepository( repository );
694         event.setException( exception );
695         if ( artifact != null )
696         {
697             event.setFile( artifact.getFile() );
698         }
699 
700         repositoryEventDispatcher.dispatch( event.build() );
701     }
702 
703     static class ResolutionGroup
704     {
705 
706         final RemoteRepository repository;
707 
708         final List<ResolutionItem> items = new ArrayList<>();
709 
710         ResolutionGroup( RemoteRepository repository )
711         {
712             this.repository = repository;
713         }
714 
715         boolean matches( RemoteRepository repo )
716         {
717             return repository.getUrl().equals( repo.getUrl() )
718                 && repository.getContentType().equals( repo.getContentType() )
719                 && repository.isRepositoryManager() == repo.isRepositoryManager();
720         }
721 
722     }
723 
724     static class ResolutionItem
725     {
726 
727         final RequestTrace trace;
728 
729         final ArtifactRequest request;
730 
731         final ArtifactResult result;
732 
733         final LocalArtifactResult local;
734 
735         final RemoteRepository repository;
736 
737         final Artifact artifact;
738 
739         final AtomicBoolean resolved;
740 
741         ArtifactDownload download;
742 
743         UpdateCheck<Artifact, ArtifactTransferException> updateCheck;
744 
745         ResolutionItem( RequestTrace trace, Artifact artifact, AtomicBoolean resolved, ArtifactResult result,
746                         LocalArtifactResult local, RemoteRepository repository )
747         {
748             this.trace = trace;
749             this.artifact = artifact;
750             this.resolved = resolved;
751             this.result = result;
752             this.request = result.getRequest();
753             this.local = local;
754             this.repository = repository;
755         }
756 
757     }
758 
759 }