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