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