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