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