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 = 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(), repoSystem);
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 result = repoSystem.resolveArtifact(session, artifactRequest);
189 } catch (org.eclipse.aether.resolution.ArtifactResolutionException e) {
190 if (e.getCause() instanceof org.eclipse.aether.transfer.ArtifactNotFoundException) {
191 throw new ArtifactNotFoundException(e.getMessage(), artifact, remoteRepositories, e);
192 } else {
193 throw new ArtifactResolutionException(e.getMessage(), artifact, remoteRepositories, e);
194 }
195 }
196
197 artifact.selectVersion(result.getArtifact().getVersion());
198 artifact.setFile(result.getArtifact().getFile());
199 artifact.setResolved(true);
200
201 if (artifact.isSnapshot()) {
202 Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher(artifact.getVersion());
203 if (matcher.matches()) {
204 Snapshot snapshot = new Snapshot();
205 snapshot.setTimestamp(matcher.group(2));
206 try {
207 snapshot.setBuildNumber(Integer.parseInt(matcher.group(3)));
208 artifact.addMetadata(new SnapshotArtifactRepositoryMetadata(artifact, snapshot));
209 } catch (NumberFormatException e) {
210 logger.warn("Invalid artifact version " + artifact.getVersion() + ": " + e.getMessage());
211 }
212 }
213 }
214 }
215 }
216
217 public ArtifactResolutionResult resolveTransitively(
218 Set<Artifact> artifacts,
219 Artifact originatingArtifact,
220 ArtifactRepository localRepository,
221 List<ArtifactRepository> remoteRepositories,
222 ArtifactMetadataSource source,
223 ArtifactFilter filter)
224 throws ArtifactResolutionException, ArtifactNotFoundException {
225 return resolveTransitively(
226 artifacts,
227 originatingArtifact,
228 Collections.emptyMap(),
229 localRepository,
230 remoteRepositories,
231 source,
232 filter);
233 }
234
235 public ArtifactResolutionResult resolveTransitively(
236 Set<Artifact> artifacts,
237 Artifact originatingArtifact,
238 Map<String, Artifact> managedVersions,
239 ArtifactRepository localRepository,
240 List<ArtifactRepository> remoteRepositories,
241 ArtifactMetadataSource source)
242 throws ArtifactResolutionException, ArtifactNotFoundException {
243 return resolveTransitively(
244 artifacts, originatingArtifact, managedVersions, localRepository, remoteRepositories, source, null);
245 }
246
247 public ArtifactResolutionResult resolveTransitively(
248 Set<Artifact> artifacts,
249 Artifact originatingArtifact,
250 Map<String, Artifact> managedVersions,
251 ArtifactRepository localRepository,
252 List<ArtifactRepository> remoteRepositories,
253 ArtifactMetadataSource source,
254 ArtifactFilter filter)
255 throws ArtifactResolutionException, ArtifactNotFoundException {
256 return resolveTransitively(
257 artifacts,
258 originatingArtifact,
259 managedVersions,
260 localRepository,
261 remoteRepositories,
262 source,
263 filter,
264 null);
265 }
266
267 public ArtifactResolutionResult resolveTransitively(
268 Set<Artifact> artifacts,
269 Artifact originatingArtifact,
270 List<ArtifactRepository> remoteRepositories,
271 ArtifactRepository localRepository,
272 ArtifactMetadataSource source)
273 throws ArtifactResolutionException, ArtifactNotFoundException {
274 return resolveTransitively(artifacts, originatingArtifact, localRepository, remoteRepositories, source, null);
275 }
276
277 public ArtifactResolutionResult resolveTransitively(
278 Set<Artifact> artifacts,
279 Artifact originatingArtifact,
280 List<ArtifactRepository> remoteRepositories,
281 ArtifactRepository localRepository,
282 ArtifactMetadataSource source,
283 List<ResolutionListener> listeners)
284 throws ArtifactResolutionException, ArtifactNotFoundException {
285 return resolveTransitively(
286 artifacts,
287 originatingArtifact,
288 Collections.emptyMap(),
289 localRepository,
290 remoteRepositories,
291 source,
292 null,
293 listeners);
294 }
295
296 @SuppressWarnings("checkstyle:parameternumber")
297 public ArtifactResolutionResult resolveTransitively(
298 Set<Artifact> artifacts,
299 Artifact originatingArtifact,
300 Map<String, Artifact> managedVersions,
301 ArtifactRepository localRepository,
302 List<ArtifactRepository> remoteRepositories,
303 ArtifactMetadataSource source,
304 ArtifactFilter filter,
305 List<ResolutionListener> listeners)
306 throws ArtifactResolutionException, ArtifactNotFoundException {
307 return resolveTransitively(
308 artifacts,
309 originatingArtifact,
310 managedVersions,
311 localRepository,
312 remoteRepositories,
313 source,
314 filter,
315 listeners,
316 null);
317 }
318
319 @SuppressWarnings("checkstyle:parameternumber")
320 public ArtifactResolutionResult resolveTransitively(
321 Set<Artifact> artifacts,
322 Artifact originatingArtifact,
323 Map<String, Artifact> managedVersions,
324 ArtifactRepository localRepository,
325 List<ArtifactRepository> remoteRepositories,
326 ArtifactMetadataSource source,
327 ArtifactFilter filter,
328 List<ResolutionListener> listeners,
329 List<ConflictResolver> conflictResolvers)
330 throws ArtifactResolutionException, ArtifactNotFoundException {
331 ArtifactResolutionRequest request = new ArtifactResolutionRequest()
332 .setArtifact(originatingArtifact)
333 .setResolveRoot(false)
334 .
335
336 setArtifactDependencies(artifacts)
337 .setManagedVersionMap(managedVersions)
338 .setLocalRepository(localRepository)
339 .setRemoteRepositories(remoteRepositories)
340 .setCollectionFilter(filter)
341 .setListeners(listeners);
342
343 injectSession2(request, legacySupport.getSession());
344
345 return resolveWithExceptions(request);
346 }
347
348 public ArtifactResolutionResult resolveWithExceptions(ArtifactResolutionRequest request)
349 throws ArtifactResolutionException, ArtifactNotFoundException {
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 @SuppressWarnings("checkstyle:methodlength")
366 public ArtifactResolutionResult resolve(ArtifactResolutionRequest request) {
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
377 if (source == null) {
378 try {
379 source = container.lookup(ArtifactMetadataSource.class);
380 } catch (ComponentLookupException e) {
381
382 }
383 }
384
385 if (listeners == null) {
386 listeners = new ArrayList<>();
387
388 if (logger.isDebugEnabled()) {
389 listeners.add(new DebugResolutionListener(logger));
390 }
391
392 listeners.add(new WarningResolutionListener(logger));
393 }
394
395 ArtifactResolutionResult result = new ArtifactResolutionResult();
396
397
398
399
400
401
402 if (request.isResolveRoot() ) {
403 try {
404 resolve(rootArtifact, request.getRemoteRepositories(), session);
405 } catch (ArtifactResolutionException e) {
406 result.addErrorArtifactException(e);
407 return result;
408 } catch (ArtifactNotFoundException e) {
409 result.addMissingArtifact(request.getArtifact());
410 return result;
411 }
412 }
413
414 ArtifactResolutionRequest collectionRequest = request;
415
416 if (request.isResolveTransitively()) {
417 MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest(request);
418
419 metadataRequest.setArtifact(rootArtifact);
420 metadataRequest.setResolveManagedVersions(managedVersions == null);
421
422 try {
423 ResolutionGroup resolutionGroup = source.retrieve(metadataRequest);
424
425 if (managedVersions == null) {
426 managedVersions = resolutionGroup.getManagedVersions();
427 }
428
429 Set<Artifact> directArtifacts = resolutionGroup.getArtifacts();
430
431 if (artifacts == null || artifacts.isEmpty()) {
432 artifacts = directArtifacts;
433 } else {
434 List<Artifact> allArtifacts = new ArrayList<>();
435 allArtifacts.addAll(artifacts);
436 allArtifacts.addAll(directArtifacts);
437
438 Map<String, Artifact> mergedArtifacts = new LinkedHashMap<>();
439 for (Artifact artifact : allArtifacts) {
440 String conflictId = artifact.getDependencyConflictId();
441 if (!mergedArtifacts.containsKey(conflictId)) {
442 mergedArtifacts.put(conflictId, artifact);
443 }
444 }
445
446 artifacts = new LinkedHashSet<>(mergedArtifacts.values());
447 }
448
449 collectionRequest = new ArtifactResolutionRequest(request);
450 collectionRequest.setServers(request.getServers());
451 collectionRequest.setMirrors(request.getMirrors());
452 collectionRequest.setProxies(request.getProxies());
453 collectionRequest.setRemoteRepositories(resolutionGroup.getResolutionRepositories());
454 } catch (ArtifactMetadataRetrievalException e) {
455 ArtifactResolutionException are = new ArtifactResolutionException(
456 "Unable to get dependency information for " + rootArtifact.getId() + ": " + e.getMessage(),
457 rootArtifact,
458 metadataRequest.getRemoteRepositories(),
459 e);
460 result.addMetadataResolutionException(are);
461 return result;
462 }
463 }
464
465 if (artifacts == null || artifacts.isEmpty()) {
466 if (request.isResolveRoot()) {
467 result.addArtifact(rootArtifact);
468 }
469 return result;
470 }
471
472
473 result = artifactCollector.collect(
474 artifacts, rootArtifact, managedVersions, collectionRequest, source, collectionFilter, listeners, null);
475
476
477
478
479
480 if (result.hasMetadataResolutionExceptions()
481 || result.hasVersionRangeViolations()
482 || result.hasCircularDependencyExceptions()) {
483 return result;
484 }
485
486 if (result.getArtifactResolutionNodes() != null) {
487 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
488
489 CountDownLatch latch =
490 new CountDownLatch(result.getArtifactResolutionNodes().size());
491
492 for (ResolutionNode node : result.getArtifactResolutionNodes()) {
493 Artifact artifact = node.getArtifact();
494
495 if (resolutionFilter == null || resolutionFilter.include(artifact)) {
496 executor.execute(new ResolveTask(
497 classLoader, latch, artifact, session, node.getRemoteRepositories(), result));
498 } else {
499 latch.countDown();
500 }
501 }
502 try {
503 latch.await();
504 } catch (InterruptedException e) {
505 result.addErrorArtifactException(
506 new ArtifactResolutionException("Resolution interrupted", rootArtifact, e));
507 }
508 }
509
510
511
512 if (request.isResolveRoot()) {
513
514 Set<Artifact> allArtifacts = new LinkedHashSet<>();
515 allArtifacts.add(rootArtifact);
516 allArtifacts.addAll(result.getArtifacts());
517 result.setArtifacts(allArtifacts);
518 }
519
520 return result;
521 }
522
523 public void resolve(
524 Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
525 throws ArtifactResolutionException, ArtifactNotFoundException {
526 resolve(artifact, remoteRepositories, localRepository, null);
527 }
528
529
530
531
532 static final class DaemonThreadCreator implements ThreadFactory {
533 static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
534
535 static final ThreadGroup GROUP = new ThreadGroup(THREADGROUP_NAME);
536
537 static final AtomicInteger THREAD_NUMBER = new AtomicInteger(1);
538
539 public Thread newThread(Runnable r) {
540 Thread newThread = new Thread(GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement());
541 newThread.setDaemon(true);
542 newThread.setContextClassLoader(null);
543 return newThread;
544 }
545 }
546
547 private class ResolveTask implements Runnable {
548
549 private final ClassLoader classLoader;
550
551 private final CountDownLatch latch;
552
553 private final Artifact artifact;
554
555 private final RepositorySystemSession session;
556
557 private final List<ArtifactRepository> remoteRepositories;
558
559 private final ArtifactResolutionResult result;
560
561 ResolveTask(
562 ClassLoader classLoader,
563 CountDownLatch latch,
564 Artifact artifact,
565 RepositorySystemSession session,
566 List<ArtifactRepository> remoteRepositories,
567 ArtifactResolutionResult result) {
568 this.classLoader = classLoader;
569 this.latch = latch;
570 this.artifact = artifact;
571 this.session = session;
572 this.remoteRepositories = remoteRepositories;
573 this.result = result;
574 }
575
576 public void run() {
577 ClassLoader old = Thread.currentThread().getContextClassLoader();
578 try {
579 Thread.currentThread().setContextClassLoader(classLoader);
580 resolve(artifact, remoteRepositories, session);
581 } catch (ArtifactNotFoundException anfe) {
582
583
584
585 synchronized (result) {
586 result.addMissingArtifact(artifact);
587 }
588 } catch (ArtifactResolutionException e) {
589
590
591
592 synchronized (result) {
593 result.addErrorArtifactException(e);
594 }
595 } finally {
596 latch.countDown();
597 Thread.currentThread().setContextClassLoader(old);
598 }
599 }
600 }
601
602 @Override
603 public void dispose() {
604 if (executor instanceof ExecutorService) {
605 ((ExecutorService) executor).shutdownNow();
606 }
607 }
608 }