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.util.graph.manager; 020 021import java.util.Collection; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.LinkedHashSet; 025import java.util.Map; 026import java.util.Objects; 027 028import org.eclipse.aether.artifact.Artifact; 029import org.eclipse.aether.collection.DependencyCollectionContext; 030import org.eclipse.aether.collection.DependencyManagement; 031import org.eclipse.aether.collection.DependencyManager; 032import org.eclipse.aether.graph.Dependency; 033import org.eclipse.aether.graph.Exclusion; 034import org.eclipse.aether.scope.ScopeManager; 035import org.eclipse.aether.scope.SystemDependencyScope; 036 037import static java.util.Objects.requireNonNull; 038 039/** 040 * A dependency manager support class. 041 * 042 * @since 2.0.0 043 */ 044public abstract class AbstractDependencyManager implements DependencyManager { 045 046 protected final int depth; 047 048 protected final int deriveUntil; 049 050 protected final int applyFrom; 051 052 protected final Map<Object, String> managedVersions; 053 054 protected final Map<Object, String> managedScopes; 055 056 protected final Map<Object, Boolean> managedOptionals; 057 058 protected final Map<Object, String> managedLocalPaths; 059 060 protected final Map<Object, Collection<Exclusion>> managedExclusions; 061 062 protected final SystemDependencyScope systemDependencyScope; 063 064 private final int hashCode; 065 066 protected AbstractDependencyManager(int deriveUntil, int applyFrom, ScopeManager scopeManager) { 067 this( 068 0, 069 deriveUntil, 070 applyFrom, 071 Collections.emptyMap(), 072 Collections.emptyMap(), 073 Collections.emptyMap(), 074 Collections.emptyMap(), 075 Collections.emptyMap(), 076 scopeManager != null 077 ? scopeManager.getSystemDependencyScope().orElse(null) 078 : SystemDependencyScope.LEGACY); 079 } 080 081 @SuppressWarnings("checkstyle:ParameterNumber") 082 protected AbstractDependencyManager( 083 int depth, 084 int deriveUntil, 085 int applyFrom, 086 Map<Object, String> managedVersions, 087 Map<Object, String> managedScopes, 088 Map<Object, Boolean> managedOptionals, 089 Map<Object, String> managedLocalPaths, 090 Map<Object, Collection<Exclusion>> managedExclusions, 091 SystemDependencyScope systemDependencyScope) { 092 this.depth = depth; 093 this.deriveUntil = deriveUntil; 094 this.applyFrom = applyFrom; 095 this.managedVersions = requireNonNull(managedVersions); 096 this.managedScopes = requireNonNull(managedScopes); 097 this.managedOptionals = requireNonNull(managedOptionals); 098 this.managedLocalPaths = requireNonNull(managedLocalPaths); 099 this.managedExclusions = requireNonNull(managedExclusions); 100 // nullable: if using scope manager, but there is no system scope defined 101 this.systemDependencyScope = systemDependencyScope; 102 103 this.hashCode = Objects.hash( 104 depth, 105 deriveUntil, 106 applyFrom, 107 managedVersions, 108 managedScopes, 109 managedOptionals, 110 managedLocalPaths, 111 managedExclusions); 112 } 113 114 protected abstract DependencyManager newInstance( 115 Map<Object, String> managedVersions, 116 Map<Object, String> managedScopes, 117 Map<Object, Boolean> managedOptionals, 118 Map<Object, String> managedLocalPaths, 119 Map<Object, Collection<Exclusion>> managedExclusions); 120 121 @Override 122 public DependencyManager deriveChildManager(DependencyCollectionContext context) { 123 requireNonNull(context, "context cannot be null"); 124 if (depth >= deriveUntil) { 125 return this; 126 } 127 128 Map<Object, String> managedVersions = this.managedVersions; 129 Map<Object, String> managedScopes = this.managedScopes; 130 Map<Object, Boolean> managedOptionals = this.managedOptionals; 131 Map<Object, String> managedLocalPaths = this.managedLocalPaths; 132 Map<Object, Collection<Exclusion>> managedExclusions = this.managedExclusions; 133 134 for (Dependency managedDependency : context.getManagedDependencies()) { 135 Artifact artifact = managedDependency.getArtifact(); 136 Object key = new Key(artifact); 137 138 String version = artifact.getVersion(); 139 if (!version.isEmpty() && !managedVersions.containsKey(key)) { 140 if (managedVersions == this.managedVersions) { 141 managedVersions = new HashMap<>(this.managedVersions); 142 } 143 managedVersions.put(key, version); 144 } 145 146 String scope = managedDependency.getScope(); 147 if (!scope.isEmpty() && !managedScopes.containsKey(key)) { 148 if (managedScopes == this.managedScopes) { 149 managedScopes = new HashMap<>(this.managedScopes); 150 } 151 managedScopes.put(key, scope); 152 } 153 154 Boolean optional = managedDependency.getOptional(); 155 if (optional != null && !managedOptionals.containsKey(key)) { 156 if (managedOptionals == this.managedOptionals) { 157 managedOptionals = new HashMap<>(this.managedOptionals); 158 } 159 managedOptionals.put(key, optional); 160 } 161 162 String localPath = systemDependencyScope == null 163 ? null 164 : systemDependencyScope.getSystemPath(managedDependency.getArtifact()); 165 if (localPath != null && !managedLocalPaths.containsKey(key)) { 166 if (managedLocalPaths == this.managedLocalPaths) { 167 managedLocalPaths = new HashMap<>(this.managedLocalPaths); 168 } 169 managedLocalPaths.put(key, localPath); 170 } 171 172 Collection<Exclusion> exclusions = managedDependency.getExclusions(); 173 if (!exclusions.isEmpty()) { 174 if (managedExclusions == this.managedExclusions) { 175 managedExclusions = new HashMap<>(this.managedExclusions); 176 } 177 Collection<Exclusion> managed = managedExclusions.computeIfAbsent(key, k -> new LinkedHashSet<>()); 178 managed.addAll(exclusions); 179 } 180 } 181 182 return newInstance(managedVersions, managedScopes, managedOptionals, managedLocalPaths, managedExclusions); 183 } 184 185 @Override 186 public DependencyManagement manageDependency(Dependency dependency) { 187 requireNonNull(dependency, "dependency cannot be null"); 188 DependencyManagement management = null; 189 Object key = new Key(dependency.getArtifact()); 190 191 if (depth >= applyFrom) { 192 String version = managedVersions.get(key); 193 if (version != null) { 194 management = new DependencyManagement(); 195 management.setVersion(version); 196 } 197 198 String scope = managedScopes.get(key); 199 if (scope != null) { 200 if (management == null) { 201 management = new DependencyManagement(); 202 } 203 management.setScope(scope); 204 205 if (systemDependencyScope != null 206 && !systemDependencyScope.is(scope) 207 && systemDependencyScope.getSystemPath(dependency.getArtifact()) != null) { 208 Map<String, String> properties = 209 new HashMap<>(dependency.getArtifact().getProperties()); 210 systemDependencyScope.setSystemPath(properties, null); 211 management.setProperties(properties); 212 } 213 } 214 215 if (systemDependencyScope != null 216 && (systemDependencyScope.is(scope) 217 || (scope == null && systemDependencyScope.is(dependency.getScope())))) { 218 String localPath = managedLocalPaths.get(key); 219 if (localPath != null) { 220 if (management == null) { 221 management = new DependencyManagement(); 222 } 223 Map<String, String> properties = 224 new HashMap<>(dependency.getArtifact().getProperties()); 225 systemDependencyScope.setSystemPath(properties, localPath); 226 management.setProperties(properties); 227 } 228 } 229 230 Boolean optional = managedOptionals.get(key); 231 if (optional != null) { 232 if (management == null) { 233 management = new DependencyManagement(); 234 } 235 management.setOptional(optional); 236 } 237 } 238 239 Collection<Exclusion> exclusions = managedExclusions.get(key); 240 if (exclusions != null) { 241 if (management == null) { 242 management = new DependencyManagement(); 243 } 244 Collection<Exclusion> result = new LinkedHashSet<>(dependency.getExclusions()); 245 result.addAll(exclusions); 246 management.setExclusions(result); 247 } 248 249 return management; 250 } 251 252 @Override 253 public boolean equals(Object obj) { 254 if (this == obj) { 255 return true; 256 } else if (null == obj || !getClass().equals(obj.getClass())) { 257 return false; 258 } 259 260 AbstractDependencyManager that = (AbstractDependencyManager) obj; 261 return depth == that.depth 262 && deriveUntil == that.deriveUntil 263 && applyFrom == that.applyFrom 264 && managedVersions.equals(that.managedVersions) 265 && managedScopes.equals(that.managedScopes) 266 && managedOptionals.equals(that.managedOptionals) 267 && managedExclusions.equals(that.managedExclusions); 268 } 269 270 @Override 271 public int hashCode() { 272 return hashCode; 273 } 274 275 protected static class Key { 276 277 private final Artifact artifact; 278 279 private final int hashCode; 280 281 Key(Artifact artifact) { 282 this.artifact = artifact; 283 this.hashCode = Objects.hash(artifact.getGroupId(), artifact.getArtifactId()); 284 } 285 286 @Override 287 public boolean equals(Object obj) { 288 if (obj == this) { 289 return true; 290 } else if (!(obj instanceof Key)) { 291 return false; 292 } 293 Key that = (Key) obj; 294 return artifact.getArtifactId().equals(that.artifact.getArtifactId()) 295 && artifact.getGroupId().equals(that.artifact.getGroupId()) 296 && artifact.getExtension().equals(that.artifact.getExtension()) 297 && artifact.getClassifier().equals(that.artifact.getClassifier()); 298 } 299 300 @Override 301 public int hashCode() { 302 return hashCode; 303 } 304 305 @Override 306 public String toString() { 307 return String.valueOf(artifact); 308 } 309 } 310}