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