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