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.FilteringDependencyVisitor; 096import org.eclipse.aether.util.graph.visitor.LevelOrderDependencyNodeConsumerVisitor; 097import org.eclipse.aether.util.graph.visitor.PostorderDependencyNodeConsumerVisitor; 098import org.eclipse.aether.util.graph.visitor.PreorderDependencyNodeConsumerVisitor; 099import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager; 100 101import static java.util.Objects.requireNonNull; 102import static java.util.stream.Collectors.toList; 103 104/** 105 * 106 */ 107@Singleton 108@Named 109public class DefaultRepositorySystem implements RepositorySystem { 110 private final AtomicBoolean shutdown; 111 112 private final AtomicInteger sessionIdCounter; 113 114 private final VersionResolver versionResolver; 115 116 private final VersionRangeResolver versionRangeResolver; 117 118 private final ArtifactResolver artifactResolver; 119 120 private final MetadataResolver metadataResolver; 121 122 private final ArtifactDescriptorReader artifactDescriptorReader; 123 124 private final DependencyCollector dependencyCollector; 125 126 private final Installer installer; 127 128 private final Deployer deployer; 129 130 private final LocalRepositoryProvider localRepositoryProvider; 131 132 private final SyncContextFactory syncContextFactory; 133 134 private final RemoteRepositoryManager remoteRepositoryManager; 135 136 private final RepositorySystemLifecycle repositorySystemLifecycle; 137 138 private final Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories; 139 140 private final RepositorySystemValidator repositorySystemValidator; 141 142 @SuppressWarnings("checkstyle:parameternumber") 143 @Inject 144 public DefaultRepositorySystem( 145 VersionResolver versionResolver, 146 VersionRangeResolver versionRangeResolver, 147 ArtifactResolver artifactResolver, 148 MetadataResolver metadataResolver, 149 ArtifactDescriptorReader artifactDescriptorReader, 150 DependencyCollector dependencyCollector, 151 Installer installer, 152 Deployer deployer, 153 LocalRepositoryProvider localRepositoryProvider, 154 SyncContextFactory syncContextFactory, 155 RemoteRepositoryManager remoteRepositoryManager, 156 RepositorySystemLifecycle repositorySystemLifecycle, 157 Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories, 158 RepositorySystemValidator repositorySystemValidator) { 159 this.shutdown = new AtomicBoolean(false); 160 this.sessionIdCounter = new AtomicInteger(0); 161 this.versionResolver = requireNonNull(versionResolver, "version resolver cannot be null"); 162 this.versionRangeResolver = requireNonNull(versionRangeResolver, "version range resolver cannot be null"); 163 this.artifactResolver = requireNonNull(artifactResolver, "artifact resolver cannot be null"); 164 this.metadataResolver = requireNonNull(metadataResolver, "metadata resolver cannot be null"); 165 this.artifactDescriptorReader = 166 requireNonNull(artifactDescriptorReader, "artifact descriptor reader cannot be null"); 167 this.dependencyCollector = requireNonNull(dependencyCollector, "dependency collector cannot be null"); 168 this.installer = requireNonNull(installer, "installer cannot be null"); 169 this.deployer = requireNonNull(deployer, "deployer cannot be null"); 170 this.localRepositoryProvider = 171 requireNonNull(localRepositoryProvider, "local repository provider cannot be null"); 172 this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null"); 173 this.remoteRepositoryManager = 174 requireNonNull(remoteRepositoryManager, "remote repository provider cannot be null"); 175 this.repositorySystemLifecycle = 176 requireNonNull(repositorySystemLifecycle, "repository system lifecycle cannot be null"); 177 this.artifactDecoratorFactories = 178 requireNonNull(artifactDecoratorFactories, "artifact decorator factories cannot be null"); 179 this.repositorySystemValidator = 180 requireNonNull(repositorySystemValidator, "repository system validator cannot be null"); 181 } 182 183 @Override 184 public VersionResult resolveVersion(RepositorySystemSession session, VersionRequest request) 185 throws VersionResolutionException { 186 validateSession(session); 187 requireNonNull(request, "request cannot be null"); 188 repositorySystemValidator.validateVersionRequest(session, request); 189 return versionResolver.resolveVersion(session, request); 190 } 191 192 @Override 193 public VersionRangeResult resolveVersionRange(RepositorySystemSession session, VersionRangeRequest request) 194 throws VersionRangeResolutionException { 195 validateSession(session); 196 requireNonNull(request, "request cannot be null"); 197 repositorySystemValidator.validateVersionRangeRequest(session, request); 198 return versionRangeResolver.resolveVersionRange(session, request); 199 } 200 201 @Override 202 public ArtifactDescriptorResult readArtifactDescriptor( 203 RepositorySystemSession session, ArtifactDescriptorRequest request) throws ArtifactDescriptorException { 204 validateSession(session); 205 requireNonNull(request, "request cannot be null"); 206 repositorySystemValidator.validateArtifactDescriptorRequest(session, request); 207 ArtifactDescriptorResult descriptorResult = artifactDescriptorReader.readArtifactDescriptor(session, request); 208 for (ArtifactDecorator decorator : Utils.getArtifactDecorators(session, artifactDecoratorFactories)) { 209 descriptorResult.setArtifact(decorator.decorateArtifact(descriptorResult)); 210 } 211 return descriptorResult; 212 } 213 214 @Override 215 public ArtifactResult resolveArtifact(RepositorySystemSession session, ArtifactRequest request) 216 throws ArtifactResolutionException { 217 validateSession(session); 218 requireNonNull(request, "request cannot be null"); 219 repositorySystemValidator.validateArtifactRequests(session, Collections.singleton(request)); 220 return artifactResolver.resolveArtifact(session, request); 221 } 222 223 @Override 224 public List<ArtifactResult> resolveArtifacts( 225 RepositorySystemSession session, Collection<? extends ArtifactRequest> requests) 226 throws ArtifactResolutionException { 227 validateSession(session); 228 requireNonNull(requests, "requests cannot be null"); 229 repositorySystemValidator.validateArtifactRequests(session, requests); 230 return artifactResolver.resolveArtifacts(session, requests); 231 } 232 233 @Override 234 public List<MetadataResult> resolveMetadata( 235 RepositorySystemSession session, Collection<? extends MetadataRequest> requests) { 236 validateSession(session); 237 requireNonNull(requests, "requests cannot be null"); 238 repositorySystemValidator.validateMetadataRequests(session, requests); 239 return metadataResolver.resolveMetadata(session, requests); 240 } 241 242 @Override 243 public CollectResult collectDependencies(RepositorySystemSession session, CollectRequest request) 244 throws DependencyCollectionException { 245 validateSession(session); 246 requireNonNull(request, "request cannot be null"); 247 repositorySystemValidator.validateCollectRequest(session, request); 248 return dependencyCollector.collectDependencies(session, request); 249 } 250 251 @Override 252 public DependencyResult resolveDependencies(RepositorySystemSession session, DependencyRequest request) 253 throws DependencyResolutionException { 254 validateSession(session); 255 requireNonNull(request, "request cannot be null"); 256 repositorySystemValidator.validateDependencyRequest(session, request); 257 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request); 258 259 DependencyResult result = new DependencyResult(request); 260 261 DependencyCollectionException dce = null; 262 ArtifactResolutionException are = null; 263 264 if (request.getRoot() != null) { 265 result.setRoot(request.getRoot()); 266 } else if (request.getCollectRequest() != null) { 267 CollectResult collectResult; 268 try { 269 request.getCollectRequest().setTrace(trace); 270 collectResult = dependencyCollector.collectDependencies(session, request.getCollectRequest()); 271 } catch (DependencyCollectionException e) { 272 dce = e; 273 collectResult = e.getResult(); 274 } 275 result.setRoot(collectResult.getRoot()); 276 result.setCycles(collectResult.getCycles()); 277 result.setCollectExceptions(collectResult.getExceptions()); 278 } else { 279 throw new NullPointerException("dependency node and collect request cannot be null"); 280 } 281 282 final List<DependencyNode> dependencyNodes = 283 doFlattenDependencyNodes(session, result.getRoot(), request.getFilter()); 284 285 final List<ArtifactRequest> requests = dependencyNodes.stream() 286 .map(n -> { 287 if (n.getDependency() != null) { 288 ArtifactRequest artifactRequest = new ArtifactRequest(n); 289 artifactRequest.setTrace(trace); 290 return artifactRequest; 291 } else { 292 return null; 293 } 294 }) 295 .filter(Objects::nonNull) 296 .collect(Collectors.toList()); 297 List<ArtifactResult> results; 298 try { 299 results = artifactResolver.resolveArtifacts(session, requests); 300 } catch (ArtifactResolutionException e) { 301 are = e; 302 results = e.getResults(); 303 } 304 result.setDependencyNodeResults(dependencyNodes); 305 result.setArtifactResults(results); 306 307 updateNodesWithResolvedArtifacts(results); 308 309 if (dce != null) { 310 throw new DependencyResolutionException(result, dce); 311 } else if (are != null) { 312 throw new DependencyResolutionException(result, are); 313 } 314 315 return result; 316 } 317 318 @Override 319 public List<DependencyNode> flattenDependencyNodes( 320 RepositorySystemSession session, DependencyNode root, DependencyFilter dependencyFilter) { 321 validateSession(session); 322 requireNonNull(root, "root cannot be null"); 323 324 return doFlattenDependencyNodes(session, root, dependencyFilter); 325 } 326 327 private List<DependencyNode> doFlattenDependencyNodes( 328 RepositorySystemSession session, DependencyNode root, DependencyFilter dependencyFilter) { 329 final ArrayList<DependencyNode> dependencyNodes = new ArrayList<>(); 330 if (root != null) { 331 DependencyVisitor builder = getDependencyVisitor(session, dependencyNodes::add); 332 DependencyVisitor visitor = 333 (dependencyFilter != null) ? new FilteringDependencyVisitor(builder, dependencyFilter) : builder; 334 root.accept(visitor); 335 } 336 return dependencyNodes; 337 } 338 339 private DependencyVisitor getDependencyVisitor( 340 RepositorySystemSession session, Consumer<DependencyNode> nodeConsumer) { 341 String strategy = ConfigUtils.getString( 342 session, 343 ConfigurationProperties.REPOSITORY_SYSTEM_DEPENDENCY_VISITOR_PREORDER, 344 ConfigurationProperties.REPOSITORY_SYSTEM_DEPENDENCY_VISITOR); 345 switch (strategy) { 346 case PreorderDependencyNodeConsumerVisitor.NAME: 347 return new PreorderDependencyNodeConsumerVisitor(nodeConsumer); 348 case PostorderDependencyNodeConsumerVisitor.NAME: 349 return new PostorderDependencyNodeConsumerVisitor(nodeConsumer); 350 case LevelOrderDependencyNodeConsumerVisitor.NAME: 351 return new LevelOrderDependencyNodeConsumerVisitor(nodeConsumer); 352 default: 353 throw new IllegalArgumentException("Invalid dependency visitor strategy: " + strategy); 354 } 355 } 356 357 private void updateNodesWithResolvedArtifacts(List<ArtifactResult> results) { 358 for (ArtifactResult result : results) { 359 Artifact artifact = result.getArtifact(); 360 if (artifact != null) { 361 result.getRequest().getDependencyNode().setArtifact(artifact); 362 } 363 } 364 } 365 366 @Override 367 public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException { 368 validateSession(session); 369 requireNonNull(request, "request cannot be null"); 370 repositorySystemValidator.validateInstallRequest(session, request); 371 return installer.install(session, request); 372 } 373 374 @Override 375 public DeployResult deploy(RepositorySystemSession session, DeployRequest request) throws DeploymentException { 376 validateSession(session); 377 requireNonNull(request, "request cannot be null"); 378 repositorySystemValidator.validateDeployRequest(session, request); 379 return deployer.deploy(session, request); 380 } 381 382 @Override 383 public LocalRepositoryManager newLocalRepositoryManager( 384 RepositorySystemSession session, LocalRepository localRepository) { 385 requireNonNull(session, "session cannot be null"); 386 requireNonNull(localRepository, "localRepository cannot be null"); 387 validateSystem(); 388 repositorySystemValidator.validateLocalRepositories(session, Collections.singleton(localRepository)); 389 return createLocalRepositoryManager(session, localRepository); 390 } 391 392 @Override 393 public LocalRepositoryManager newLocalRepositoryManager( 394 RepositorySystemSession session, LocalRepository... localRepositories) { 395 requireNonNull(session, "session cannot be null"); 396 requireNonNull(localRepositories, "localRepositories cannot be null"); 397 validateSystem(); 398 repositorySystemValidator.validateLocalRepositories(session, Arrays.asList(localRepositories)); 399 return createLocalRepositoryManager(session, Arrays.asList(localRepositories)); 400 } 401 402 @Override 403 public LocalRepositoryManager newLocalRepositoryManager( 404 RepositorySystemSession session, List<LocalRepository> localRepositories) { 405 requireNonNull(session, "session cannot be null"); 406 requireNonNull(localRepositories, "localRepositories cannot be null"); 407 validateSystem(); 408 repositorySystemValidator.validateLocalRepositories(session, localRepositories); 409 return createLocalRepositoryManager(session, localRepositories); 410 } 411 412 private LocalRepositoryManager createLocalRepositoryManager( 413 RepositorySystemSession session, List<LocalRepository> localRepositories) { 414 if (localRepositories.isEmpty()) { 415 throw new IllegalArgumentException("empty localRepositories"); 416 } else if (localRepositories.size() == 1) { 417 return createLocalRepositoryManager(session, localRepositories.get(0)); 418 } else { 419 LocalRepositoryManager head = createLocalRepositoryManager(session, localRepositories.get(0)); 420 List<LocalRepositoryManager> tail = localRepositories.subList(1, localRepositories.size()).stream() 421 .map(l -> createLocalRepositoryManager(session, l)) 422 .collect(toList()); 423 return new ChainedLocalRepositoryManager(head, tail, session); 424 } 425 } 426 427 private LocalRepositoryManager createLocalRepositoryManager( 428 RepositorySystemSession session, LocalRepository localRepository) { 429 try { 430 return localRepositoryProvider.newLocalRepositoryManager(session, localRepository); 431 } catch (NoLocalRepositoryManagerException e) { 432 throw new IllegalArgumentException(e.getMessage(), e); 433 } 434 } 435 436 @Override 437 public SyncContext newSyncContext(RepositorySystemSession session, boolean shared) { 438 validateSession(session); 439 return syncContextFactory.newInstance(session, shared); 440 } 441 442 @Override 443 public List<RemoteRepository> newResolutionRepositories( 444 RepositorySystemSession session, List<RemoteRepository> repositories) { 445 validateSession(session); 446 validateRepositories(repositories); 447 repositorySystemValidator.validateRemoteRepositories(session, repositories); 448 repositories = remoteRepositoryManager.aggregateRepositories(session, new ArrayList<>(), repositories, true); 449 return repositories; 450 } 451 452 @Override 453 public RemoteRepository newDeploymentRepository(RepositorySystemSession session, RemoteRepository repository) { 454 validateSession(session); 455 requireNonNull(repository, "repository cannot be null"); 456 repositorySystemValidator.validateRemoteRepositories(session, Collections.singletonList(repository)); 457 RemoteRepository.Builder builder = new RemoteRepository.Builder(repository); 458 Authentication auth = session.getAuthenticationSelector().getAuthentication(repository); 459 builder.setAuthentication(auth); 460 Proxy proxy = session.getProxySelector().getProxy(repository); 461 builder.setProxy(proxy); 462 return builder.build(); 463 } 464 465 @Override 466 public void addOnSystemEndedHandler(Runnable handler) { 467 validateSystem(); 468 repositorySystemLifecycle.addOnSystemEndedHandler(handler); 469 } 470 471 @Override 472 public RepositorySystemSession.SessionBuilder createSessionBuilder() { 473 validateSystem(); 474 return new DefaultSessionBuilder( 475 this, repositorySystemLifecycle, () -> "id-" + sessionIdCounter.incrementAndGet()); 476 } 477 478 @Override 479 public void shutdown() { 480 if (shutdown.compareAndSet(false, true)) { 481 repositorySystemLifecycle.systemEnded(); 482 } 483 } 484 485 private void validateSession(RepositorySystemSession session) { 486 requireNonNull(session, "repository system session cannot be null"); 487 invalidSession(session.getLocalRepositoryManager(), "local repository manager"); 488 invalidSession(session.getSystemProperties(), "system properties"); 489 invalidSession(session.getUserProperties(), "user properties"); 490 invalidSession(session.getConfigProperties(), "config properties"); 491 invalidSession(session.getMirrorSelector(), "mirror selector"); 492 invalidSession(session.getProxySelector(), "proxy selector"); 493 invalidSession(session.getAuthenticationSelector(), "authentication selector"); 494 invalidSession(session.getArtifactTypeRegistry(), "artifact type registry"); 495 invalidSession(session.getData(), "data"); 496 validateSystem(); 497 } 498 499 private void validateSystem() { 500 if (shutdown.get()) { 501 throw new IllegalStateException("repository system is already shut down"); 502 } 503 } 504 505 private void validateRepositories(List<RemoteRepository> repositories) { 506 requireNonNull(repositories, "repositories cannot be null"); 507 for (RemoteRepository repository : repositories) { 508 requireNonNull(repository, "repository cannot be null"); 509 } 510 } 511 512 private void invalidSession(Object obj, String name) { 513 requireNonNull(obj, "repository system session's " + name + " cannot be null"); 514 } 515}