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