001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023import javax.inject.Singleton; 024 025import java.io.File; 026import java.io.IOException; 027import java.util.ArrayList; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.Iterator; 031import java.util.List; 032import java.util.Map; 033import java.util.concurrent.atomic.AtomicBoolean; 034 035import org.eclipse.aether.RepositoryEvent; 036import org.eclipse.aether.RepositoryEvent.EventType; 037import org.eclipse.aether.RepositorySystemSession; 038import org.eclipse.aether.RequestTrace; 039import org.eclipse.aether.SyncContext; 040import org.eclipse.aether.artifact.Artifact; 041import org.eclipse.aether.artifact.ArtifactProperties; 042import org.eclipse.aether.impl.ArtifactResolver; 043import org.eclipse.aether.impl.OfflineController; 044import org.eclipse.aether.impl.RemoteRepositoryFilterManager; 045import org.eclipse.aether.impl.RemoteRepositoryManager; 046import org.eclipse.aether.impl.RepositoryConnectorProvider; 047import org.eclipse.aether.impl.RepositoryEventDispatcher; 048import org.eclipse.aether.impl.UpdateCheck; 049import org.eclipse.aether.impl.UpdateCheckManager; 050import org.eclipse.aether.impl.VersionResolver; 051import org.eclipse.aether.repository.ArtifactRepository; 052import org.eclipse.aether.repository.LocalArtifactRegistration; 053import org.eclipse.aether.repository.LocalArtifactRequest; 054import org.eclipse.aether.repository.LocalArtifactResult; 055import org.eclipse.aether.repository.LocalRepository; 056import org.eclipse.aether.repository.LocalRepositoryManager; 057import org.eclipse.aether.repository.RemoteRepository; 058import org.eclipse.aether.repository.RepositoryPolicy; 059import org.eclipse.aether.repository.WorkspaceReader; 060import org.eclipse.aether.resolution.ArtifactRequest; 061import org.eclipse.aether.resolution.ArtifactResolutionException; 062import org.eclipse.aether.resolution.ArtifactResult; 063import org.eclipse.aether.resolution.ResolutionErrorPolicy; 064import org.eclipse.aether.resolution.VersionRequest; 065import org.eclipse.aether.resolution.VersionResolutionException; 066import org.eclipse.aether.resolution.VersionResult; 067import org.eclipse.aether.spi.connector.ArtifactDownload; 068import org.eclipse.aether.spi.connector.RepositoryConnector; 069import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter; 070import org.eclipse.aether.spi.io.FileProcessor; 071import org.eclipse.aether.spi.locator.Service; 072import org.eclipse.aether.spi.locator.ServiceLocator; 073import org.eclipse.aether.spi.resolution.ArtifactResolverPostProcessor; 074import org.eclipse.aether.spi.synccontext.SyncContextFactory; 075import org.eclipse.aether.transfer.ArtifactFilteredOutException; 076import org.eclipse.aether.transfer.ArtifactNotFoundException; 077import org.eclipse.aether.transfer.ArtifactTransferException; 078import org.eclipse.aether.transfer.NoRepositoryConnectorException; 079import org.eclipse.aether.transfer.RepositoryOfflineException; 080import org.eclipse.aether.util.ConfigUtils; 081import org.slf4j.Logger; 082import org.slf4j.LoggerFactory; 083 084import static java.util.Objects.requireNonNull; 085 086/** 087 * 088 */ 089@Singleton 090@Named 091public class DefaultArtifactResolver implements ArtifactResolver, Service { 092 093 /** 094 * Configuration to enable "snapshot normalization", downloaded snapshots from remote with timestamped file names 095 * will have file names converted back to baseVersion. Default: {@code true}. 096 */ 097 private static final String CONFIG_PROP_SNAPSHOT_NORMALIZATION = "aether.artifactResolver.snapshotNormalization"; 098 099 /** 100 * Configuration to enable "interoperability" with Simple LRM, but this breaks RRF feature, hence this configuration 101 * is IGNORED when RRF is used, and is warmly recommended to leave it disabled even if no RRF is being used. 102 * Default: {@code false}. 103 */ 104 private static final String CONFIG_PROP_SIMPLE_LRM_INTEROP = "aether.artifactResolver.simpleLrmInterop"; 105 106 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultArtifactResolver.class); 107 108 private FileProcessor fileProcessor; 109 110 private RepositoryEventDispatcher repositoryEventDispatcher; 111 112 private VersionResolver versionResolver; 113 114 private UpdateCheckManager updateCheckManager; 115 116 private RepositoryConnectorProvider repositoryConnectorProvider; 117 118 private RemoteRepositoryManager remoteRepositoryManager; 119 120 private SyncContextFactory syncContextFactory; 121 122 private OfflineController offlineController; 123 124 private Map<String, ArtifactResolverPostProcessor> artifactResolverPostProcessors; 125 126 private RemoteRepositoryFilterManager remoteRepositoryFilterManager; 127 128 @Deprecated 129 public DefaultArtifactResolver() { 130 // enables default constructor 131 } 132 133 @SuppressWarnings("checkstyle:parameternumber") 134 @Inject 135 public DefaultArtifactResolver( 136 FileProcessor fileProcessor, 137 RepositoryEventDispatcher repositoryEventDispatcher, 138 VersionResolver versionResolver, 139 UpdateCheckManager updateCheckManager, 140 RepositoryConnectorProvider repositoryConnectorProvider, 141 RemoteRepositoryManager remoteRepositoryManager, 142 SyncContextFactory syncContextFactory, 143 OfflineController offlineController, 144 Map<String, ArtifactResolverPostProcessor> artifactResolverPostProcessors, 145 RemoteRepositoryFilterManager remoteRepositoryFilterManager) { 146 setFileProcessor(fileProcessor); 147 setRepositoryEventDispatcher(repositoryEventDispatcher); 148 setVersionResolver(versionResolver); 149 setUpdateCheckManager(updateCheckManager); 150 setRepositoryConnectorProvider(repositoryConnectorProvider); 151 setRemoteRepositoryManager(remoteRepositoryManager); 152 setSyncContextFactory(syncContextFactory); 153 setOfflineController(offlineController); 154 setArtifactResolverPostProcessors(artifactResolverPostProcessors); 155 setRemoteRepositoryFilterManager(remoteRepositoryFilterManager); 156 } 157 158 public void initService(ServiceLocator locator) { 159 setFileProcessor(locator.getService(FileProcessor.class)); 160 setRepositoryEventDispatcher(locator.getService(RepositoryEventDispatcher.class)); 161 setVersionResolver(locator.getService(VersionResolver.class)); 162 setUpdateCheckManager(locator.getService(UpdateCheckManager.class)); 163 setRepositoryConnectorProvider(locator.getService(RepositoryConnectorProvider.class)); 164 setRemoteRepositoryManager(locator.getService(RemoteRepositoryManager.class)); 165 setSyncContextFactory(locator.getService(SyncContextFactory.class)); 166 setOfflineController(locator.getService(OfflineController.class)); 167 setArtifactResolverPostProcessors(Collections.emptyMap()); 168 setRemoteRepositoryFilterManager(locator.getService(RemoteRepositoryFilterManager.class)); 169 } 170 171 /** 172 * @deprecated not used any more since MRESOLVER-36 move to slf4j, added back in MRESOLVER-64 for compatibility 173 */ 174 @Deprecated 175 public DefaultArtifactResolver setLoggerFactory(org.eclipse.aether.spi.log.LoggerFactory loggerFactory) { 176 // this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); 177 return this; 178 } 179 180 public DefaultArtifactResolver setFileProcessor(FileProcessor fileProcessor) { 181 this.fileProcessor = requireNonNull(fileProcessor, "file processor cannot be null"); 182 return this; 183 } 184 185 public DefaultArtifactResolver setRepositoryEventDispatcher(RepositoryEventDispatcher repositoryEventDispatcher) { 186 this.repositoryEventDispatcher = 187 requireNonNull(repositoryEventDispatcher, "repository event dispatcher cannot be null"); 188 return this; 189 } 190 191 public DefaultArtifactResolver setVersionResolver(VersionResolver versionResolver) { 192 this.versionResolver = requireNonNull(versionResolver, "version resolver cannot be null"); 193 return this; 194 } 195 196 public DefaultArtifactResolver setUpdateCheckManager(UpdateCheckManager updateCheckManager) { 197 this.updateCheckManager = requireNonNull(updateCheckManager, "update check manager cannot be null"); 198 return this; 199 } 200 201 public DefaultArtifactResolver setRepositoryConnectorProvider( 202 RepositoryConnectorProvider repositoryConnectorProvider) { 203 this.repositoryConnectorProvider = 204 requireNonNull(repositoryConnectorProvider, "repository connector provider cannot be null"); 205 return this; 206 } 207 208 public DefaultArtifactResolver setRemoteRepositoryManager(RemoteRepositoryManager remoteRepositoryManager) { 209 this.remoteRepositoryManager = 210 requireNonNull(remoteRepositoryManager, "remote repository provider cannot be null"); 211 return this; 212 } 213 214 public DefaultArtifactResolver setSyncContextFactory(SyncContextFactory syncContextFactory) { 215 this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null"); 216 return this; 217 } 218 219 public DefaultArtifactResolver setOfflineController(OfflineController offlineController) { 220 this.offlineController = requireNonNull(offlineController, "offline controller cannot be null"); 221 return this; 222 } 223 224 public DefaultArtifactResolver setArtifactResolverPostProcessors( 225 Map<String, ArtifactResolverPostProcessor> artifactResolverPostProcessors) { 226 this.artifactResolverPostProcessors = 227 requireNonNull(artifactResolverPostProcessors, "artifact resolver post-processors cannot be null"); 228 return this; 229 } 230 231 public DefaultArtifactResolver setRemoteRepositoryFilterManager( 232 RemoteRepositoryFilterManager remoteRepositoryFilterManager) { 233 this.remoteRepositoryFilterManager = 234 requireNonNull(remoteRepositoryFilterManager, "remote repository filter manager cannot be null"); 235 return this; 236 } 237 238 public ArtifactResult resolveArtifact(RepositorySystemSession session, ArtifactRequest request) 239 throws ArtifactResolutionException { 240 requireNonNull(session, "session cannot be null"); 241 requireNonNull(request, "request cannot be null"); 242 243 return resolveArtifacts(session, Collections.singleton(request)).get(0); 244 } 245 246 public List<ArtifactResult> resolveArtifacts( 247 RepositorySystemSession session, Collection<? extends ArtifactRequest> requests) 248 throws ArtifactResolutionException { 249 requireNonNull(session, "session cannot be null"); 250 requireNonNull(requests, "requests cannot be null"); 251 try (SyncContext shared = syncContextFactory.newInstance(session, true); 252 SyncContext exclusive = syncContextFactory.newInstance(session, false)) { 253 Collection<Artifact> artifacts = new ArrayList<>(requests.size()); 254 for (ArtifactRequest request : requests) { 255 if (request.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) { 256 continue; 257 } 258 artifacts.add(request.getArtifact()); 259 } 260 261 return resolve(shared, exclusive, artifacts, session, requests); 262 } 263 } 264 265 @SuppressWarnings("checkstyle:methodlength") 266 private List<ArtifactResult> resolve( 267 SyncContext shared, 268 SyncContext exclusive, 269 Collection<Artifact> subjects, 270 RepositorySystemSession session, 271 Collection<? extends ArtifactRequest> requests) 272 throws ArtifactResolutionException { 273 SyncContext current = shared; 274 try { 275 while (true) { 276 current.acquire(subjects, null); 277 278 boolean failures = false; 279 final List<ArtifactResult> results = new ArrayList<>(requests.size()); 280 final boolean simpleLrmInterop = ConfigUtils.getBoolean(session, false, CONFIG_PROP_SIMPLE_LRM_INTEROP); 281 final LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 282 final WorkspaceReader workspace = session.getWorkspaceReader(); 283 final List<ResolutionGroup> groups = new ArrayList<>(); 284 // filter != null: means "filtering applied", if null no filtering applied (behave as before) 285 final RemoteRepositoryFilter filter = remoteRepositoryFilterManager.getRemoteRepositoryFilter(session); 286 287 for (ArtifactRequest request : requests) { 288 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request); 289 290 ArtifactResult result = new ArtifactResult(request); 291 results.add(result); 292 293 Artifact artifact = request.getArtifact(); 294 295 if (current == shared) { 296 artifactResolving(session, trace, artifact); 297 } 298 299 String localPath = artifact.getProperty(ArtifactProperties.LOCAL_PATH, null); 300 if (localPath != null) { 301 // unhosted artifact, just validate file 302 File file = new File(localPath); 303 if (!file.isFile()) { 304 failures = true; 305 result.addException(new ArtifactNotFoundException(artifact, null)); 306 } else { 307 artifact = artifact.setFile(file); 308 result.setArtifact(artifact); 309 artifactResolved(session, trace, artifact, null, result.getExceptions()); 310 } 311 continue; 312 } 313 314 List<RemoteRepository> remoteRepositories = request.getRepositories(); 315 List<RemoteRepository> filteredRemoteRepositories = new ArrayList<>(remoteRepositories); 316 if (filter != null) { 317 for (RemoteRepository repository : remoteRepositories) { 318 RemoteRepositoryFilter.Result filterResult = filter.acceptArtifact(repository, artifact); 319 if (!filterResult.isAccepted()) { 320 result.addException(new ArtifactFilteredOutException( 321 artifact, repository, filterResult.reasoning())); 322 filteredRemoteRepositories.remove(repository); 323 } 324 } 325 } 326 327 VersionResult versionResult; 328 try { 329 VersionRequest versionRequest = 330 new VersionRequest(artifact, filteredRemoteRepositories, request.getRequestContext()); 331 versionRequest.setTrace(trace); 332 versionResult = versionResolver.resolveVersion(session, versionRequest); 333 } catch (VersionResolutionException e) { 334 result.addException(e); 335 continue; 336 } 337 338 artifact = artifact.setVersion(versionResult.getVersion()); 339 340 if (versionResult.getRepository() != null) { 341 if (versionResult.getRepository() instanceof RemoteRepository) { 342 filteredRemoteRepositories = 343 Collections.singletonList((RemoteRepository) versionResult.getRepository()); 344 } else { 345 filteredRemoteRepositories = Collections.emptyList(); 346 } 347 } 348 349 if (workspace != null) { 350 File file = workspace.findArtifact(artifact); 351 if (file != null) { 352 artifact = artifact.setFile(file); 353 result.setArtifact(artifact); 354 result.setRepository(workspace.getRepository()); 355 artifactResolved(session, trace, artifact, result.getRepository(), null); 356 continue; 357 } 358 } 359 360 LocalArtifactResult local = lrm.find( 361 session, 362 new LocalArtifactRequest( 363 artifact, filteredRemoteRepositories, request.getRequestContext())); 364 result.setLocalArtifactResult(local); 365 boolean found = (filter != null && local.isAvailable()) 366 || (filter == null && isLocallyInstalled(local, versionResult)); 367 // with filtering: availability drives the logic 368 // without filtering: simply presence of file drives the logic 369 // "interop" logic with simple LRM leads to RRF breakage: hence is ignored when filtering in effect 370 if (found) { 371 if (local.getRepository() != null) { 372 result.setRepository(local.getRepository()); 373 } else { 374 result.setRepository(lrm.getRepository()); 375 } 376 377 try { 378 artifact = artifact.setFile(getFile(session, artifact, local.getFile())); 379 result.setArtifact(artifact); 380 artifactResolved(session, trace, artifact, result.getRepository(), null); 381 } catch (ArtifactTransferException e) { 382 result.addException(e); 383 } 384 if (filter == null && simpleLrmInterop && !local.isAvailable()) { 385 /* 386 * NOTE: Interop with simple local repository: An artifact installed by a simple local repo 387 * manager will not show up in the repository tracking file of the enhanced local repository. 388 * If however the maven-metadata-local.xml tells us the artifact was installed locally, we 389 * sync the repository tracking file. 390 */ 391 lrm.add(session, new LocalArtifactRegistration(artifact)); 392 } 393 394 continue; 395 } 396 397 if (local.getFile() != null) { 398 LOGGER.info( 399 "Artifact {} is present in the local repository, but cached from a remote repository ID that is unavailable in current build context, verifying that is downloadable from {}", 400 artifact, 401 remoteRepositories); 402 } 403 404 LOGGER.debug("Resolving artifact {} from {}", artifact, remoteRepositories); 405 AtomicBoolean resolved = new AtomicBoolean(false); 406 Iterator<ResolutionGroup> groupIt = groups.iterator(); 407 for (RemoteRepository repo : filteredRemoteRepositories) { 408 if (!repo.getPolicy(artifact.isSnapshot()).isEnabled()) { 409 continue; 410 } 411 412 try { 413 Utils.checkOffline(session, offlineController, repo); 414 } catch (RepositoryOfflineException e) { 415 Exception exception = new ArtifactNotFoundException( 416 artifact, 417 repo, 418 "Cannot access " + repo.getId() + " (" 419 + repo.getUrl() + ") in offline mode and the artifact " + artifact 420 + " has not been downloaded from it before.", 421 e); 422 result.addException(exception); 423 continue; 424 } 425 426 ResolutionGroup group = null; 427 while (groupIt.hasNext()) { 428 ResolutionGroup t = groupIt.next(); 429 if (t.matches(repo)) { 430 group = t; 431 break; 432 } 433 } 434 if (group == null) { 435 group = new ResolutionGroup(repo); 436 groups.add(group); 437 groupIt = Collections.emptyIterator(); 438 } 439 group.items.add(new ResolutionItem(trace, artifact, resolved, result, local, repo)); 440 } 441 } 442 443 if (!groups.isEmpty() && current == shared) { 444 current.close(); 445 current = exclusive; 446 continue; 447 } 448 449 for (ResolutionGroup group : groups) { 450 performDownloads(session, group); 451 } 452 453 for (ArtifactResolverPostProcessor artifactResolverPostProcessor : 454 artifactResolverPostProcessors.values()) { 455 artifactResolverPostProcessor.postProcess(session, results); 456 } 457 458 for (ArtifactResult result : results) { 459 ArtifactRequest request = result.getRequest(); 460 461 Artifact artifact = result.getArtifact(); 462 if (artifact == null || artifact.getFile() == null) { 463 failures = true; 464 if (result.getExceptions().isEmpty()) { 465 Exception exception = new ArtifactNotFoundException(request.getArtifact(), null); 466 result.addException(exception); 467 } 468 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request); 469 artifactResolved(session, trace, request.getArtifact(), null, result.getExceptions()); 470 } 471 } 472 473 if (failures) { 474 throw new ArtifactResolutionException(results); 475 } 476 477 return results; 478 } 479 } finally { 480 current.close(); 481 } 482 } 483 484 /** 485 * This is the method that checks local artifact result if no RRF being used. Unlike with RRF, where only 486 * {@link LocalArtifactResult#isAvailable()} is checked, here we perform multiple checks: 487 * <ul> 488 * <li>if {@link LocalArtifactResult#isAvailable()} is {@code true}, return {@code true}</li> 489 * <li>if {@link LocalArtifactResult#getRepository()} is instance of {@link LocalRepository}, return {@code true}</li> 490 * <li>if {@link LocalArtifactResult#getRepository()} is {@code null} and request had zero remote repositories set, return {@code true}</li> 491 * </ul> 492 * Note: the third check is interfering with RRF, as RRF may make list of remote repositories empty, that was 493 * originally non-empty, by eliminating remote repositories to consider. 494 * Hence, we may use this method ONLY if RRF is inactive. 495 */ 496 private boolean isLocallyInstalled(LocalArtifactResult lar, VersionResult vr) { 497 if (lar.isAvailable()) { 498 return true; 499 } 500 if (lar.getFile() != null) { 501 if (vr.getRepository() instanceof LocalRepository) { 502 // resolution of (snapshot) version found locally installed artifact 503 return true; 504 } else if (vr.getRepository() == null 505 && lar.getRequest().getRepositories().isEmpty()) { 506 // resolution of version range found locally installed artifact 507 return true; 508 } 509 } 510 return false; 511 } 512 513 private File getFile(RepositorySystemSession session, Artifact artifact, File file) 514 throws ArtifactTransferException { 515 if (artifact.isSnapshot() 516 && !artifact.getVersion().equals(artifact.getBaseVersion()) 517 && ConfigUtils.getBoolean(session, true, CONFIG_PROP_SNAPSHOT_NORMALIZATION)) { 518 String name = file.getName().replace(artifact.getVersion(), artifact.getBaseVersion()); 519 File dst = new File(file.getParent(), name); 520 521 boolean copy = dst.length() != file.length() || dst.lastModified() != file.lastModified(); 522 if (copy) { 523 try { 524 fileProcessor.copy(file, dst); 525 dst.setLastModified(file.lastModified()); 526 } catch (IOException e) { 527 throw new ArtifactTransferException(artifact, null, e); 528 } 529 } 530 531 file = dst; 532 } 533 534 return file; 535 } 536 537 private void performDownloads(RepositorySystemSession session, ResolutionGroup group) { 538 List<ArtifactDownload> downloads = gatherDownloads(session, group); 539 if (downloads.isEmpty()) { 540 return; 541 } 542 543 for (ArtifactDownload download : downloads) { 544 artifactDownloading(session, download.getTrace(), download.getArtifact(), group.repository); 545 } 546 547 try { 548 try (RepositoryConnector connector = 549 repositoryConnectorProvider.newRepositoryConnector(session, group.repository)) { 550 connector.get(downloads, null); 551 } 552 } catch (NoRepositoryConnectorException e) { 553 for (ArtifactDownload download : downloads) { 554 download.setException(new ArtifactTransferException(download.getArtifact(), group.repository, e)); 555 } 556 } 557 558 evaluateDownloads(session, group); 559 } 560 561 private List<ArtifactDownload> gatherDownloads(RepositorySystemSession session, ResolutionGroup group) { 562 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 563 List<ArtifactDownload> downloads = new ArrayList<>(); 564 565 for (ResolutionItem item : group.items) { 566 Artifact artifact = item.artifact; 567 568 if (item.resolved.get()) { 569 // resolved in previous resolution group 570 continue; 571 } 572 573 ArtifactDownload download = new ArtifactDownload(); 574 download.setArtifact(artifact); 575 download.setRequestContext(item.request.getRequestContext()); 576 download.setListener(SafeTransferListener.wrap(session)); 577 download.setTrace(item.trace); 578 if (item.local.getFile() != null) { 579 download.setFile(item.local.getFile()); 580 download.setExistenceCheck(true); 581 } else { 582 String path = 583 lrm.getPathForRemoteArtifact(artifact, group.repository, item.request.getRequestContext()); 584 download.setFile(new File(lrm.getRepository().getBasedir(), path)); 585 } 586 587 boolean snapshot = artifact.isSnapshot(); 588 RepositoryPolicy policy = remoteRepositoryManager.getPolicy(session, group.repository, !snapshot, snapshot); 589 590 int errorPolicy = Utils.getPolicy(session, artifact, group.repository); 591 if ((errorPolicy & ResolutionErrorPolicy.CACHE_ALL) != 0) { 592 UpdateCheck<Artifact, ArtifactTransferException> check = new UpdateCheck<>(); 593 check.setItem(artifact); 594 check.setFile(download.getFile()); 595 check.setFileValid(false); 596 check.setRepository(group.repository); 597 check.setPolicy(policy.getUpdatePolicy()); 598 item.updateCheck = check; 599 updateCheckManager.checkArtifact(session, check); 600 if (!check.isRequired()) { 601 item.result.addException(check.getException()); 602 continue; 603 } 604 } 605 606 download.setChecksumPolicy(policy.getChecksumPolicy()); 607 download.setRepositories(item.repository.getMirroredRepositories()); 608 downloads.add(download); 609 item.download = download; 610 } 611 612 return downloads; 613 } 614 615 private void evaluateDownloads(RepositorySystemSession session, ResolutionGroup group) { 616 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 617 618 for (ResolutionItem item : group.items) { 619 ArtifactDownload download = item.download; 620 if (download == null) { 621 continue; 622 } 623 624 Artifact artifact = download.getArtifact(); 625 if (download.getException() == null) { 626 item.resolved.set(true); 627 item.result.setRepository(group.repository); 628 try { 629 artifact = artifact.setFile(getFile(session, artifact, download.getFile())); 630 item.result.setArtifact(artifact); 631 632 lrm.add( 633 session, 634 new LocalArtifactRegistration(artifact, group.repository, download.getSupportedContexts())); 635 } catch (ArtifactTransferException e) { 636 download.setException(e); 637 item.result.addException(e); 638 } 639 } else { 640 item.result.addException(download.getException()); 641 } 642 643 /* 644 * NOTE: Touch after registration with local repo to ensure concurrent resolution is not rejected with 645 * "already updated" via session data when actual update to local repo is still pending. 646 */ 647 if (item.updateCheck != null) { 648 item.updateCheck.setException(download.getException()); 649 updateCheckManager.touchArtifact(session, item.updateCheck); 650 } 651 652 artifactDownloaded(session, download.getTrace(), artifact, group.repository, download.getException()); 653 if (download.getException() == null) { 654 artifactResolved(session, download.getTrace(), artifact, group.repository, null); 655 } 656 } 657 } 658 659 private void artifactResolving(RepositorySystemSession session, RequestTrace trace, Artifact artifact) { 660 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_RESOLVING); 661 event.setTrace(trace); 662 event.setArtifact(artifact); 663 664 repositoryEventDispatcher.dispatch(event.build()); 665 } 666 667 private void artifactResolved( 668 RepositorySystemSession session, 669 RequestTrace trace, 670 Artifact artifact, 671 ArtifactRepository repository, 672 List<Exception> exceptions) { 673 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_RESOLVED); 674 event.setTrace(trace); 675 event.setArtifact(artifact); 676 event.setRepository(repository); 677 event.setExceptions(exceptions); 678 if (artifact != null) { 679 event.setFile(artifact.getFile()); 680 } 681 682 repositoryEventDispatcher.dispatch(event.build()); 683 } 684 685 private void artifactDownloading( 686 RepositorySystemSession session, RequestTrace trace, Artifact artifact, RemoteRepository repository) { 687 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DOWNLOADING); 688 event.setTrace(trace); 689 event.setArtifact(artifact); 690 event.setRepository(repository); 691 692 repositoryEventDispatcher.dispatch(event.build()); 693 } 694 695 private void artifactDownloaded( 696 RepositorySystemSession session, 697 RequestTrace trace, 698 Artifact artifact, 699 RemoteRepository repository, 700 Exception exception) { 701 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DOWNLOADED); 702 event.setTrace(trace); 703 event.setArtifact(artifact); 704 event.setRepository(repository); 705 event.setException(exception); 706 if (artifact != null) { 707 event.setFile(artifact.getFile()); 708 } 709 710 repositoryEventDispatcher.dispatch(event.build()); 711 } 712 713 static class ResolutionGroup { 714 715 final RemoteRepository repository; 716 717 final List<ResolutionItem> items = new ArrayList<>(); 718 719 ResolutionGroup(RemoteRepository repository) { 720 this.repository = repository; 721 } 722 723 boolean matches(RemoteRepository repo) { 724 return repository.getUrl().equals(repo.getUrl()) 725 && repository.getContentType().equals(repo.getContentType()) 726 && repository.isRepositoryManager() == repo.isRepositoryManager(); 727 } 728 } 729 730 static class ResolutionItem { 731 732 final RequestTrace trace; 733 734 final ArtifactRequest request; 735 736 final ArtifactResult result; 737 738 final LocalArtifactResult local; 739 740 final RemoteRepository repository; 741 742 final Artifact artifact; 743 744 final AtomicBoolean resolved; 745 746 ArtifactDownload download; 747 748 UpdateCheck<Artifact, ArtifactTransferException> updateCheck; 749 750 ResolutionItem( 751 RequestTrace trace, 752 Artifact artifact, 753 AtomicBoolean resolved, 754 ArtifactResult result, 755 LocalArtifactResult local, 756 RemoteRepository repository) { 757 this.trace = trace; 758 this.artifact = artifact; 759 this.resolved = resolved; 760 this.result = result; 761 this.request = result.getRequest(); 762 this.local = local; 763 this.repository = repository; 764 } 765 } 766}