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.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.List; 030import java.util.Map; 031import java.util.Objects; 032import java.util.concurrent.atomic.AtomicBoolean; 033import java.util.concurrent.atomic.AtomicInteger; 034import java.util.function.Consumer; 035import java.util.stream.Collectors; 036 037import org.eclipse.aether.ConfigurationProperties; 038import org.eclipse.aether.RepositorySystem; 039import org.eclipse.aether.RepositorySystemSession; 040import org.eclipse.aether.RequestTrace; 041import org.eclipse.aether.SyncContext; 042import org.eclipse.aether.artifact.Artifact; 043import org.eclipse.aether.collection.CollectRequest; 044import org.eclipse.aether.collection.CollectResult; 045import org.eclipse.aether.collection.DependencyCollectionException; 046import org.eclipse.aether.deployment.DeployRequest; 047import org.eclipse.aether.deployment.DeployResult; 048import org.eclipse.aether.deployment.DeploymentException; 049import org.eclipse.aether.graph.DependencyFilter; 050import org.eclipse.aether.graph.DependencyNode; 051import org.eclipse.aether.graph.DependencyVisitor; 052import org.eclipse.aether.impl.ArtifactDescriptorReader; 053import org.eclipse.aether.impl.ArtifactResolver; 054import org.eclipse.aether.impl.DependencyCollector; 055import org.eclipse.aether.impl.Deployer; 056import org.eclipse.aether.impl.Installer; 057import org.eclipse.aether.impl.LocalRepositoryProvider; 058import org.eclipse.aether.impl.MetadataResolver; 059import org.eclipse.aether.impl.RemoteRepositoryManager; 060import org.eclipse.aether.impl.RepositorySystemLifecycle; 061import org.eclipse.aether.impl.RepositorySystemValidator; 062import org.eclipse.aether.impl.VersionRangeResolver; 063import org.eclipse.aether.impl.VersionResolver; 064import org.eclipse.aether.installation.InstallRequest; 065import org.eclipse.aether.installation.InstallResult; 066import org.eclipse.aether.installation.InstallationException; 067import org.eclipse.aether.internal.impl.session.DefaultSessionBuilder; 068import org.eclipse.aether.repository.Authentication; 069import org.eclipse.aether.repository.LocalRepository; 070import org.eclipse.aether.repository.LocalRepositoryManager; 071import org.eclipse.aether.repository.NoLocalRepositoryManagerException; 072import org.eclipse.aether.repository.Proxy; 073import org.eclipse.aether.repository.RemoteRepository; 074import org.eclipse.aether.resolution.ArtifactDescriptorException; 075import org.eclipse.aether.resolution.ArtifactDescriptorRequest; 076import org.eclipse.aether.resolution.ArtifactDescriptorResult; 077import org.eclipse.aether.resolution.ArtifactRequest; 078import org.eclipse.aether.resolution.ArtifactResolutionException; 079import org.eclipse.aether.resolution.ArtifactResult; 080import org.eclipse.aether.resolution.DependencyRequest; 081import org.eclipse.aether.resolution.DependencyResolutionException; 082import org.eclipse.aether.resolution.DependencyResult; 083import org.eclipse.aether.resolution.MetadataRequest; 084import org.eclipse.aether.resolution.MetadataResult; 085import org.eclipse.aether.resolution.VersionRangeRequest; 086import org.eclipse.aether.resolution.VersionRangeResolutionException; 087import org.eclipse.aether.resolution.VersionRangeResult; 088import org.eclipse.aether.resolution.VersionRequest; 089import org.eclipse.aether.resolution.VersionResolutionException; 090import org.eclipse.aether.resolution.VersionResult; 091import org.eclipse.aether.spi.artifact.decorator.ArtifactDecorator; 092import org.eclipse.aether.spi.artifact.decorator.ArtifactDecoratorFactory; 093import org.eclipse.aether.spi.synccontext.SyncContextFactory; 094import org.eclipse.aether.util.ConfigUtils; 095import org.eclipse.aether.util.graph.visitor.LevelOrderDependencyNodeConsumerVisitor; 096import org.eclipse.aether.util.graph.visitor.PostorderDependencyNodeConsumerVisitor; 097import org.eclipse.aether.util.graph.visitor.PreorderDependencyNodeConsumerVisitor; 098import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager; 099 100import static java.util.Objects.requireNonNull; 101import static java.util.stream.Collectors.toList; 102 103/** 104 * 105 */ 106@Singleton 107@Named 108public class DefaultRepositorySystem implements RepositorySystem { 109 /** 110 * Sentinel object placed into the {@link RequestTrace} chain by each public method 111 * to detect re-entrant calls into this {@code RepositorySystem}. 112 * <p> 113 * The resolver's architecture assumes that internal components ({@code ArtifactResolver}, 114 * {@code DependencyCollector}, {@code ArtifactDescriptorReader}, etc.) call each other 115 * directly via the internal API in {@code org.eclipse.aether.impl}, never going through 116 * the public {@code RepositorySystem} facade. This means session validation, request 117 * validation, and artifact decoration only need to run once — on the outermost call. 118 * <p> 119 * However, some {@code RepositorySystem} consumers (notably Maven 4's 120 * {@code ArtifactDescriptorReader} → {@code ModelBuilder} → {@code ModelResolver} chain) 121 * re-enter {@code RepositorySystem} during an ongoing operation. Without this guard, 122 * every re-entrant call redundantly validates the session, validates the request (which 123 * may reject intermediate state like uninterpolated expressions from transitive POMs), 124 * and applies artifact decorators. This causes both correctness issues (false validation 125 * failures) and unnecessary performance overhead. 126 * <p> 127 * Re-entrancy can happen on the <em>same</em> thread (e.g. {@code collectDependencies} 128 * → {@code readArtifactDescriptor} → model builder → model resolver → {@code resolveVersionRange}) 129 * or on a <em>different</em> thread when the resolver uses internal parallelism (e.g. 130 * {@code BfDependencyCollector}'s {@code SmartExecutor} dispatches descriptor resolution 131 * to pool threads, which then re-enter {@code RepositorySystem} via the model resolver). 132 * <p> 133 * To handle both cases, we leverage the {@link RequestTrace} chain that is already 134 * propagated across threads by the caller (e.g. Maven's model builder explicitly copies 135 * traces to pool threads). On the outermost call, we stamp this marker into the request's 136 * trace. On re-entry — whether on the same thread or a pool thread — the marker is found 137 * in the trace ancestry, so validation and decoration are skipped. 138 */ 139 private static final Object REPOSITORY_SYSTEM_CALL = new Object() { 140 @Override 141 public String toString() { 142 return "RepositorySystem"; 143 } 144 }; 145 146 private final AtomicBoolean shutdown; 147 148 private final AtomicInteger sessionIdCounter; 149 150 private final VersionResolver versionResolver; 151 152 private final VersionRangeResolver versionRangeResolver; 153 154 private final ArtifactResolver artifactResolver; 155 156 private final MetadataResolver metadataResolver; 157 158 private final ArtifactDescriptorReader artifactDescriptorReader; 159 160 private final DependencyCollector dependencyCollector; 161 162 private final Installer installer; 163 164 private final Deployer deployer; 165 166 private final LocalRepositoryProvider localRepositoryProvider; 167 168 private final SyncContextFactory syncContextFactory; 169 170 private final RemoteRepositoryManager remoteRepositoryManager; 171 172 private final RepositorySystemLifecycle repositorySystemLifecycle; 173 174 private final Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories; 175 176 private final RepositorySystemValidator repositorySystemValidator; 177 178 @SuppressWarnings("checkstyle:parameternumber") 179 @Inject 180 public DefaultRepositorySystem( 181 VersionResolver versionResolver, 182 VersionRangeResolver versionRangeResolver, 183 ArtifactResolver artifactResolver, 184 MetadataResolver metadataResolver, 185 ArtifactDescriptorReader artifactDescriptorReader, 186 DependencyCollector dependencyCollector, 187 Installer installer, 188 Deployer deployer, 189 LocalRepositoryProvider localRepositoryProvider, 190 SyncContextFactory syncContextFactory, 191 RemoteRepositoryManager remoteRepositoryManager, 192 RepositorySystemLifecycle repositorySystemLifecycle, 193 Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories, 194 RepositorySystemValidator repositorySystemValidator) { 195 this.shutdown = new AtomicBoolean(false); 196 this.sessionIdCounter = new AtomicInteger(0); 197 this.versionResolver = requireNonNull(versionResolver, "version resolver cannot be null"); 198 this.versionRangeResolver = requireNonNull(versionRangeResolver, "version range resolver cannot be null"); 199 this.artifactResolver = requireNonNull(artifactResolver, "artifact resolver cannot be null"); 200 this.metadataResolver = requireNonNull(metadataResolver, "metadata resolver cannot be null"); 201 this.artifactDescriptorReader = 202 requireNonNull(artifactDescriptorReader, "artifact descriptor reader cannot be null"); 203 this.dependencyCollector = requireNonNull(dependencyCollector, "dependency collector cannot be null"); 204 this.installer = requireNonNull(installer, "installer cannot be null"); 205 this.deployer = requireNonNull(deployer, "deployer cannot be null"); 206 this.localRepositoryProvider = 207 requireNonNull(localRepositoryProvider, "local repository provider cannot be null"); 208 this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null"); 209 this.remoteRepositoryManager = 210 requireNonNull(remoteRepositoryManager, "remote repository provider cannot be null"); 211 this.repositorySystemLifecycle = 212 requireNonNull(repositorySystemLifecycle, "repository system lifecycle cannot be null"); 213 this.artifactDecoratorFactories = 214 requireNonNull(artifactDecoratorFactories, "artifact decorator factories cannot be null"); 215 this.repositorySystemValidator = 216 requireNonNull(repositorySystemValidator, "repository system validator cannot be null"); 217 } 218 219 @Override 220 public VersionResult resolveVersion(RepositorySystemSession session, VersionRequest request) 221 throws VersionResolutionException { 222 requireNonNull(request, "request cannot be null"); 223 if (!isReentrant(request.getTrace())) { 224 validateSession(session); 225 repositorySystemValidator.validateVersionRequest(session, request); 226 request.setTrace(stampReentrancyMarker(request.getTrace())); 227 } 228 return versionResolver.resolveVersion(session, request); 229 } 230 231 @Override 232 public VersionRangeResult resolveVersionRange(RepositorySystemSession session, VersionRangeRequest request) 233 throws VersionRangeResolutionException { 234 requireNonNull(request, "request cannot be null"); 235 if (!isReentrant(request.getTrace())) { 236 validateSession(session); 237 repositorySystemValidator.validateVersionRangeRequest(session, request); 238 request.setTrace(stampReentrancyMarker(request.getTrace())); 239 } 240 return versionRangeResolver.resolveVersionRange(session, request); 241 } 242 243 @Override 244 public ArtifactDescriptorResult readArtifactDescriptor( 245 RepositorySystemSession session, ArtifactDescriptorRequest request) throws ArtifactDescriptorException { 246 requireNonNull(request, "request cannot be null"); 247 boolean outermost = !isReentrant(request.getTrace()); 248 if (outermost) { 249 validateSession(session); 250 repositorySystemValidator.validateArtifactDescriptorRequest(session, request); 251 request.setTrace(stampReentrancyMarker(request.getTrace())); 252 } 253 ArtifactDescriptorResult descriptorResult = artifactDescriptorReader.readArtifactDescriptor(session, request); 254 if (outermost) { 255 for (ArtifactDecorator decorator : Utils.getArtifactDecorators(session, artifactDecoratorFactories)) { 256 descriptorResult.setArtifact(decorator.decorateArtifact(descriptorResult)); 257 } 258 } 259 return descriptorResult; 260 } 261 262 @Override 263 public ArtifactResult resolveArtifact(RepositorySystemSession session, ArtifactRequest request) 264 throws ArtifactResolutionException { 265 requireNonNull(request, "request cannot be null"); 266 if (!isReentrant(request.getTrace())) { 267 validateSession(session); 268 repositorySystemValidator.validateArtifactRequests(session, Collections.singleton(request)); 269 request.setTrace(stampReentrancyMarker(request.getTrace())); 270 } 271 return artifactResolver.resolveArtifact(session, request); 272 } 273 274 @Override 275 public List<ArtifactResult> resolveArtifacts( 276 RepositorySystemSession session, Collection<? extends ArtifactRequest> requests) 277 throws ArtifactResolutionException { 278 requireNonNull(requests, "requests cannot be null"); 279 // All requests in a batch share the same trace context, so checking any one is sufficient. 280 RequestTrace firstTrace = requests.stream() 281 .map(ArtifactRequest::getTrace) 282 .filter(Objects::nonNull) 283 .findFirst() 284 .orElse(null); 285 if (!isReentrant(firstTrace)) { 286 validateSession(session); 287 repositorySystemValidator.validateArtifactRequests(session, requests); 288 for (ArtifactRequest request : requests) { 289 request.setTrace(stampReentrancyMarker(request.getTrace())); 290 } 291 } 292 return artifactResolver.resolveArtifacts(session, requests); 293 } 294 295 @Override 296 public List<MetadataResult> resolveMetadata( 297 RepositorySystemSession session, Collection<? extends MetadataRequest> requests) { 298 requireNonNull(requests, "requests cannot be null"); 299 // All requests in a batch share the same trace context, so checking any one is sufficient. 300 RequestTrace firstTrace = requests.stream() 301 .map(MetadataRequest::getTrace) 302 .filter(Objects::nonNull) 303 .findFirst() 304 .orElse(null); 305 if (!isReentrant(firstTrace)) { 306 validateSession(session); 307 repositorySystemValidator.validateMetadataRequests(session, requests); 308 for (MetadataRequest request : requests) { 309 request.setTrace(stampReentrancyMarker(request.getTrace())); 310 } 311 } 312 return metadataResolver.resolveMetadata(session, requests); 313 } 314 315 @Override 316 public CollectResult collectDependencies(RepositorySystemSession session, CollectRequest request) 317 throws DependencyCollectionException { 318 requireNonNull(request, "request cannot be null"); 319 if (!isReentrant(request.getTrace())) { 320 validateSession(session); 321 repositorySystemValidator.validateCollectRequest(session, request); 322 request.setTrace(stampReentrancyMarker(request.getTrace())); 323 } 324 return dependencyCollector.collectDependencies(session, request); 325 } 326 327 @Override 328 public DependencyResult resolveDependencies(RepositorySystemSession session, DependencyRequest request) 329 throws DependencyResolutionException { 330 requireNonNull(request, "request cannot be null"); 331 if (!isReentrant(request.getTrace())) { 332 validateSession(session); 333 repositorySystemValidator.validateDependencyRequest(session, request); 334 request.setTrace(stampReentrancyMarker(request.getTrace())); 335 } 336 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request); 337 338 DependencyResult result = new DependencyResult(request); 339 340 DependencyCollectionException dce = null; 341 ArtifactResolutionException are = null; 342 343 if (request.getRoot() != null) { 344 result.setRoot(request.getRoot()); 345 } else if (request.getCollectRequest() != null) { 346 CollectResult collectResult; 347 try { 348 request.getCollectRequest().setTrace(trace); 349 collectResult = dependencyCollector.collectDependencies(session, request.getCollectRequest()); 350 } catch (DependencyCollectionException e) { 351 dce = e; 352 collectResult = e.getResult(); 353 } 354 result.setRoot(collectResult.getRoot()); 355 result.setCycles(collectResult.getCycles()); 356 result.setCollectExceptions(collectResult.getExceptions()); 357 } else { 358 throw new NullPointerException("dependency node and collect request cannot be null"); 359 } 360 361 final List<DependencyNode> dependencyNodes = 362 doFlattenDependencyNodes(session, result.getRoot(), request.getFilter()); 363 364 final List<ArtifactRequest> requests = dependencyNodes.stream() 365 .map(n -> { 366 if (n.getDependency() != null) { 367 ArtifactRequest artifactRequest = new ArtifactRequest(n); 368 artifactRequest.setTrace(trace); 369 return artifactRequest; 370 } else { 371 return null; 372 } 373 }) 374 .filter(Objects::nonNull) 375 .collect(Collectors.toList()); 376 List<ArtifactResult> results; 377 try { 378 results = artifactResolver.resolveArtifacts(session, requests); 379 } catch (ArtifactResolutionException e) { 380 are = e; 381 results = e.getResults(); 382 } 383 result.setDependencyNodeResults(dependencyNodes); 384 result.setArtifactResults(results); 385 386 updateNodesWithResolvedArtifacts(results); 387 388 if (dce != null) { 389 throw new DependencyResolutionException(result, dce); 390 } else if (are != null) { 391 throw new DependencyResolutionException(result, are); 392 } 393 394 return result; 395 } 396 397 @Override 398 public List<DependencyNode> flattenDependencyNodes( 399 RepositorySystemSession session, DependencyNode root, DependencyFilter dependencyFilter) { 400 validateSession(session); 401 requireNonNull(root, "root cannot be null"); 402 return doFlattenDependencyNodes(session, root, dependencyFilter); 403 } 404 405 private List<DependencyNode> doFlattenDependencyNodes( 406 RepositorySystemSession session, DependencyNode root, DependencyFilter dependencyFilter) { 407 final ArrayList<DependencyNode> dependencyNodes = new ArrayList<>(); 408 if (root != null) { 409 root.accept(getDependencyVisitor(session, dependencyNodes::add, dependencyFilter)); 410 } 411 return dependencyNodes; 412 } 413 414 private DependencyVisitor getDependencyVisitor( 415 RepositorySystemSession session, Consumer<DependencyNode> nodeConsumer, DependencyFilter dependencyFilter) { 416 String strategy = ConfigUtils.getString( 417 session, 418 ConfigurationProperties.DEFAULT_REPOSITORY_SYSTEM_DEPENDENCY_VISITOR, 419 ConfigurationProperties.REPOSITORY_SYSTEM_DEPENDENCY_VISITOR); 420 switch (strategy) { 421 case PreorderDependencyNodeConsumerVisitor.NAME: 422 return new PreorderDependencyNodeConsumerVisitor(nodeConsumer, dependencyFilter); 423 case PostorderDependencyNodeConsumerVisitor.NAME: 424 return new PostorderDependencyNodeConsumerVisitor(nodeConsumer, dependencyFilter); 425 case LevelOrderDependencyNodeConsumerVisitor.NAME: 426 return new LevelOrderDependencyNodeConsumerVisitor(nodeConsumer, dependencyFilter); 427 default: 428 throw new IllegalArgumentException("Invalid dependency visitor strategy: " + strategy); 429 } 430 } 431 432 private void updateNodesWithResolvedArtifacts(List<ArtifactResult> results) { 433 for (ArtifactResult result : results) { 434 Artifact artifact = result.getArtifact(); 435 if (artifact != null) { 436 result.getRequest().getDependencyNode().setArtifact(artifact); 437 } 438 } 439 } 440 441 @Override 442 public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException { 443 validateSession(session); 444 requireNonNull(request, "request cannot be null"); 445 repositorySystemValidator.validateInstallRequest(session, request); 446 return installer.install(session, request); 447 } 448 449 @Override 450 public DeployResult deploy(RepositorySystemSession session, DeployRequest request) throws DeploymentException { 451 validateSession(session); 452 requireNonNull(request, "request cannot be null"); 453 repositorySystemValidator.validateDeployRequest(session, request); 454 return deployer.deploy(session, request); 455 } 456 457 @Override 458 public LocalRepositoryManager newLocalRepositoryManager( 459 RepositorySystemSession session, LocalRepository localRepository) { 460 requireNonNull(session, "session cannot be null"); 461 requireNonNull(localRepository, "localRepository cannot be null"); 462 validateSystem(); 463 repositorySystemValidator.validateLocalRepositories(session, Collections.singleton(localRepository)); 464 return createLocalRepositoryManager(session, localRepository); 465 } 466 467 @Override 468 public LocalRepositoryManager newLocalRepositoryManager( 469 RepositorySystemSession session, LocalRepository... localRepositories) { 470 requireNonNull(session, "session cannot be null"); 471 requireNonNull(localRepositories, "localRepositories cannot be null"); 472 validateSystem(); 473 repositorySystemValidator.validateLocalRepositories(session, Arrays.asList(localRepositories)); 474 return createLocalRepositoryManager(session, Arrays.asList(localRepositories)); 475 } 476 477 @Override 478 public LocalRepositoryManager newLocalRepositoryManager( 479 RepositorySystemSession session, List<LocalRepository> localRepositories) { 480 requireNonNull(session, "session cannot be null"); 481 requireNonNull(localRepositories, "localRepositories cannot be null"); 482 validateSystem(); 483 repositorySystemValidator.validateLocalRepositories(session, localRepositories); 484 return createLocalRepositoryManager(session, localRepositories); 485 } 486 487 private LocalRepositoryManager createLocalRepositoryManager( 488 RepositorySystemSession session, List<LocalRepository> localRepositories) { 489 if (localRepositories.isEmpty()) { 490 throw new IllegalArgumentException("empty localRepositories"); 491 } else if (localRepositories.size() == 1) { 492 return createLocalRepositoryManager(session, localRepositories.get(0)); 493 } else { 494 LocalRepositoryManager head = createLocalRepositoryManager(session, localRepositories.get(0)); 495 List<LocalRepositoryManager> tail = localRepositories.subList(1, localRepositories.size()).stream() 496 .map(l -> createLocalRepositoryManager(session, l)) 497 .collect(toList()); 498 return new ChainedLocalRepositoryManager(head, tail, session); 499 } 500 } 501 502 private LocalRepositoryManager createLocalRepositoryManager( 503 RepositorySystemSession session, LocalRepository localRepository) { 504 try { 505 return localRepositoryProvider.newLocalRepositoryManager(session, localRepository); 506 } catch (NoLocalRepositoryManagerException e) { 507 throw new IllegalArgumentException(e.getMessage(), e); 508 } 509 } 510 511 @Override 512 public SyncContext newSyncContext(RepositorySystemSession session, boolean shared) { 513 validateSession(session); 514 return syncContextFactory.newInstance(session, shared); 515 } 516 517 @Override 518 public List<RemoteRepository> newResolutionRepositories( 519 RepositorySystemSession session, List<RemoteRepository> repositories) { 520 validateSession(session); 521 validateRepositories(repositories); 522 repositorySystemValidator.validateRemoteRepositories(session, repositories); 523 return remoteRepositoryManager.aggregateRepositories(session, new ArrayList<>(), repositories, true); 524 } 525 526 @Override 527 public RemoteRepository newDeploymentRepository(RepositorySystemSession session, RemoteRepository repository) { 528 validateSession(session); 529 requireNonNull(repository, "repository cannot be null"); 530 repositorySystemValidator.validateRemoteRepositories(session, Collections.singletonList(repository)); 531 Authentication auth = session.getAuthenticationSelector().getAuthentication(repository); 532 Proxy proxy = session.getProxySelector().getProxy(repository); 533 return new RemoteRepository.Builder(repository) 534 .setAuthentication(auth) 535 .setProxy(proxy) 536 .setIntent(RemoteRepository.Intent.DEPLOYMENT) 537 .build(); 538 } 539 540 @Override 541 public void addOnSystemEndedHandler(Runnable handler) { 542 validateSystem(); 543 repositorySystemLifecycle.addOnSystemEndedHandler(handler); 544 } 545 546 @Override 547 public RepositorySystemSession.SessionBuilder createSessionBuilder() { 548 validateSystem(); 549 return new DefaultSessionBuilder( 550 this, repositorySystemLifecycle, () -> "id-" + sessionIdCounter.incrementAndGet()); 551 } 552 553 @Override 554 public void shutdown() { 555 if (shutdown.compareAndSet(false, true)) { 556 repositorySystemLifecycle.systemEnded(); 557 } 558 } 559 560 /** 561 * Stamps the {@link #REPOSITORY_SYSTEM_CALL} re-entrancy marker into the trace chain 562 * while preserving the original trace tip data. The marker is inserted <em>below</em> 563 * the tip so that code walking the trace and casting {@code getData()} to its expected 564 * type (e.g. {@code org.apache.maven.artifact.Artifact}) still finds the original data 565 * at the tip rather than the anonymous marker object. 566 * 567 * @param currentTrace the current request trace (may be {@code null}) 568 * @return a new trace with the marker inserted and original tip data preserved 569 */ 570 private static RequestTrace stampReentrancyMarker(RequestTrace currentTrace) { 571 RequestTrace markerTrace = RequestTrace.newChild(currentTrace, REPOSITORY_SYSTEM_CALL); 572 return currentTrace != null ? RequestTrace.newChild(markerTrace, currentTrace.getData()) : markerTrace; 573 } 574 575 /** 576 * Checks whether the given {@link RequestTrace} indicates a re-entrant call by looking 577 * for the {@link #REPOSITORY_SYSTEM_CALL} marker in the trace ancestry. 578 * 579 * @return {@code true} if the marker is found (re-entrant call), {@code false} otherwise 580 */ 581 private static boolean isReentrant(RequestTrace trace) { 582 for (RequestTrace t = trace; t != null; t = t.getParent()) { 583 if (t.getData() == REPOSITORY_SYSTEM_CALL) { 584 return true; 585 } 586 } 587 return false; 588 } 589 590 private void validateSession(RepositorySystemSession session) { 591 requireNonNull(session, "repository system session cannot be null"); 592 invalidSession(session.getLocalRepositoryManager(), "local repository manager"); 593 invalidSession(session.getSystemProperties(), "system properties"); 594 invalidSession(session.getUserProperties(), "user properties"); 595 invalidSession(session.getConfigProperties(), "config properties"); 596 invalidSession(session.getMirrorSelector(), "mirror selector"); 597 invalidSession(session.getProxySelector(), "proxy selector"); 598 invalidSession(session.getAuthenticationSelector(), "authentication selector"); 599 invalidSession(session.getArtifactTypeRegistry(), "artifact type registry"); 600 invalidSession(session.getData(), "data"); 601 validateSystem(); 602 } 603 604 private void validateSystem() { 605 if (shutdown.get()) { 606 throw new IllegalStateException("repository system is already shut down"); 607 } 608 } 609 610 private void validateRepositories(List<RemoteRepository> repositories) { 611 requireNonNull(repositories, "repositories cannot be null"); 612 for (RemoteRepository repository : repositories) { 613 requireNonNull(repository, "repository cannot be null"); 614 } 615 } 616 617 private void invalidSession(Object obj, String name) { 618 requireNonNull(obj, "repository system session's " + name + " cannot be null"); 619 } 620}