1   package org.apache.maven.artifact.resolver;
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  import java.io.File;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.LinkedHashMap;
26  import java.util.LinkedHashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.concurrent.CountDownLatch;
31  import java.util.concurrent.Executor;
32  import java.util.concurrent.ExecutorService;
33  import java.util.concurrent.LinkedBlockingQueue;
34  import java.util.concurrent.ThreadFactory;
35  import java.util.concurrent.ThreadPoolExecutor;
36  import java.util.concurrent.TimeUnit;
37  import java.util.concurrent.atomic.AtomicInteger;
38  import java.util.regex.Matcher;
39  
40  import org.apache.maven.RepositoryUtils;
41  import org.apache.maven.artifact.Artifact;
42  import org.apache.maven.artifact.factory.ArtifactFactory;
43  import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
44  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
45  import org.apache.maven.artifact.metadata.ResolutionGroup;
46  import org.apache.maven.artifact.repository.ArtifactRepository;
47  import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager;
48  import org.apache.maven.artifact.repository.RepositoryRequest;
49  import org.apache.maven.artifact.repository.metadata.Snapshot;
50  import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
51  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
52  import org.apache.maven.execution.MavenSession;
53  import org.apache.maven.plugin.LegacySupport;
54  import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
55  import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
56  import org.apache.maven.repository.legacy.resolver.conflict.ConflictResolver;
57  import org.apache.maven.wagon.events.TransferListener;
58  import org.codehaus.plexus.PlexusContainer;
59  import org.codehaus.plexus.component.annotations.Component;
60  import org.codehaus.plexus.component.annotations.Requirement;
61  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
62  import org.codehaus.plexus.logging.Logger;
63  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
64  import org.eclipse.aether.RepositorySystem;
65  import org.eclipse.aether.RepositorySystemSession;
66  import org.eclipse.aether.repository.LocalRepositoryManager;
67  import org.eclipse.aether.resolution.ArtifactRequest;
68  import org.eclipse.aether.resolution.ArtifactResult;
69  
70  
71  
72  
73  @Component( role = ArtifactResolver.class )
74  public class DefaultArtifactResolver
75      implements ArtifactResolver, Disposable
76  {
77      @Requirement
78      private Logger logger;
79  
80      @Requirement
81      protected ArtifactFactory artifactFactory;
82  
83      @Requirement
84      private ArtifactCollector artifactCollector;
85  
86      @Requirement
87      private ResolutionErrorHandler resolutionErrorHandler;
88  
89      @Requirement
90      private ArtifactMetadataSource source;
91  
92      @Requirement
93      private PlexusContainer container;
94  
95      @Requirement
96      private LegacySupport legacySupport;
97  
98      @Requirement
99      private RepositorySystem repoSystem;
100 
101     private final Executor executor;
102 
103     public DefaultArtifactResolver()
104     {
105         int threads = Integer.getInteger( "maven.artifact.threads", 5 );
106         if ( threads <= 1 )
107         {
108             executor = new Executor()
109             {
110                 public void execute( Runnable command )
111                 {
112                     command.run();
113                 }
114             };
115         }
116         else
117         {
118             executor = new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS,
119                                                new LinkedBlockingQueue<Runnable>(), new DaemonThreadCreator() );
120         }
121     }
122 
123     private RepositorySystemSession getSession( ArtifactRepository localRepository )
124     {
125         return LegacyLocalRepositoryManager.overlay( localRepository, legacySupport.getRepositorySession(),
126                                                      repoSystem );
127     }
128 
129     private void injectSession1( RepositoryRequest request, MavenSession session )
130     {
131         if ( session != null )
132         {
133             request.setOffline( session.isOffline() );
134             request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
135         }
136     }
137 
138     private void injectSession2( ArtifactResolutionRequest request, MavenSession session )
139     {
140         injectSession1( request, session );
141 
142         if ( session != null )
143         {
144             request.setServers( session.getRequest().getServers() );
145             request.setMirrors( session.getRequest().getMirrors() );
146             request.setProxies( session.getRequest().getProxies() );
147         }
148     }
149 
150     public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
151                          ArtifactRepository localRepository, TransferListener resolutionListener )
152                              throws ArtifactResolutionException, ArtifactNotFoundException
153     {
154         resolve( artifact, remoteRepositories, getSession( localRepository ) );
155     }
156 
157     public void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories,
158                                ArtifactRepository localRepository )
159                                    throws ArtifactResolutionException, ArtifactNotFoundException
160     {
161         resolve( artifact, remoteRepositories, getSession( localRepository ) );
162     }
163 
164     private void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
165                           RepositorySystemSession session )
166                               throws ArtifactResolutionException, ArtifactNotFoundException
167     {
168         if ( artifact == null )
169         {
170             return;
171         }
172 
173         if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
174         {
175             File systemFile = artifact.getFile();
176 
177             if ( systemFile == null )
178             {
179                 throw new ArtifactNotFoundException( "System artifact: " + artifact + " has no file attached",
180                                                      artifact );
181             }
182 
183             if ( !systemFile.exists() )
184             {
185                 throw new ArtifactNotFoundException( "System artifact: " + artifact + " not found in path: "
186                     + systemFile, artifact );
187             }
188 
189             if ( !systemFile.isFile() )
190             {
191                 throw new ArtifactNotFoundException( "System artifact: " + artifact + " is not a file: " + systemFile,
192                                                      artifact );
193             }
194 
195             artifact.setResolved( true );
196 
197             return;
198         }
199 
200         if ( !artifact.isResolved() )
201         {
202             ArtifactResult result;
203 
204             try
205             {
206                 ArtifactRequest artifactRequest = new ArtifactRequest();
207                 artifactRequest.setArtifact( RepositoryUtils.toArtifact( artifact ) );
208                 artifactRequest.setRepositories( RepositoryUtils.toRepos( remoteRepositories ) );
209 
210                 
211                 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
212                 String path = lrm.getPathForLocalArtifact( artifactRequest.getArtifact() );
213                 artifact.setFile( new File( lrm.getRepository().getBasedir(), path ) );
214 
215                 result = repoSystem.resolveArtifact( session, artifactRequest );
216             }
217             catch ( org.eclipse.aether.resolution.ArtifactResolutionException e )
218             {
219                 if ( e.getCause() instanceof org.eclipse.aether.transfer.ArtifactNotFoundException )
220                 {
221                     throw new ArtifactNotFoundException( e.getMessage(), artifact, remoteRepositories, e );
222                 }
223                 else
224                 {
225                     throw new ArtifactResolutionException( e.getMessage(), artifact, remoteRepositories, e );
226                 }
227             }
228 
229             artifact.selectVersion( result.getArtifact().getVersion() );
230             artifact.setFile( result.getArtifact().getFile() );
231             artifact.setResolved( true );
232 
233             if ( artifact.isSnapshot() )
234             {
235                 Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
236                 if ( matcher.matches() )
237                 {
238                     Snapshot snapshot = new Snapshot();
239                     snapshot.setTimestamp( matcher.group( 2 ) );
240                     try
241                     {
242                         snapshot.setBuildNumber( Integer.parseInt( matcher.group( 3 ) ) );
243                         artifact.addMetadata( new SnapshotArtifactRepositoryMetadata( artifact, snapshot ) );
244                     }
245                     catch ( NumberFormatException e )
246                     {
247                         logger.warn( "Invalid artifact version " + artifact.getVersion() + ": " + e.getMessage() );
248                     }
249                 }
250             }
251         }
252     }
253 
254     public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
255                                                          ArtifactRepository localRepository,
256                                                          List<ArtifactRepository> remoteRepositories,
257                                                          ArtifactMetadataSource source, ArtifactFilter filter )
258                                                              throws ArtifactResolutionException,
259                                                              ArtifactNotFoundException
260     {
261         return resolveTransitively(
262                 artifacts, originatingArtifact, Collections.<String, Artifact>emptyMap(), localRepository,
263                                     remoteRepositories, source, filter );
264 
265     }
266 
267     public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
268                                                          Map<String, Artifact> managedVersions,
269                                                          ArtifactRepository localRepository,
270                                                          List<ArtifactRepository> remoteRepositories,
271                                                          ArtifactMetadataSource source )
272                                                              throws ArtifactResolutionException,
273                                                              ArtifactNotFoundException
274     {
275         return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
276                                     remoteRepositories, source, null );
277     }
278 
279     public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
280                                                          Map<String, Artifact> managedVersions,
281                                                          ArtifactRepository localRepository,
282                                                          List<ArtifactRepository> remoteRepositories,
283                                                          ArtifactMetadataSource source, ArtifactFilter filter )
284                                                              throws ArtifactResolutionException,
285                                                              ArtifactNotFoundException
286     {
287         return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
288                                     remoteRepositories, source, filter, null );
289     }
290 
291     public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
292                                                          List<ArtifactRepository> remoteRepositories,
293                                                          ArtifactRepository localRepository,
294                                                          ArtifactMetadataSource source )
295                                                              throws ArtifactResolutionException,
296                                                              ArtifactNotFoundException
297     {
298         return resolveTransitively( artifacts, originatingArtifact, localRepository, remoteRepositories, source, null );
299     }
300 
301     public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
302                                                          List<ArtifactRepository> remoteRepositories,
303                                                          ArtifactRepository localRepository,
304                                                          ArtifactMetadataSource source,
305                                                          List<ResolutionListener> listeners )
306                                                              throws ArtifactResolutionException,
307                                                              ArtifactNotFoundException
308     {
309         return resolveTransitively(
310                 artifacts, originatingArtifact, Collections.<String, Artifact>emptyMap(), localRepository,
311                                     remoteRepositories, source, null, listeners );
312     }
313 
314     @SuppressWarnings( "checkstyle:parameternumber" )
315     public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
316                                                          Map<String, Artifact> managedVersions,
317                                                          ArtifactRepository localRepository,
318                                                          List<ArtifactRepository> remoteRepositories,
319                                                          ArtifactMetadataSource source, ArtifactFilter filter,
320                                                          List<ResolutionListener> listeners )
321                                                              throws ArtifactResolutionException,
322                                                              ArtifactNotFoundException
323     {
324         return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
325                                     remoteRepositories, source, filter, listeners, null );
326     }
327 
328     @SuppressWarnings( "checkstyle:parameternumber" )
329     public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
330                                                          Map<String, Artifact> managedVersions,
331                                                          ArtifactRepository localRepository,
332                                                          List<ArtifactRepository> remoteRepositories,
333                                                          ArtifactMetadataSource source, ArtifactFilter filter,
334                                                          List<ResolutionListener> listeners,
335                                                          List<ConflictResolver> conflictResolvers )
336                                                              throws ArtifactResolutionException,
337                                                              ArtifactNotFoundException
338     {
339         ArtifactResolutionRequest request = new ArtifactResolutionRequest().
340             setArtifact( originatingArtifact ).
341             setResolveRoot( false ).
342             
343             setArtifactDependencies( artifacts ).
344             setManagedVersionMap( managedVersions ).
345             setLocalRepository( localRepository ).
346             setRemoteRepositories( remoteRepositories ).
347             setCollectionFilter( filter ).
348             setListeners( listeners );
349 
350         injectSession2( request, legacySupport.getSession() );
351 
352         return resolveWithExceptions( request );
353     }
354 
355     public ArtifactResolutionResult resolveWithExceptions( ArtifactResolutionRequest request )
356         throws ArtifactResolutionException, ArtifactNotFoundException
357     {
358         ArtifactResolutionResult result = resolve( request );
359 
360         
361         
362         
363 
364         resolutionErrorHandler.throwErrors( request, result );
365 
366         return result;
367     }
368 
369     
370     
371     
372 
373     @SuppressWarnings( "checkstyle:methodlength" )
374     public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
375     {
376         Artifact rootArtifact = request.getArtifact();
377         Set<Artifact> artifacts = request.getArtifactDependencies();
378         Map<String, Artifact> managedVersions = request.getManagedVersionMap();
379         List<ResolutionListener> listeners = request.getListeners();
380         ArtifactFilter collectionFilter = request.getCollectionFilter();
381         ArtifactFilter resolutionFilter = request.getResolutionFilter();
382         RepositorySystemSession session = getSession( request.getLocalRepository() );
383 
384         
385         
386         if ( source == null )
387         {
388             try
389             {
390                 source = container.lookup( ArtifactMetadataSource.class );
391             }
392             catch ( ComponentLookupException e )
393             {
394                 
395             }
396         }
397 
398         if ( listeners == null )
399         {
400             listeners = new ArrayList<>();
401 
402             if ( logger.isDebugEnabled() )
403             {
404                 listeners.add( new DebugResolutionListener( logger ) );
405             }
406 
407             listeners.add( new WarningResolutionListener( logger ) );
408         }
409 
410         ArtifactResolutionResult result = new ArtifactResolutionResult();
411 
412         
413         
414         
415         
416 
417         if ( request.isResolveRoot()  )
418         {
419             try
420             {
421                 resolve( rootArtifact, request.getRemoteRepositories(), session );
422             }
423             catch ( ArtifactResolutionException e )
424             {
425                 result.addErrorArtifactException( e );
426                 return result;
427             }
428             catch ( ArtifactNotFoundException e )
429             {
430                 result.addMissingArtifact( request.getArtifact() );
431                 return result;
432             }
433         }
434 
435         ArtifactResolutionRequest collectionRequest = request;
436 
437         if ( request.isResolveTransitively() )
438         {
439             MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest( request );
440 
441             metadataRequest.setArtifact( rootArtifact );
442             metadataRequest.setResolveManagedVersions( managedVersions == null );
443 
444             try
445             {
446                 ResolutionGroup resolutionGroup = source.retrieve( metadataRequest );
447 
448                 if ( managedVersions == null )
449                 {
450                     managedVersions = resolutionGroup.getManagedVersions();
451                 }
452 
453                 Set<Artifact> directArtifacts = resolutionGroup.getArtifacts();
454 
455                 if ( artifacts == null || artifacts.isEmpty() )
456                 {
457                     artifacts = directArtifacts;
458                 }
459                 else
460                 {
461                     List<Artifact> allArtifacts = new ArrayList<>();
462                     allArtifacts.addAll( artifacts );
463                     allArtifacts.addAll( directArtifacts );
464 
465                     Map<String, Artifact> mergedArtifacts = new LinkedHashMap<>();
466                     for ( Artifact artifact : allArtifacts )
467                     {
468                         String conflictId = artifact.getDependencyConflictId();
469                         if ( !mergedArtifacts.containsKey( conflictId ) )
470                         {
471                             mergedArtifacts.put( conflictId, artifact );
472                         }
473                     }
474 
475                     artifacts = new LinkedHashSet<>( mergedArtifacts.values() );
476                 }
477 
478                 collectionRequest = new ArtifactResolutionRequest( request );
479                 collectionRequest.setServers( request.getServers() );
480                 collectionRequest.setMirrors( request.getMirrors() );
481                 collectionRequest.setProxies( request.getProxies() );
482                 collectionRequest.setRemoteRepositories( resolutionGroup.getResolutionRepositories() );
483             }
484             catch ( ArtifactMetadataRetrievalException e )
485             {
486                 ArtifactResolutionException are =
487                     new ArtifactResolutionException( "Unable to get dependency information for " + rootArtifact.getId()
488                         + ": " + e.getMessage(), rootArtifact, metadataRequest.getRemoteRepositories(), e );
489                 result.addMetadataResolutionException( are );
490                 return result;
491             }
492         }
493 
494         if ( artifacts == null || artifacts.isEmpty() )
495         {
496             if ( request.isResolveRoot() )
497             {
498                 result.addArtifact( rootArtifact );
499             }
500             return result;
501         }
502 
503         
504         result = artifactCollector.collect( artifacts, rootArtifact, managedVersions, collectionRequest, source,
505                                             collectionFilter, listeners, null );
506 
507         
508         
509         
510 
511         if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations()
512             || result.hasCircularDependencyExceptions() )
513         {
514             logger.info( "Failure detected." );
515             return result;
516         }
517 
518         if ( result.getArtifactResolutionNodes() != null )
519         {
520             ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
521 
522             CountDownLatch latch = new CountDownLatch( result.getArtifactResolutionNodes().size() );
523 
524             for ( ResolutionNode node : result.getArtifactResolutionNodes() )
525             {
526                 Artifact artifact = node.getArtifact();
527 
528                 if ( resolutionFilter == null || resolutionFilter.include( artifact ) )
529                 {
530                     executor.execute( new ResolveTask( classLoader, latch, artifact, session,
531                                                        node.getRemoteRepositories(), result ) );
532                 }
533                 else
534                 {
535                     latch.countDown();
536                 }
537             }
538             try
539             {
540                 latch.await();
541             }
542             catch ( InterruptedException e )
543             {
544                 result.addErrorArtifactException( new ArtifactResolutionException( "Resolution interrupted",
545                                                                                    rootArtifact, e ) );
546             }
547         }
548 
549         
550         
551         if ( request.isResolveRoot() )
552         {
553             
554             Set<Artifact> allArtifacts = new LinkedHashSet<>();
555             allArtifacts.add( rootArtifact );
556             allArtifacts.addAll( result.getArtifacts() );
557             result.setArtifacts( allArtifacts );
558         }
559 
560         return result;
561     }
562 
563     public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
564                          ArtifactRepository localRepository )
565                              throws ArtifactResolutionException, ArtifactNotFoundException
566     {
567         resolve( artifact, remoteRepositories, localRepository, null );
568     }
569 
570     
571 
572 
573     static final class DaemonThreadCreator
574         implements ThreadFactory
575     {
576         static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
577 
578         static final ThreadGroup GROUP = new ThreadGroup( THREADGROUP_NAME );
579 
580         static final AtomicInteger THREAD_NUMBER = new AtomicInteger( 1 );
581 
582         public Thread newThread( Runnable r )
583         {
584             Thread newThread = new Thread( GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement() );
585             newThread.setDaemon( true );
586             newThread.setContextClassLoader( null );
587             return newThread;
588         }
589     }
590 
591     private class ResolveTask
592         implements Runnable
593     {
594 
595         private final ClassLoader classLoader;
596 
597         private final CountDownLatch latch;
598 
599         private final Artifact artifact;
600 
601         private final RepositorySystemSession session;
602 
603         private final List<ArtifactRepository> remoteRepositories;
604 
605         private final ArtifactResolutionResult result;
606 
607         ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact,
608                             RepositorySystemSession session, List<ArtifactRepository> remoteRepositories,
609                             ArtifactResolutionResult result )
610         {
611             this.classLoader = classLoader;
612             this.latch = latch;
613             this.artifact = artifact;
614             this.session = session;
615             this.remoteRepositories = remoteRepositories;
616             this.result = result;
617         }
618 
619         public void run()
620         {
621             ClassLoader old = Thread.currentThread().getContextClassLoader();
622             try
623             {
624                 Thread.currentThread().setContextClassLoader( classLoader );
625                 resolve( artifact, remoteRepositories, session );
626             }
627             catch ( ArtifactNotFoundException anfe )
628             {
629                 
630                 
631 
632                 synchronized ( result )
633                 {
634                     result.addMissingArtifact( artifact );
635                 }
636             }
637             catch ( ArtifactResolutionException e )
638             {
639                 
640                 
641 
642                 synchronized ( result )
643                 {
644                     result.addErrorArtifactException( e );
645                 }
646             }
647             finally
648             {
649                 latch.countDown();
650                 Thread.currentThread().setContextClassLoader( old );
651 
652             }
653         }
654 
655     }
656 
657     @Override
658     public void dispose()
659     {
660         if ( executor instanceof ExecutorService )
661         {
662             ( (ExecutorService) executor ).shutdownNow();
663         }
664     }
665 
666 }