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 /** 094 * Flag controlling interning data pool type used by dependency lists collector for ArtifactDescriptor (POM) instances, 095 * matters for heap consumption. By default, uses “weak” references (consume less heap). Using “hard” will make it 096 * much more memory aggressive and possibly faster (system and Java dependent). Supported values: "hard", "weak". 097 * 098 * @since 1.9.22 099 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 100 * @configurationType {@link java.lang.String} 101 * @configurationDefaultValue {@link #HARD} 102 */ 103 public static final String CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY_LISTS = 104 "aether.dependencyCollector.pool.dependencyLists"; 105 106 /** 107 * Flag controlling interning artifact descriptor dependencies. 108 * 109 * @since 1.9.22 110 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 111 * @configurationType {@link java.lang.Boolean} 112 * @configurationDefaultValue false 113 */ 114 public static final String CONFIG_PROP_COLLECTOR_POOL_INTERN_ARTIFACT_DESCRIPTOR_DEPENDENCIES = 115 "aether.dependencyCollector.pool.internArtifactDescriptorDependencies"; 116 117 /** 118 * Flag controlling interning artifact descriptor managed dependencies. 119 * 120 * @since 1.9.22 121 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 122 * @configurationType {@link java.lang.Boolean} 123 * @configurationDefaultValue true 124 */ 125 public static final String CONFIG_PROP_COLLECTOR_POOL_INTERN_ARTIFACT_DESCRIPTOR_MANAGED_DEPENDENCIES = 126 "aether.dependencyCollector.pool.internArtifactDescriptorManagedDependencies"; 127 128 private static final String ARTIFACT_POOL = DataPool.class.getName() + "$Artifact"; 129 130 private static final String DEPENDENCY_POOL = DataPool.class.getName() + "$Dependency"; 131 132 private static final String DESCRIPTORS = DataPool.class.getName() + "$Descriptors"; 133 134 private static final String DEPENDENCY_LISTS_POOL = DataPool.class.getName() + "$DependencyLists"; 135 136 public static final ArtifactDescriptorResult NO_DESCRIPTOR = 137 new ArtifactDescriptorResult(new ArtifactDescriptorRequest()); 138 139 /** 140 * Artifact interning pool, lives across session (if session carries non-null {@link RepositoryCache}). 141 */ 142 private final InternPool<Artifact, Artifact> artifacts; 143 144 /** 145 * Dependency interning pool, lives across session (if session carries non-null {@link RepositoryCache}). 146 */ 147 private final InternPool<Dependency, Dependency> dependencies; 148 149 /** 150 * Descriptor interning pool, lives across session (if session carries non-null {@link RepositoryCache}). 151 */ 152 private final InternPool<DescriptorKey, Descriptor> descriptors; 153 154 /** 155 * {@link Dependency} list interning pool, lives across session (if session carries non-null {@link RepositoryCache}). 156 */ 157 private final InternPool<List<Dependency>, List<Dependency>> dependencyLists; 158 159 /** 160 * Constraint cache, lives during single collection invocation (same as this DataPool instance). 161 */ 162 private final ConcurrentHashMap<Object, Constraint> constraints; 163 164 /** 165 * DependencyNode cache, lives during single collection invocation (same as this DataPool instance). 166 */ 167 private final ConcurrentHashMap<Object, List<DependencyNode>> nodes; 168 169 private final boolean internArtifactDescriptorDependencies; 170 171 private final boolean internArtifactDescriptorManagedDependencies; 172 173 @SuppressWarnings("unchecked") 174 public DataPool(RepositorySystemSession session) { 175 final RepositoryCache cache = session.getCache(); 176 177 internArtifactDescriptorDependencies = ConfigUtils.getBoolean( 178 session, false, CONFIG_PROP_COLLECTOR_POOL_INTERN_ARTIFACT_DESCRIPTOR_DEPENDENCIES); 179 internArtifactDescriptorManagedDependencies = ConfigUtils.getBoolean( 180 session, true, CONFIG_PROP_COLLECTOR_POOL_INTERN_ARTIFACT_DESCRIPTOR_MANAGED_DEPENDENCIES); 181 182 InternPool<Artifact, Artifact> artifactsPool = null; 183 InternPool<Dependency, Dependency> dependenciesPool = null; 184 InternPool<DescriptorKey, Descriptor> descriptorsPool = null; 185 InternPool<List<Dependency>, List<Dependency>> dependencyListsPool = null; 186 if (cache != null) { 187 artifactsPool = (InternPool<Artifact, Artifact>) cache.get(session, ARTIFACT_POOL); 188 dependenciesPool = (InternPool<Dependency, Dependency>) cache.get(session, DEPENDENCY_POOL); 189 descriptorsPool = (InternPool<DescriptorKey, Descriptor>) cache.get(session, DESCRIPTORS); 190 dependencyListsPool = 191 (InternPool<List<Dependency>, List<Dependency>>) cache.get(session, DEPENDENCY_LISTS_POOL); 192 } 193 194 if (artifactsPool == null) { 195 String artifactPoolType = ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_ARTIFACT); 196 197 artifactsPool = createPool(artifactPoolType); 198 if (cache != null) { 199 cache.put(session, ARTIFACT_POOL, artifactsPool); 200 } 201 } 202 203 if (dependenciesPool == null) { 204 String dependencyPoolType = ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY); 205 206 dependenciesPool = createPool(dependencyPoolType); 207 if (cache != null) { 208 cache.put(session, DEPENDENCY_POOL, dependenciesPool); 209 } 210 } 211 212 if (descriptorsPool == null) { 213 String descriptorPoolType = ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DESCRIPTOR); 214 215 descriptorsPool = createPool(descriptorPoolType); 216 if (cache != null) { 217 cache.put(session, DESCRIPTORS, descriptorsPool); 218 } 219 } 220 221 if (dependencyListsPool == null) { 222 String dependencyListsPoolType = 223 ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY_LISTS); 224 225 dependencyListsPool = createPool(dependencyListsPoolType); 226 if (cache != null) { 227 cache.put(session, DEPENDENCY_LISTS_POOL, dependencyListsPool); 228 } 229 } 230 231 this.artifacts = artifactsPool; 232 this.dependencies = dependenciesPool; 233 this.descriptors = descriptorsPool; 234 this.dependencyLists = dependencyListsPool; 235 236 this.constraints = new ConcurrentHashMap<>(256); 237 this.nodes = new ConcurrentHashMap<>(256); 238 } 239 240 public Artifact intern(Artifact artifact) { 241 return artifacts.intern(artifact, artifact); 242 } 243 244 public Dependency intern(Dependency dependency) { 245 return dependencies.intern(dependency, dependency); 246 } 247 248 public DescriptorKey toKey(ArtifactDescriptorRequest request) { 249 return new DescriptorKey(request.getArtifact()); 250 } 251 252 public ArtifactDescriptorResult getDescriptor(DescriptorKey key, ArtifactDescriptorRequest request) { 253 Descriptor descriptor = descriptors.get(key); 254 if (descriptor != null) { 255 return descriptor.toResult(request); 256 } 257 return null; 258 } 259 260 public void putDescriptor(DescriptorKey key, ArtifactDescriptorResult result) { 261 if (internArtifactDescriptorDependencies) { 262 result.setDependencies(intern(result.getDependencies())); 263 } 264 if (internArtifactDescriptorManagedDependencies) { 265 result.setManagedDependencies(intern(result.getManagedDependencies())); 266 } 267 descriptors.intern(key, new GoodDescriptor(result)); 268 } 269 270 public void putDescriptor(DescriptorKey key, ArtifactDescriptorException e) { 271 descriptors.intern(key, BadDescriptor.INSTANCE); 272 } 273 274 private List<Dependency> intern(List<Dependency> dependencies) { 275 return dependencyLists.intern(dependencies, dependencies); 276 } 277 278 public Object toKey(VersionRangeRequest request) { 279 return new ConstraintKey(request); 280 } 281 282 public VersionRangeResult getConstraint(Object key, VersionRangeRequest request) { 283 Constraint constraint = constraints.get(key); 284 if (constraint != null) { 285 return constraint.toResult(request); 286 } 287 return null; 288 } 289 290 public void putConstraint(Object key, VersionRangeResult result) { 291 constraints.put(key, new Constraint(result)); 292 } 293 294 public Object toKey( 295 Artifact artifact, 296 List<RemoteRepository> repositories, 297 DependencySelector selector, 298 DependencyManager manager, 299 DependencyTraverser traverser, 300 VersionFilter filter) { 301 return new GraphKey(artifact, repositories, selector, manager, traverser, filter); 302 } 303 304 public List<DependencyNode> getChildren(Object key) { 305 return nodes.get(key); 306 } 307 308 public void putChildren(Object key, List<DependencyNode> children) { 309 nodes.put(key, children); 310 } 311 312 public static final class DescriptorKey { 313 private final Artifact artifact; 314 private final int hashCode; 315 316 private DescriptorKey(Artifact artifact) { 317 this.artifact = artifact; 318 this.hashCode = Objects.hashCode(artifact); 319 } 320 321 @Override 322 public boolean equals(Object o) { 323 if (this == o) { 324 return true; 325 } 326 if (o == null || getClass() != o.getClass()) { 327 return false; 328 } 329 DescriptorKey that = (DescriptorKey) o; 330 return Objects.equals(artifact, that.artifact); 331 } 332 333 @Override 334 public int hashCode() { 335 return hashCode; 336 } 337 338 @Override 339 public String toString() { 340 return getClass().getSimpleName() + "{" + "artifact='" + artifact + '\'' + '}'; 341 } 342 } 343 344 abstract static class Descriptor { 345 public abstract ArtifactDescriptorResult toResult(ArtifactDescriptorRequest request); 346 } 347 348 static final class GoodDescriptor extends Descriptor { 349 350 final Artifact artifact; 351 352 final List<Artifact> relocations; 353 354 final Collection<Artifact> aliases; 355 356 final List<RemoteRepository> repositories; 357 358 final List<Dependency> dependencies; 359 360 final List<Dependency> managedDependencies; 361 362 GoodDescriptor(ArtifactDescriptorResult result) { 363 artifact = result.getArtifact(); 364 relocations = result.getRelocations(); 365 aliases = result.getAliases(); 366 dependencies = result.getDependencies(); 367 managedDependencies = result.getManagedDependencies(); 368 repositories = result.getRepositories(); 369 } 370 371 public ArtifactDescriptorResult toResult(ArtifactDescriptorRequest request) { 372 ArtifactDescriptorResult result = new ArtifactDescriptorResult(request); 373 result.setArtifact(artifact); 374 result.setRelocations(relocations); 375 result.setAliases(aliases); 376 result.setDependencies(dependencies); 377 result.setManagedDependencies(managedDependencies); 378 result.setRepositories(repositories); 379 return result; 380 } 381 } 382 383 static final class BadDescriptor extends Descriptor { 384 385 static final BadDescriptor INSTANCE = new BadDescriptor(); 386 387 public ArtifactDescriptorResult toResult(ArtifactDescriptorRequest request) { 388 return NO_DESCRIPTOR; 389 } 390 } 391 392 private static final class Constraint { 393 final VersionRepo[] repositories; 394 395 final VersionConstraint versionConstraint; 396 397 Constraint(VersionRangeResult result) { 398 versionConstraint = result.getVersionConstraint(); 399 List<Version> versions = result.getVersions(); 400 repositories = new VersionRepo[versions.size()]; 401 int i = 0; 402 for (Version version : versions) { 403 repositories[i++] = new VersionRepo(version, result.getRepository(version)); 404 } 405 } 406 407 VersionRangeResult toResult(VersionRangeRequest request) { 408 VersionRangeResult result = new VersionRangeResult(request); 409 for (VersionRepo vr : repositories) { 410 result.addVersion(vr.version); 411 result.setRepository(vr.version, vr.repo); 412 } 413 result.setVersionConstraint(versionConstraint); 414 return result; 415 } 416 417 static final class VersionRepo { 418 final Version version; 419 420 final ArtifactRepository repo; 421 422 VersionRepo(Version version, ArtifactRepository repo) { 423 this.version = version; 424 this.repo = repo; 425 } 426 } 427 } 428 429 static final class ConstraintKey { 430 private final Artifact artifact; 431 432 private final List<RemoteRepository> repositories; 433 434 private final int hashCode; 435 436 ConstraintKey(VersionRangeRequest request) { 437 artifact = request.getArtifact(); 438 repositories = request.getRepositories(); 439 hashCode = artifact.hashCode(); 440 } 441 442 @Override 443 public boolean equals(Object obj) { 444 if (obj == this) { 445 return true; 446 } else if (!(obj instanceof ConstraintKey)) { 447 return false; 448 } 449 ConstraintKey that = (ConstraintKey) obj; 450 return artifact.equals(that.artifact) && equals(repositories, that.repositories); 451 } 452 453 private static boolean equals(List<RemoteRepository> repos1, List<RemoteRepository> repos2) { 454 if (repos1.size() != repos2.size()) { 455 return false; 456 } 457 for (Iterator<RemoteRepository> it1 = repos1.iterator(), it2 = repos2.iterator(); 458 it1.hasNext() && it2.hasNext(); ) { 459 RemoteRepository repo1 = it1.next(); 460 RemoteRepository repo2 = it2.next(); 461 if (repo1.isRepositoryManager() != repo2.isRepositoryManager()) { 462 return false; 463 } 464 if (repo1.isRepositoryManager()) { 465 if (!equals(repo1.getMirroredRepositories(), repo2.getMirroredRepositories())) { 466 return false; 467 } 468 } else if (!repo1.getUrl().equals(repo2.getUrl())) { 469 return false; 470 } else if (repo1.getPolicy(true).isEnabled() 471 != repo2.getPolicy(true).isEnabled()) { 472 return false; 473 } else if (repo1.getPolicy(false).isEnabled() 474 != repo2.getPolicy(false).isEnabled()) { 475 return false; 476 } 477 } 478 return true; 479 } 480 481 @Override 482 public int hashCode() { 483 return hashCode; 484 } 485 } 486 487 static final class GraphKey { 488 private final Artifact artifact; 489 490 private final List<RemoteRepository> repositories; 491 492 private final DependencySelector selector; 493 494 private final DependencyManager manager; 495 496 private final DependencyTraverser traverser; 497 498 private final VersionFilter filter; 499 500 private final int hashCode; 501 502 GraphKey( 503 Artifact artifact, 504 List<RemoteRepository> repositories, 505 DependencySelector selector, 506 DependencyManager manager, 507 DependencyTraverser traverser, 508 VersionFilter filter) { 509 this.artifact = artifact; 510 this.repositories = repositories; 511 this.selector = selector; 512 this.manager = manager; 513 this.traverser = traverser; 514 this.filter = filter; 515 516 hashCode = Objects.hash(artifact, repositories, selector, manager, traverser, filter); 517 } 518 519 @Override 520 public boolean equals(Object obj) { 521 if (obj == this) { 522 return true; 523 } else if (!(obj instanceof GraphKey)) { 524 return false; 525 } 526 GraphKey that = (GraphKey) obj; 527 return Objects.equals(artifact, that.artifact) 528 && Objects.equals(repositories, that.repositories) 529 && Objects.equals(selector, that.selector) 530 && Objects.equals(manager, that.manager) 531 && Objects.equals(traverser, that.traverser) 532 && Objects.equals(filter, that.filter); 533 } 534 535 @Override 536 public int hashCode() { 537 return hashCode; 538 } 539 } 540 541 private static <K, V> InternPool<K, V> createPool(String type) { 542 if (HARD.equals(type)) { 543 return new HardInternPool<>(); 544 } else if (WEAK.equals(type)) { 545 return new WeakInternPool<>(); 546 } else { 547 throw new IllegalArgumentException("Unknown object pool type: '" + type + "'"); 548 } 549 } 550 551 public static final String HARD = "hard"; 552 553 public static final String WEAK = "weak"; 554 555 private interface InternPool<K, V> { 556 V get(K key); 557 558 V intern(K key, V value); 559 } 560 561 private static class HardInternPool<K, V> implements InternPool<K, V> { 562 private final ConcurrentHashMap<K, V> map = new ConcurrentHashMap<>(256); 563 564 @Override 565 public V get(K key) { 566 return map.get(key); 567 } 568 569 @Override 570 public V intern(K key, V value) { 571 return map.computeIfAbsent(key, k -> value); 572 } 573 } 574 575 private static class WeakInternPool<K, V> implements InternPool<K, V> { 576 private final Map<K, WeakReference<V>> map = Collections.synchronizedMap(new WeakHashMap<>(256)); 577 578 @Override 579 public V get(K key) { 580 WeakReference<V> ref = map.get(key); 581 return ref != null ? ref.get() : null; 582 } 583 584 @Override 585 public V intern(K key, V value) { 586 WeakReference<V> pooledRef = map.get(key); 587 if (pooledRef != null) { 588 V pooled = pooledRef.get(); 589 if (pooled != null) { 590 return pooled; 591 } 592 } 593 map.put(key, new WeakReference<>(value)); 594 return value; 595 } 596 } 597}