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