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