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.collect; 020 021import java.lang.ref.WeakReference; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Map; 027import java.util.Objects; 028import java.util.WeakHashMap; 029import java.util.concurrent.ConcurrentHashMap; 030 031import org.eclipse.aether.RepositoryCache; 032import org.eclipse.aether.RepositorySystemSession; 033import org.eclipse.aether.artifact.Artifact; 034import org.eclipse.aether.collection.DependencyManager; 035import org.eclipse.aether.collection.DependencySelector; 036import org.eclipse.aether.collection.DependencyTraverser; 037import org.eclipse.aether.collection.VersionFilter; 038import org.eclipse.aether.graph.Dependency; 039import org.eclipse.aether.graph.DependencyNode; 040import org.eclipse.aether.repository.ArtifactRepository; 041import org.eclipse.aether.repository.RemoteRepository; 042import org.eclipse.aether.resolution.ArtifactDescriptorException; 043import org.eclipse.aether.resolution.ArtifactDescriptorRequest; 044import org.eclipse.aether.resolution.ArtifactDescriptorResult; 045import org.eclipse.aether.resolution.VersionRangeRequest; 046import org.eclipse.aether.resolution.VersionRangeResult; 047import org.eclipse.aether.util.ConfigUtils; 048import org.eclipse.aether.version.Version; 049import org.eclipse.aether.version.VersionConstraint; 050 051/** 052 * Internal helper class for collector implementations. 053 */ 054public final class DataPool { 055 private static final String CONFIG_PROP_COLLECTOR_POOL_ARTIFACT = "aether.dependencyCollector.pool.artifact"; 056 057 private static final String CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY = "aether.dependencyCollector.pool.dependency"; 058 059 private static final String CONFIG_PROP_COLLECTOR_POOL_DESCRIPTOR = "aether.dependencyCollector.pool.descriptor"; 060 061 private static final String ARTIFACT_POOL = DataPool.class.getName() + "$Artifact"; 062 063 private static final String DEPENDENCY_POOL = DataPool.class.getName() + "$Dependency"; 064 065 private static final String DESCRIPTORS = DataPool.class.getName() + "$Descriptors"; 066 067 public static final ArtifactDescriptorResult NO_DESCRIPTOR = 068 new ArtifactDescriptorResult(new ArtifactDescriptorRequest()); 069 070 /** 071 * Artifact interning pool, lives across session (if session carries non-null {@link RepositoryCache}). 072 */ 073 private final InternPool<Artifact, Artifact> artifacts; 074 075 /** 076 * Dependency interning pool, lives across session (if session carries non-null {@link RepositoryCache}). 077 */ 078 private final InternPool<Dependency, Dependency> dependencies; 079 080 /** 081 * Descriptor interning pool, lives across session (if session carries non-null {@link RepositoryCache}). 082 */ 083 private final InternPool<Object, Descriptor> descriptors; 084 085 /** 086 * Constraint cache, lives during single collection invocation (same as this DataPool instance). 087 */ 088 private final ConcurrentHashMap<Object, Constraint> constraints; 089 090 /** 091 * DependencyNode cache, lives during single collection invocation (same as this DataPool instance). 092 */ 093 private final ConcurrentHashMap<Object, List<DependencyNode>> nodes; 094 095 @SuppressWarnings("unchecked") 096 public DataPool(RepositorySystemSession session) { 097 final RepositoryCache cache = session.getCache(); 098 099 InternPool<Artifact, Artifact> artifactsPool = null; 100 InternPool<Dependency, Dependency> dependenciesPool = null; 101 InternPool<Object, Descriptor> descriptorsPool = null; 102 if (cache != null) { 103 artifactsPool = (InternPool<Artifact, Artifact>) cache.get(session, ARTIFACT_POOL); 104 dependenciesPool = (InternPool<Dependency, Dependency>) cache.get(session, DEPENDENCY_POOL); 105 descriptorsPool = (InternPool<Object, Descriptor>) cache.get(session, DESCRIPTORS); 106 } 107 108 if (artifactsPool == null) { 109 String artifactPoolType = ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_ARTIFACT); 110 111 artifactsPool = createPool(artifactPoolType); 112 if (cache != null) { 113 cache.put(session, ARTIFACT_POOL, artifactsPool); 114 } 115 } 116 117 if (dependenciesPool == null) { 118 String dependencyPoolType = ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY); 119 120 dependenciesPool = createPool(dependencyPoolType); 121 if (cache != null) { 122 cache.put(session, DEPENDENCY_POOL, dependenciesPool); 123 } 124 } 125 126 if (descriptorsPool == null) { 127 String descriptorPoolType = ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DESCRIPTOR); 128 129 descriptorsPool = createPool(descriptorPoolType); 130 if (cache != null) { 131 cache.put(session, DESCRIPTORS, descriptorsPool); 132 } 133 } 134 135 this.artifacts = artifactsPool; 136 this.dependencies = dependenciesPool; 137 this.descriptors = descriptorsPool; 138 139 this.constraints = new ConcurrentHashMap<>(256); 140 this.nodes = new ConcurrentHashMap<>(256); 141 } 142 143 public Artifact intern(Artifact artifact) { 144 return artifacts.intern(artifact, artifact); 145 } 146 147 public Dependency intern(Dependency dependency) { 148 return dependencies.intern(dependency, dependency); 149 } 150 151 public Object toKey(ArtifactDescriptorRequest request) { 152 return request.getArtifact(); 153 } 154 155 public ArtifactDescriptorResult getDescriptor(Object key, ArtifactDescriptorRequest request) { 156 Descriptor descriptor = descriptors.get(key); 157 if (descriptor != null) { 158 return descriptor.toResult(request); 159 } 160 return null; 161 } 162 163 public void putDescriptor(Object key, ArtifactDescriptorResult result) { 164 descriptors.intern(key, new GoodDescriptor(result)); 165 } 166 167 public void putDescriptor(Object key, ArtifactDescriptorException e) { 168 descriptors.intern(key, BadDescriptor.INSTANCE); 169 } 170 171 public Object toKey(VersionRangeRequest request) { 172 return new ConstraintKey(request); 173 } 174 175 public VersionRangeResult getConstraint(Object key, VersionRangeRequest request) { 176 Constraint constraint = constraints.get(key); 177 if (constraint != null) { 178 return constraint.toResult(request); 179 } 180 return null; 181 } 182 183 public void putConstraint(Object key, VersionRangeResult result) { 184 constraints.put(key, new Constraint(result)); 185 } 186 187 public Object toKey( 188 Artifact artifact, 189 List<RemoteRepository> repositories, 190 DependencySelector selector, 191 DependencyManager manager, 192 DependencyTraverser traverser, 193 VersionFilter filter) { 194 return new GraphKey(artifact, repositories, selector, manager, traverser, filter); 195 } 196 197 public List<DependencyNode> getChildren(Object key) { 198 return nodes.get(key); 199 } 200 201 public void putChildren(Object key, List<DependencyNode> children) { 202 nodes.put(key, children); 203 } 204 205 abstract static class Descriptor { 206 207 public abstract ArtifactDescriptorResult toResult(ArtifactDescriptorRequest request); 208 } 209 210 static final class GoodDescriptor extends Descriptor { 211 212 final Artifact artifact; 213 214 final List<Artifact> relocations; 215 216 final Collection<Artifact> aliases; 217 218 final List<RemoteRepository> repositories; 219 220 final List<Dependency> dependencies; 221 222 final List<Dependency> managedDependencies; 223 224 GoodDescriptor(ArtifactDescriptorResult result) { 225 artifact = result.getArtifact(); 226 relocations = result.getRelocations(); 227 aliases = result.getAliases(); 228 dependencies = result.getDependencies(); 229 managedDependencies = result.getManagedDependencies(); 230 repositories = result.getRepositories(); 231 } 232 233 public ArtifactDescriptorResult toResult(ArtifactDescriptorRequest request) { 234 ArtifactDescriptorResult result = new ArtifactDescriptorResult(request); 235 result.setArtifact(artifact); 236 result.setRelocations(relocations); 237 result.setAliases(aliases); 238 result.setDependencies(dependencies); 239 result.setManagedDependencies(managedDependencies); 240 result.setRepositories(repositories); 241 return result; 242 } 243 } 244 245 static final class BadDescriptor extends Descriptor { 246 247 static final BadDescriptor INSTANCE = new BadDescriptor(); 248 249 public ArtifactDescriptorResult toResult(ArtifactDescriptorRequest request) { 250 return NO_DESCRIPTOR; 251 } 252 } 253 254 private static final class Constraint { 255 final VersionRepo[] repositories; 256 257 final VersionConstraint versionConstraint; 258 259 Constraint(VersionRangeResult result) { 260 versionConstraint = result.getVersionConstraint(); 261 List<Version> versions = result.getVersions(); 262 repositories = new VersionRepo[versions.size()]; 263 int i = 0; 264 for (Version version : versions) { 265 repositories[i++] = new VersionRepo(version, result.getRepository(version)); 266 } 267 } 268 269 VersionRangeResult toResult(VersionRangeRequest request) { 270 VersionRangeResult result = new VersionRangeResult(request); 271 for (VersionRepo vr : repositories) { 272 result.addVersion(vr.version); 273 result.setRepository(vr.version, vr.repo); 274 } 275 result.setVersionConstraint(versionConstraint); 276 return result; 277 } 278 279 static final class VersionRepo { 280 final Version version; 281 282 final ArtifactRepository repo; 283 284 VersionRepo(Version version, ArtifactRepository repo) { 285 this.version = version; 286 this.repo = repo; 287 } 288 } 289 } 290 291 static final class ConstraintKey { 292 private final Artifact artifact; 293 294 private final List<RemoteRepository> repositories; 295 296 private final int hashCode; 297 298 ConstraintKey(VersionRangeRequest request) { 299 artifact = request.getArtifact(); 300 repositories = request.getRepositories(); 301 hashCode = artifact.hashCode(); 302 } 303 304 @Override 305 public boolean equals(Object obj) { 306 if (obj == this) { 307 return true; 308 } else if (!(obj instanceof ConstraintKey)) { 309 return false; 310 } 311 ConstraintKey that = (ConstraintKey) obj; 312 return artifact.equals(that.artifact) && equals(repositories, that.repositories); 313 } 314 315 private static boolean equals(List<RemoteRepository> repos1, List<RemoteRepository> repos2) { 316 if (repos1.size() != repos2.size()) { 317 return false; 318 } 319 for (Iterator<RemoteRepository> it1 = repos1.iterator(), it2 = repos2.iterator(); 320 it1.hasNext() && it2.hasNext(); ) { 321 RemoteRepository repo1 = it1.next(); 322 RemoteRepository repo2 = it2.next(); 323 if (repo1.isRepositoryManager() != repo2.isRepositoryManager()) { 324 return false; 325 } 326 if (repo1.isRepositoryManager()) { 327 if (!equals(repo1.getMirroredRepositories(), repo2.getMirroredRepositories())) { 328 return false; 329 } 330 } else if (!repo1.getUrl().equals(repo2.getUrl())) { 331 return false; 332 } else if (repo1.getPolicy(true).isEnabled() 333 != repo2.getPolicy(true).isEnabled()) { 334 return false; 335 } else if (repo1.getPolicy(false).isEnabled() 336 != repo2.getPolicy(false).isEnabled()) { 337 return false; 338 } 339 } 340 return true; 341 } 342 343 @Override 344 public int hashCode() { 345 return hashCode; 346 } 347 } 348 349 static final class GraphKey { 350 private final Artifact artifact; 351 352 private final List<RemoteRepository> repositories; 353 354 private final DependencySelector selector; 355 356 private final DependencyManager manager; 357 358 private final DependencyTraverser traverser; 359 360 private final VersionFilter filter; 361 362 private final int hashCode; 363 364 GraphKey( 365 Artifact artifact, 366 List<RemoteRepository> repositories, 367 DependencySelector selector, 368 DependencyManager manager, 369 DependencyTraverser traverser, 370 VersionFilter filter) { 371 this.artifact = artifact; 372 this.repositories = repositories; 373 this.selector = selector; 374 this.manager = manager; 375 this.traverser = traverser; 376 this.filter = filter; 377 378 hashCode = Objects.hash(artifact, repositories, selector, manager, traverser, filter); 379 } 380 381 @Override 382 public boolean equals(Object obj) { 383 if (obj == this) { 384 return true; 385 } else if (!(obj instanceof GraphKey)) { 386 return false; 387 } 388 GraphKey that = (GraphKey) obj; 389 return Objects.equals(artifact, that.artifact) 390 && Objects.equals(repositories, that.repositories) 391 && Objects.equals(selector, that.selector) 392 && Objects.equals(manager, that.manager) 393 && Objects.equals(traverser, that.traverser) 394 && Objects.equals(filter, that.filter); 395 } 396 397 @Override 398 public int hashCode() { 399 return hashCode; 400 } 401 } 402 403 private static <K, V> InternPool<K, V> createPool(String type) { 404 if (HARD.equals(type)) { 405 return new HardInternPool<>(); 406 } else if (WEAK.equals(type)) { 407 return new WeakInternPool<>(); 408 } else { 409 throw new IllegalArgumentException("Unknown object pool type: '" + type + "'"); 410 } 411 } 412 413 private static final String HARD = "hard"; 414 415 private static final String WEAK = "weak"; 416 417 private interface InternPool<K, V> { 418 V get(K key); 419 420 V intern(K key, V value); 421 } 422 423 private static class HardInternPool<K, V> implements InternPool<K, V> { 424 private final ConcurrentHashMap<K, V> map = new ConcurrentHashMap<>(256); 425 426 @Override 427 public V get(K key) { 428 return map.get(key); 429 } 430 431 @Override 432 public V intern(K key, V value) { 433 return map.computeIfAbsent(key, k -> value); 434 } 435 } 436 437 private static class WeakInternPool<K, V> implements InternPool<K, V> { 438 private final Map<K, WeakReference<V>> map = Collections.synchronizedMap(new WeakHashMap<>(256)); 439 440 @Override 441 public V get(K key) { 442 WeakReference<V> ref = map.get(key); 443 return ref != null ? ref.get() : null; 444 } 445 446 @Override 447 public V intern(K key, V value) { 448 WeakReference<V> pooledRef = map.get(key); 449 if (pooledRef != null) { 450 V pooled = pooledRef.get(); 451 if (pooled != null) { 452 return pooled; 453 } 454 } 455 map.put(key, new WeakReference<>(value)); 456 return value; 457 } 458 } 459}