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