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