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 public DefaultArtifactResolver() { 129 // enables default constructor 130 } 131 132 @SuppressWarnings("checkstyle:parameternumber") 133 @Inject 134 DefaultArtifactResolver( 135 FileProcessor fileProcessor, 136 RepositoryEventDispatcher repositoryEventDispatcher, 137 VersionResolver versionResolver, 138 UpdateCheckManager updateCheckManager, 139 RepositoryConnectorProvider repositoryConnectorProvider, 140 RemoteRepositoryManager remoteRepositoryManager, 141 SyncContextFactory syncContextFactory, 142 OfflineController offlineController, 143 Map<String, ArtifactResolverPostProcessor> artifactResolverPostProcessors, 144 RemoteRepositoryFilterManager remoteRepositoryFilterManager) { 145 setFileProcessor(fileProcessor); 146 setRepositoryEventDispatcher(repositoryEventDispatcher); 147 setVersionResolver(versionResolver); 148 setUpdateCheckManager(updateCheckManager); 149 setRepositoryConnectorProvider(repositoryConnectorProvider); 150 setRemoteRepositoryManager(remoteRepositoryManager); 151 setSyncContextFactory(syncContextFactory); 152 setOfflineController(offlineController); 153 setArtifactResolverPostProcessors(artifactResolverPostProcessors); 154 setRemoteRepositoryFilterManager(remoteRepositoryFilterManager); 155 } 156 157 public void initService(ServiceLocator locator) { 158 setFileProcessor(locator.getService(FileProcessor.class)); 159 setRepositoryEventDispatcher(locator.getService(RepositoryEventDispatcher.class)); 160 setVersionResolver(locator.getService(VersionResolver.class)); 161 setUpdateCheckManager(locator.getService(UpdateCheckManager.class)); 162 setRepositoryConnectorProvider(locator.getService(RepositoryConnectorProvider.class)); 163 setRemoteRepositoryManager(locator.getService(RemoteRepositoryManager.class)); 164 setSyncContextFactory(locator.getService(SyncContextFactory.class)); 165 setOfflineController(locator.getService(OfflineController.class)); 166 setArtifactResolverPostProcessors(Collections.emptyMap()); 167 setRemoteRepositoryFilterManager(locator.getService(RemoteRepositoryFilterManager.class)); 168 } 169 170 /** 171 * @deprecated not used any more since MRESOLVER-36 move to slf4j, added back in MRESOLVER-64 for compatibility 172 */ 173 @Deprecated 174 public DefaultArtifactResolver setLoggerFactory(org.eclipse.aether.spi.log.LoggerFactory loggerFactory) { 175 // this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); 176 return this; 177 } 178 179 public DefaultArtifactResolver setFileProcessor(FileProcessor fileProcessor) { 180 this.fileProcessor = requireNonNull(fileProcessor, "file processor cannot be null"); 181 return this; 182 } 183 184 public DefaultArtifactResolver setRepositoryEventDispatcher(RepositoryEventDispatcher repositoryEventDispatcher) { 185 this.repositoryEventDispatcher = 186 requireNonNull(repositoryEventDispatcher, "repository event dispatcher cannot be null"); 187 return this; 188 } 189 190 public DefaultArtifactResolver setVersionResolver(VersionResolver versionResolver) { 191 this.versionResolver = requireNonNull(versionResolver, "version resolver cannot be null"); 192 return this; 193 } 194 195 public DefaultArtifactResolver setUpdateCheckManager(UpdateCheckManager updateCheckManager) { 196 this.updateCheckManager = requireNonNull(updateCheckManager, "update check manager cannot be null"); 197 return this; 198 } 199 200 public DefaultArtifactResolver setRepositoryConnectorProvider( 201 RepositoryConnectorProvider repositoryConnectorProvider) { 202 this.repositoryConnectorProvider = 203 requireNonNull(repositoryConnectorProvider, "repository connector provider cannot be null"); 204 return this; 205 } 206 207 public DefaultArtifactResolver setRemoteRepositoryManager(RemoteRepositoryManager remoteRepositoryManager) { 208 this.remoteRepositoryManager = 209 requireNonNull(remoteRepositoryManager, "remote repository provider cannot be null"); 210 return this; 211 } 212 213 public DefaultArtifactResolver setSyncContextFactory(SyncContextFactory syncContextFactory) { 214 this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null"); 215 return this; 216 } 217 218 public DefaultArtifactResolver setOfflineController(OfflineController offlineController) { 219 this.offlineController = requireNonNull(offlineController, "offline controller cannot be null"); 220 return this; 221 } 222 223 public DefaultArtifactResolver setArtifactResolverPostProcessors( 224 Map<String, ArtifactResolverPostProcessor> artifactResolverPostProcessors) { 225 this.artifactResolverPostProcessors = 226 requireNonNull(artifactResolverPostProcessors, "artifact resolver post-processors cannot be null"); 227 return this; 228 } 229 230 public DefaultArtifactResolver setRemoteRepositoryFilterManager( 231 RemoteRepositoryFilterManager remoteRepositoryFilterManager) { 232 this.remoteRepositoryFilterManager = 233 requireNonNull(remoteRepositoryFilterManager, "remote repository filter manager cannot be null"); 234 return this; 235 } 236 237 public ArtifactResult resolveArtifact(RepositorySystemSession session, ArtifactRequest request) 238 throws ArtifactResolutionException { 239 requireNonNull(session, "session cannot be null"); 240 requireNonNull(request, "request cannot be null"); 241 242 return resolveArtifacts(session, Collections.singleton(request)).get(0); 243 } 244 245 public List<ArtifactResult> resolveArtifacts( 246 RepositorySystemSession session, Collection<? extends ArtifactRequest> requests) 247 throws ArtifactResolutionException { 248 requireNonNull(session, "session cannot be null"); 249 requireNonNull(requests, "requests cannot be null"); 250 try (SyncContext shared = syncContextFactory.newInstance(session, true); 251 SyncContext exclusive = syncContextFactory.newInstance(session, false)) { 252 Collection<Artifact> artifacts = new ArrayList<>(requests.size()); 253 for (ArtifactRequest request : requests) { 254 if (request.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) { 255 continue; 256 } 257 artifacts.add(request.getArtifact()); 258 } 259 260 return resolve(shared, exclusive, artifacts, session, requests); 261 } 262 } 263 264 @SuppressWarnings("checkstyle:methodlength") 265 private List<ArtifactResult> resolve( 266 SyncContext shared, 267 SyncContext exclusive, 268 Collection<Artifact> subjects, 269 RepositorySystemSession session, 270 Collection<? extends ArtifactRequest> requests) 271 throws ArtifactResolutionException { 272 SyncContext current = shared; 273 try { 274 while (true) { 275 current.acquire(subjects, null); 276 277 boolean failures = false; 278 final List<ArtifactResult> results = new ArrayList<>(requests.size()); 279 final boolean simpleLrmInterop = ConfigUtils.getBoolean(session, false, CONFIG_PROP_SIMPLE_LRM_INTEROP); 280 final LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 281 final WorkspaceReader workspace = session.getWorkspaceReader(); 282 final List<ResolutionGroup> groups = new ArrayList<>(); 283 // filter != null: means "filtering applied", if null no filtering applied (behave as before) 284 final RemoteRepositoryFilter filter = remoteRepositoryFilterManager.getRemoteRepositoryFilter(session); 285 286 for (ArtifactRequest request : requests) { 287 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request); 288 289 ArtifactResult result = new ArtifactResult(request); 290 results.add(result); 291 292 Artifact artifact = request.getArtifact(); 293 294 if (current == shared) { 295 artifactResolving(session, trace, artifact); 296 } 297 298 String localPath = artifact.getProperty(ArtifactProperties.LOCAL_PATH, null); 299 if (localPath != null) { 300 // unhosted artifact, just validate file 301 File file = new File(localPath); 302 if (!file.isFile()) { 303 failures = true; 304 result.addException(new ArtifactNotFoundException(artifact, null)); 305 } else { 306 artifact = artifact.setFile(file); 307 result.setArtifact(artifact); 308 artifactResolved(session, trace, artifact, null, result.getExceptions()); 309 } 310 continue; 311 } 312 313 List<RemoteRepository> remoteRepositories = request.getRepositories(); 314 List<RemoteRepository> filteredRemoteRepositories = new ArrayList<>(remoteRepositories); 315 if (filter != null) { 316 for (RemoteRepository repository : remoteRepositories) { 317 RemoteRepositoryFilter.Result filterResult = filter.acceptArtifact(repository, artifact); 318 if (!filterResult.isAccepted()) { 319 result.addException(new ArtifactFilteredOutException( 320 artifact, repository, filterResult.reasoning())); 321 filteredRemoteRepositories.remove(repository); 322 } 323 } 324 } 325 326 VersionResult versionResult; 327 try { 328 VersionRequest versionRequest = 329 new VersionRequest(artifact, filteredRemoteRepositories, request.getRequestContext()); 330 versionRequest.setTrace(trace); 331 versionResult = versionResolver.resolveVersion(session, versionRequest); 332 } catch (VersionResolutionException e) { 333 result.addException(e); 334 continue; 335 } 336 337 artifact = artifact.setVersion(versionResult.getVersion()); 338 339 if (versionResult.getRepository() != null) { 340 if (versionResult.getRepository() instanceof RemoteRepository) { 341 filteredRemoteRepositories = 342 Collections.singletonList((RemoteRepository) versionResult.getRepository()); 343 } else { 344 filteredRemoteRepositories = Collections.emptyList(); 345 } 346 } 347 348 if (workspace != null) { 349 File file = workspace.findArtifact(artifact); 350 if (file != null) { 351 artifact = artifact.setFile(file); 352 result.setArtifact(artifact); 353 result.setRepository(workspace.getRepository()); 354 artifactResolved(session, trace, artifact, result.getRepository(), null); 355 continue; 356 } 357 } 358 359 LocalArtifactResult local = lrm.find( 360 session, 361 new LocalArtifactRequest( 362 artifact, filteredRemoteRepositories, request.getRequestContext())); 363 result.setLocalArtifactResult(local); 364 boolean found = (filter != null && local.isAvailable()) || isLocallyInstalled(local, versionResult); 365 // with filtering it is availability that drives logic 366 // without filtering it is simply presence of file that drives the logic 367 // "interop" logic with simple LRM leads to RRF breakage: hence is ignored when filtering in effect 368 if (found) { 369 if (local.getRepository() != null) { 370 result.setRepository(local.getRepository()); 371 } else { 372 result.setRepository(lrm.getRepository()); 373 } 374 375 try { 376 artifact = artifact.setFile(getFile(session, artifact, local.getFile())); 377 result.setArtifact(artifact); 378 artifactResolved(session, trace, artifact, result.getRepository(), null); 379 } catch (ArtifactTransferException e) { 380 result.addException(e); 381 } 382 if (filter == null && simpleLrmInterop && !local.isAvailable()) { 383 /* 384 * NOTE: Interop with simple local repository: An artifact installed by a simple local repo 385 * manager will not show up in the repository tracking file of the enhanced local repository. 386 * If however the maven-metadata-local.xml tells us the artifact was installed locally, we 387 * sync the repository tracking file. 388 */ 389 lrm.add(session, new LocalArtifactRegistration(artifact)); 390 } 391 392 continue; 393 } 394 395 if (local.getFile() != null) { 396 LOGGER.info( 397 "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 {}", 398 artifact, 399 remoteRepositories); 400 } 401 402 LOGGER.debug("Resolving artifact {} from {}", artifact, remoteRepositories); 403 AtomicBoolean resolved = new AtomicBoolean(false); 404 Iterator<ResolutionGroup> groupIt = groups.iterator(); 405 for (RemoteRepository repo : filteredRemoteRepositories) { 406 if (!repo.getPolicy(artifact.isSnapshot()).isEnabled()) { 407 continue; 408 } 409 410 try { 411 Utils.checkOffline(session, offlineController, repo); 412 } catch (RepositoryOfflineException e) { 413 Exception exception = new ArtifactNotFoundException( 414 artifact, 415 repo, 416 "Cannot access " + repo.getId() + " (" 417 + repo.getUrl() + ") in offline mode and the artifact " + artifact 418 + " has not been downloaded from it before.", 419 e); 420 result.addException(exception); 421 continue; 422 } 423 424 ResolutionGroup group = null; 425 while (groupIt.hasNext()) { 426 ResolutionGroup t = groupIt.next(); 427 if (t.matches(repo)) { 428 group = t; 429 break; 430 } 431 } 432 if (group == null) { 433 group = new ResolutionGroup(repo); 434 groups.add(group); 435 groupIt = Collections.emptyIterator(); 436 } 437 group.items.add(new ResolutionItem(trace, artifact, resolved, result, local, repo)); 438 } 439 } 440 441 if (!groups.isEmpty() && current == shared) { 442 current.close(); 443 current = exclusive; 444 continue; 445 } 446 447 for (ResolutionGroup group : groups) { 448 performDownloads(session, group); 449 } 450 451 for (ArtifactResolverPostProcessor artifactResolverPostProcessor : 452 artifactResolverPostProcessors.values()) { 453 artifactResolverPostProcessor.postProcess(session, results); 454 } 455 456 for (ArtifactResult result : results) { 457 ArtifactRequest request = result.getRequest(); 458 459 Artifact artifact = result.getArtifact(); 460 if (artifact == null || artifact.getFile() == null) { 461 failures = true; 462 if (result.getExceptions().isEmpty()) { 463 Exception exception = new ArtifactNotFoundException(request.getArtifact(), null); 464 result.addException(exception); 465 } 466 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request); 467 artifactResolved(session, trace, request.getArtifact(), null, result.getExceptions()); 468 } 469 } 470 471 if (failures) { 472 throw new ArtifactResolutionException(results); 473 } 474 475 return results; 476 } 477 } finally { 478 current.close(); 479 } 480 } 481 482 private boolean isLocallyInstalled(LocalArtifactResult lar, VersionResult vr) { 483 if (lar.isAvailable()) { 484 return true; 485 } 486 if (lar.getFile() != null) { 487 if (vr.getRepository() instanceof LocalRepository) { 488 // resolution of (snapshot) version found locally installed artifact 489 return true; 490 } else if (vr.getRepository() == null 491 && lar.getRequest().getRepositories().isEmpty()) { 492 // resolution of version range found locally installed artifact 493 return true; 494 } 495 } 496 return false; 497 } 498 499 private File getFile(RepositorySystemSession session, Artifact artifact, File file) 500 throws ArtifactTransferException { 501 if (artifact.isSnapshot() 502 && !artifact.getVersion().equals(artifact.getBaseVersion()) 503 && ConfigUtils.getBoolean(session, true, CONFIG_PROP_SNAPSHOT_NORMALIZATION)) { 504 String name = file.getName().replace(artifact.getVersion(), artifact.getBaseVersion()); 505 File dst = new File(file.getParent(), name); 506 507 boolean copy = dst.length() != file.length() || dst.lastModified() != file.lastModified(); 508 if (copy) { 509 try { 510 fileProcessor.copy(file, dst); 511 dst.setLastModified(file.lastModified()); 512 } catch (IOException e) { 513 throw new ArtifactTransferException(artifact, null, e); 514 } 515 } 516 517 file = dst; 518 } 519 520 return file; 521 } 522 523 private void performDownloads(RepositorySystemSession session, ResolutionGroup group) { 524 List<ArtifactDownload> downloads = gatherDownloads(session, group); 525 if (downloads.isEmpty()) { 526 return; 527 } 528 529 for (ArtifactDownload download : downloads) { 530 artifactDownloading(session, download.getTrace(), download.getArtifact(), group.repository); 531 } 532 533 try { 534 try (RepositoryConnector connector = 535 repositoryConnectorProvider.newRepositoryConnector(session, group.repository)) { 536 connector.get(downloads, null); 537 } 538 } catch (NoRepositoryConnectorException e) { 539 for (ArtifactDownload download : downloads) { 540 download.setException(new ArtifactTransferException(download.getArtifact(), group.repository, e)); 541 } 542 } 543 544 evaluateDownloads(session, group); 545 } 546 547 private List<ArtifactDownload> gatherDownloads(RepositorySystemSession session, ResolutionGroup group) { 548 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 549 List<ArtifactDownload> downloads = new ArrayList<>(); 550 551 for (ResolutionItem item : group.items) { 552 Artifact artifact = item.artifact; 553 554 if (item.resolved.get()) { 555 // resolved in previous resolution group 556 continue; 557 } 558 559 ArtifactDownload download = new ArtifactDownload(); 560 download.setArtifact(artifact); 561 download.setRequestContext(item.request.getRequestContext()); 562 download.setListener(SafeTransferListener.wrap(session)); 563 download.setTrace(item.trace); 564 if (item.local.getFile() != null) { 565 download.setFile(item.local.getFile()); 566 download.setExistenceCheck(true); 567 } else { 568 String path = 569 lrm.getPathForRemoteArtifact(artifact, group.repository, item.request.getRequestContext()); 570 download.setFile(new File(lrm.getRepository().getBasedir(), path)); 571 } 572 573 boolean snapshot = artifact.isSnapshot(); 574 RepositoryPolicy policy = remoteRepositoryManager.getPolicy(session, group.repository, !snapshot, snapshot); 575 576 int errorPolicy = Utils.getPolicy(session, artifact, group.repository); 577 if ((errorPolicy & ResolutionErrorPolicy.CACHE_ALL) != 0) { 578 UpdateCheck<Artifact, ArtifactTransferException> check = new UpdateCheck<>(); 579 check.setItem(artifact); 580 check.setFile(download.getFile()); 581 check.setFileValid(false); 582 check.setRepository(group.repository); 583 check.setPolicy(policy.getUpdatePolicy()); 584 item.updateCheck = check; 585 updateCheckManager.checkArtifact(session, check); 586 if (!check.isRequired()) { 587 item.result.addException(check.getException()); 588 continue; 589 } 590 } 591 592 download.setChecksumPolicy(policy.getChecksumPolicy()); 593 download.setRepositories(item.repository.getMirroredRepositories()); 594 downloads.add(download); 595 item.download = download; 596 } 597 598 return downloads; 599 } 600 601 private void evaluateDownloads(RepositorySystemSession session, ResolutionGroup group) { 602 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 603 604 for (ResolutionItem item : group.items) { 605 ArtifactDownload download = item.download; 606 if (download == null) { 607 continue; 608 } 609 610 Artifact artifact = download.getArtifact(); 611 if (download.getException() == null) { 612 item.resolved.set(true); 613 item.result.setRepository(group.repository); 614 try { 615 artifact = artifact.setFile(getFile(session, artifact, download.getFile())); 616 item.result.setArtifact(artifact); 617 618 lrm.add( 619 session, 620 new LocalArtifactRegistration(artifact, group.repository, download.getSupportedContexts())); 621 } catch (ArtifactTransferException e) { 622 download.setException(e); 623 item.result.addException(e); 624 } 625 } else { 626 item.result.addException(download.getException()); 627 } 628 629 /* 630 * NOTE: Touch after registration with local repo to ensure concurrent resolution is not rejected with 631 * "already updated" via session data when actual update to local repo is still pending. 632 */ 633 if (item.updateCheck != null) { 634 item.updateCheck.setException(download.getException()); 635 updateCheckManager.touchArtifact(session, item.updateCheck); 636 } 637 638 artifactDownloaded(session, download.getTrace(), artifact, group.repository, download.getException()); 639 if (download.getException() == null) { 640 artifactResolved(session, download.getTrace(), artifact, group.repository, null); 641 } 642 } 643 } 644 645 private void artifactResolving(RepositorySystemSession session, RequestTrace trace, Artifact artifact) { 646 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_RESOLVING); 647 event.setTrace(trace); 648 event.setArtifact(artifact); 649 650 repositoryEventDispatcher.dispatch(event.build()); 651 } 652 653 private void artifactResolved( 654 RepositorySystemSession session, 655 RequestTrace trace, 656 Artifact artifact, 657 ArtifactRepository repository, 658 List<Exception> exceptions) { 659 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_RESOLVED); 660 event.setTrace(trace); 661 event.setArtifact(artifact); 662 event.setRepository(repository); 663 event.setExceptions(exceptions); 664 if (artifact != null) { 665 event.setFile(artifact.getFile()); 666 } 667 668 repositoryEventDispatcher.dispatch(event.build()); 669 } 670 671 private void artifactDownloading( 672 RepositorySystemSession session, RequestTrace trace, Artifact artifact, RemoteRepository repository) { 673 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DOWNLOADING); 674 event.setTrace(trace); 675 event.setArtifact(artifact); 676 event.setRepository(repository); 677 678 repositoryEventDispatcher.dispatch(event.build()); 679 } 680 681 private void artifactDownloaded( 682 RepositorySystemSession session, 683 RequestTrace trace, 684 Artifact artifact, 685 RemoteRepository repository, 686 Exception exception) { 687 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DOWNLOADED); 688 event.setTrace(trace); 689 event.setArtifact(artifact); 690 event.setRepository(repository); 691 event.setException(exception); 692 if (artifact != null) { 693 event.setFile(artifact.getFile()); 694 } 695 696 repositoryEventDispatcher.dispatch(event.build()); 697 } 698 699 static class ResolutionGroup { 700 701 final RemoteRepository repository; 702 703 final List<ResolutionItem> items = new ArrayList<>(); 704 705 ResolutionGroup(RemoteRepository repository) { 706 this.repository = repository; 707 } 708 709 boolean matches(RemoteRepository repo) { 710 return repository.getUrl().equals(repo.getUrl()) 711 && repository.getContentType().equals(repo.getContentType()) 712 && repository.isRepositoryManager() == repo.isRepositoryManager(); 713 } 714 } 715 716 static class ResolutionItem { 717 718 final RequestTrace trace; 719 720 final ArtifactRequest request; 721 722 final ArtifactResult result; 723 724 final LocalArtifactResult local; 725 726 final RemoteRepository repository; 727 728 final Artifact artifact; 729 730 final AtomicBoolean resolved; 731 732 ArtifactDownload download; 733 734 UpdateCheck<Artifact, ArtifactTransferException> updateCheck; 735 736 ResolutionItem( 737 RequestTrace trace, 738 Artifact artifact, 739 AtomicBoolean resolved, 740 ArtifactResult result, 741 LocalArtifactResult local, 742 RemoteRepository repository) { 743 this.trace = trace; 744 this.artifact = artifact; 745 this.resolved = resolved; 746 this.result = result; 747 this.request = result.getRequest(); 748 this.local = local; 749 this.repository = repository; 750 } 751 } 752}