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