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