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