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