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