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