001package org.eclipse.aether.internal.impl;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 * 
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.io.IOException;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.Collections;
027import java.util.Iterator;
028import java.util.List;
029import static java.util.Objects.requireNonNull;
030import java.util.concurrent.atomic.AtomicBoolean;
031
032import javax.inject.Inject;
033import javax.inject.Named;
034import javax.inject.Singleton;
035
036import org.eclipse.aether.RepositoryEvent;
037import org.eclipse.aether.RepositoryEvent.EventType;
038import org.eclipse.aether.RepositorySystemSession;
039import org.eclipse.aether.RequestTrace;
040import org.eclipse.aether.SyncContext;
041import org.eclipse.aether.artifact.Artifact;
042import org.eclipse.aether.artifact.ArtifactProperties;
043import org.eclipse.aether.impl.ArtifactResolver;
044import org.eclipse.aether.impl.OfflineController;
045import org.eclipse.aether.impl.RemoteRepositoryManager;
046import org.eclipse.aether.impl.RepositoryConnectorProvider;
047import org.eclipse.aether.impl.RepositoryEventDispatcher;
048import org.eclipse.aether.spi.synccontext.SyncContextFactory;
049import org.eclipse.aether.impl.UpdateCheck;
050import org.eclipse.aether.impl.UpdateCheckManager;
051import org.eclipse.aether.impl.VersionResolver;
052import org.eclipse.aether.repository.ArtifactRepository;
053import org.eclipse.aether.repository.LocalArtifactRegistration;
054import org.eclipse.aether.repository.LocalArtifactRequest;
055import org.eclipse.aether.repository.LocalArtifactResult;
056import org.eclipse.aether.repository.LocalRepository;
057import org.eclipse.aether.repository.LocalRepositoryManager;
058import org.eclipse.aether.repository.RemoteRepository;
059import org.eclipse.aether.repository.RepositoryPolicy;
060import org.eclipse.aether.repository.WorkspaceReader;
061import org.eclipse.aether.resolution.ArtifactRequest;
062import org.eclipse.aether.resolution.ArtifactResolutionException;
063import org.eclipse.aether.resolution.ArtifactResult;
064import org.eclipse.aether.resolution.ResolutionErrorPolicy;
065import org.eclipse.aether.resolution.VersionRequest;
066import org.eclipse.aether.resolution.VersionResolutionException;
067import org.eclipse.aether.resolution.VersionResult;
068import org.eclipse.aether.spi.connector.ArtifactDownload;
069import org.eclipse.aether.spi.connector.RepositoryConnector;
070import org.eclipse.aether.spi.io.FileProcessor;
071import org.eclipse.aether.spi.locator.Service;
072import org.eclipse.aether.spi.locator.ServiceLocator;
073import org.eclipse.aether.transfer.ArtifactNotFoundException;
074import org.eclipse.aether.transfer.ArtifactTransferException;
075import org.eclipse.aether.transfer.NoRepositoryConnectorException;
076import org.eclipse.aether.transfer.RepositoryOfflineException;
077import org.eclipse.aether.util.ConfigUtils;
078import org.slf4j.Logger;
079import org.slf4j.LoggerFactory;
080
081/**
082 */
083@Singleton
084@Named
085public class DefaultArtifactResolver
086    implements ArtifactResolver, Service
087{
088
089    private static final String CONFIG_PROP_SNAPSHOT_NORMALIZATION = "aether.artifactResolver.snapshotNormalization";
090
091    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultArtifactResolver.class );
092
093    private FileProcessor fileProcessor;
094
095    private RepositoryEventDispatcher repositoryEventDispatcher;
096
097    private VersionResolver versionResolver;
098
099    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}