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