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