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;
034
035import org.eclipse.aether.RepositoryEvent;
036import org.eclipse.aether.RepositoryEvent.EventType;
037import org.eclipse.aether.RepositorySystemSession;
038import org.eclipse.aether.RequestTrace;
039import org.eclipse.aether.SyncContext;
040import org.eclipse.aether.artifact.Artifact;
041import org.eclipse.aether.artifact.ArtifactProperties;
042import org.eclipse.aether.impl.ArtifactResolver;
043import org.eclipse.aether.impl.OfflineController;
044import org.eclipse.aether.impl.RemoteRepositoryManager;
045import org.eclipse.aether.impl.RepositoryConnectorProvider;
046import org.eclipse.aether.impl.RepositoryEventDispatcher;
047import org.eclipse.aether.impl.SyncContextFactory;
048import org.eclipse.aether.impl.UpdateCheck;
049import org.eclipse.aether.impl.UpdateCheckManager;
050import org.eclipse.aether.impl.VersionResolver;
051import org.eclipse.aether.repository.ArtifactRepository;
052import org.eclipse.aether.repository.LocalArtifactRegistration;
053import org.eclipse.aether.repository.LocalArtifactRequest;
054import org.eclipse.aether.repository.LocalArtifactResult;
055import org.eclipse.aether.repository.LocalRepository;
056import org.eclipse.aether.repository.LocalRepositoryManager;
057import org.eclipse.aether.repository.RemoteRepository;
058import org.eclipse.aether.repository.RepositoryPolicy;
059import org.eclipse.aether.repository.WorkspaceReader;
060import org.eclipse.aether.resolution.ArtifactRequest;
061import org.eclipse.aether.resolution.ArtifactResolutionException;
062import org.eclipse.aether.resolution.ArtifactResult;
063import org.eclipse.aether.resolution.ResolutionErrorPolicy;
064import org.eclipse.aether.resolution.VersionRequest;
065import org.eclipse.aether.resolution.VersionResolutionException;
066import org.eclipse.aether.resolution.VersionResult;
067import org.eclipse.aether.spi.connector.ArtifactDownload;
068import org.eclipse.aether.spi.connector.RepositoryConnector;
069import org.eclipse.aether.spi.io.FileProcessor;
070import org.eclipse.aether.spi.locator.Service;
071import org.eclipse.aether.spi.locator.ServiceLocator;
072import org.eclipse.aether.transfer.ArtifactNotFoundException;
073import org.eclipse.aether.transfer.ArtifactTransferException;
074import org.eclipse.aether.transfer.NoRepositoryConnectorException;
075import org.eclipse.aether.transfer.RepositoryOfflineException;
076import org.eclipse.aether.util.ConfigUtils;
077import org.slf4j.Logger;
078import org.slf4j.LoggerFactory;
079
080/**
081 */
082@Named
083public class DefaultArtifactResolver
084    implements ArtifactResolver, Service
085{
086
087    private static final String CONFIG_PROP_SNAPSHOT_NORMALIZATION = "aether.artifactResolver.snapshotNormalization";
088
089    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultArtifactResolver.class );
090
091    private FileProcessor fileProcessor;
092
093    private RepositoryEventDispatcher repositoryEventDispatcher;
094
095    private VersionResolver versionResolver;
096
097    private UpdateCheckManager updateCheckManager;
098
099    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            try ( RepositoryConnector connector =
497                          repositoryConnectorProvider.newRepositoryConnector( session, group.repository ) )
498            {
499                connector.get( downloads, null );
500            }
501        }
502        catch ( NoRepositoryConnectorException e )
503        {
504            for ( ArtifactDownload download : downloads )
505            {
506                download.setException( new ArtifactTransferException( download.getArtifact(), group.repository, e ) );
507            }
508        }
509
510        evaluateDownloads( session, group );
511    }
512
513    private List<ArtifactDownload> gatherDownloads( RepositorySystemSession session, ResolutionGroup group )
514    {
515        LocalRepositoryManager lrm = session.getLocalRepositoryManager();
516        List<ArtifactDownload> downloads = new ArrayList<>();
517
518        for ( ResolutionItem item : group.items )
519        {
520            Artifact artifact = item.artifact;
521
522            if ( item.resolved.get() )
523            {
524                // resolved in previous resolution group
525                continue;
526            }
527
528            ArtifactDownload download = new ArtifactDownload();
529            download.setArtifact( artifact );
530            download.setRequestContext( item.request.getRequestContext() );
531            download.setListener( SafeTransferListener.wrap( session ) );
532            download.setTrace( item.trace );
533            if ( item.local.getFile() != null )
534            {
535                download.setFile( item.local.getFile() );
536                download.setExistenceCheck( true );
537            }
538            else
539            {
540                String path =
541                    lrm.getPathForRemoteArtifact( artifact, group.repository, item.request.getRequestContext() );
542                download.setFile( new File( lrm.getRepository().getBasedir(), path ) );
543            }
544
545            boolean snapshot = artifact.isSnapshot();
546            RepositoryPolicy policy =
547                remoteRepositoryManager.getPolicy( session, group.repository, !snapshot, snapshot );
548
549            int errorPolicy = Utils.getPolicy( session, artifact, group.repository );
550            if ( ( errorPolicy & ResolutionErrorPolicy.CACHE_ALL ) != 0 )
551            {
552                UpdateCheck<Artifact, ArtifactTransferException> check = new UpdateCheck<>();
553                check.setItem( artifact );
554                check.setFile( download.getFile() );
555                check.setFileValid( false );
556                check.setRepository( group.repository );
557                check.setPolicy( policy.getUpdatePolicy() );
558                item.updateCheck = check;
559                updateCheckManager.checkArtifact( session, check );
560                if ( !check.isRequired() )
561                {
562                    item.result.addException( check.getException() );
563                    continue;
564                }
565            }
566
567            download.setChecksumPolicy( policy.getChecksumPolicy() );
568            download.setRepositories( item.repository.getMirroredRepositories() );
569            downloads.add( download );
570            item.download = download;
571        }
572
573        return downloads;
574    }
575
576    private void evaluateDownloads( RepositorySystemSession session, ResolutionGroup group )
577    {
578        LocalRepositoryManager lrm = session.getLocalRepositoryManager();
579
580        for ( ResolutionItem item : group.items )
581        {
582            ArtifactDownload download = item.download;
583            if ( download == null )
584            {
585                continue;
586            }
587
588            Artifact artifact = download.getArtifact();
589            if ( download.getException() == null )
590            {
591                item.resolved.set( true );
592                item.result.setRepository( group.repository );
593                try
594                {
595                    artifact = artifact.setFile( getFile( session, artifact, download.getFile() ) );
596                    item.result.setArtifact( artifact );
597
598                    lrm.add( session, new LocalArtifactRegistration(
599                            artifact, group.repository, download.getSupportedContexts() ) );
600                }
601                catch ( ArtifactTransferException e )
602                {
603                    download.setException( e );
604                    item.result.addException( e );
605                }
606            }
607            else
608            {
609                item.result.addException( download.getException() );
610            }
611
612            /*
613             * NOTE: Touch after registration with local repo to ensure concurrent resolution is not rejected with
614             * "already updated" via session data when actual update to local repo is still pending.
615             */
616            if ( item.updateCheck != null )
617            {
618                item.updateCheck.setException( download.getException() );
619                updateCheckManager.touchArtifact( session, item.updateCheck );
620            }
621
622            artifactDownloaded( session, download.getTrace(), artifact, group.repository, download.getException() );
623            if ( download.getException() == null )
624            {
625                artifactResolved( session, download.getTrace(), artifact, group.repository, null );
626            }
627        }
628    }
629
630    private void artifactResolving( RepositorySystemSession session, RequestTrace trace, Artifact artifact )
631    {
632        RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_RESOLVING );
633        event.setTrace( trace );
634        event.setArtifact( artifact );
635
636        repositoryEventDispatcher.dispatch( event.build() );
637    }
638
639    private void artifactResolved( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
640                                   ArtifactRepository repository, List<Exception> exceptions )
641    {
642        RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_RESOLVED );
643        event.setTrace( trace );
644        event.setArtifact( artifact );
645        event.setRepository( repository );
646        event.setExceptions( exceptions );
647        if ( artifact != null )
648        {
649            event.setFile( artifact.getFile() );
650        }
651
652        repositoryEventDispatcher.dispatch( event.build() );
653    }
654
655    private void artifactDownloading( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
656                                      RemoteRepository repository )
657    {
658        RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DOWNLOADING );
659        event.setTrace( trace );
660        event.setArtifact( artifact );
661        event.setRepository( repository );
662
663        repositoryEventDispatcher.dispatch( event.build() );
664    }
665
666    private void artifactDownloaded( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
667                                     RemoteRepository repository, Exception exception )
668    {
669        RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DOWNLOADED );
670        event.setTrace( trace );
671        event.setArtifact( artifact );
672        event.setRepository( repository );
673        event.setException( exception );
674        if ( artifact != null )
675        {
676            event.setFile( artifact.getFile() );
677        }
678
679        repositoryEventDispatcher.dispatch( event.build() );
680    }
681
682    static class ResolutionGroup
683    {
684
685        final RemoteRepository repository;
686
687        final List<ResolutionItem> items = new ArrayList<>();
688
689        ResolutionGroup( RemoteRepository repository )
690        {
691            this.repository = repository;
692        }
693
694        boolean matches( RemoteRepository repo )
695        {
696            return repository.getUrl().equals( repo.getUrl() )
697                && repository.getContentType().equals( repo.getContentType() )
698                && repository.isRepositoryManager() == repo.isRepositoryManager();
699        }
700
701    }
702
703    static class ResolutionItem
704    {
705
706        final RequestTrace trace;
707
708        final ArtifactRequest request;
709
710        final ArtifactResult result;
711
712        final LocalArtifactResult local;
713
714        final RemoteRepository repository;
715
716        final Artifact artifact;
717
718        final AtomicBoolean resolved;
719
720        ArtifactDownload download;
721
722        UpdateCheck<Artifact, ArtifactTransferException> updateCheck;
723
724        ResolutionItem( RequestTrace trace, Artifact artifact, AtomicBoolean resolved, ArtifactResult result,
725                        LocalArtifactResult local, RemoteRepository repository )
726        {
727            this.trace = trace;
728            this.artifact = artifact;
729            this.resolved = resolved;
730            this.result = result;
731            this.request = result.getRequest();
732            this.local = local;
733            this.repository = repository;
734        }
735
736    }
737
738}