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