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.artifact.ArtifactProperties; 030import org.eclipse.aether.collection.DependencyCollectionContext; 031import org.eclipse.aether.collection.DependencyManagement; 032import org.eclipse.aether.collection.DependencyManager; 033import org.eclipse.aether.graph.Dependency; 034import org.eclipse.aether.graph.Exclusion; 035import org.eclipse.aether.util.artifact.JavaScopes; 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 private final int hashCode; 063 064 /** 065 * Creates a new dependency manager without any management information. 066 */ 067 protected AbstractDependencyManager(int deriveUntil, int applyFrom) { 068 this( 069 0, 070 deriveUntil, 071 applyFrom, 072 Collections.emptyMap(), 073 Collections.emptyMap(), 074 Collections.emptyMap(), 075 Collections.emptyMap(), 076 Collections.emptyMap()); 077 } 078 079 @SuppressWarnings("checkstyle:ParameterNumber") 080 protected AbstractDependencyManager( 081 int depth, 082 int deriveUntil, 083 int applyFrom, 084 Map<Object, String> managedVersions, 085 Map<Object, String> managedScopes, 086 Map<Object, Boolean> managedOptionals, 087 Map<Object, String> managedLocalPaths, 088 Map<Object, Collection<Exclusion>> managedExclusions) { 089 this.depth = depth; 090 this.deriveUntil = deriveUntil; 091 this.applyFrom = applyFrom; 092 this.managedVersions = managedVersions; 093 this.managedScopes = managedScopes; 094 this.managedOptionals = managedOptionals; 095 this.managedLocalPaths = managedLocalPaths; 096 this.managedExclusions = managedExclusions; 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 = managedDependency.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null); 158 if (localPath != null && !managedLocalPaths.containsKey(key)) { 159 if (managedLocalPaths == this.managedLocalPaths) { 160 managedLocalPaths = new HashMap<>(this.managedLocalPaths); 161 } 162 managedLocalPaths.put(key, localPath); 163 } 164 165 Collection<Exclusion> exclusions = managedDependency.getExclusions(); 166 if (!exclusions.isEmpty()) { 167 if (managedExclusions == this.managedExclusions) { 168 managedExclusions = new HashMap<>(this.managedExclusions); 169 } 170 Collection<Exclusion> managed = managedExclusions.computeIfAbsent(key, k -> new LinkedHashSet<>()); 171 managed.addAll(exclusions); 172 } 173 } 174 175 return newInstance(managedVersions, managedScopes, managedOptionals, managedLocalPaths, managedExclusions); 176 } 177 178 @Override 179 public DependencyManagement manageDependency(Dependency dependency) { 180 requireNonNull(dependency, "dependency cannot be null"); 181 DependencyManagement management = null; 182 Object key = new Key(dependency.getArtifact()); 183 184 if (depth >= applyFrom) { 185 String version = managedVersions.get(key); 186 if (version != null) { 187 management = new DependencyManagement(); 188 management.setVersion(version); 189 } 190 191 String scope = managedScopes.get(key); 192 if (scope != null) { 193 if (management == null) { 194 management = new DependencyManagement(); 195 } 196 management.setScope(scope); 197 198 if (!JavaScopes.SYSTEM.equals(scope) 199 && dependency.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) { 200 Map<String, String> properties = 201 new HashMap<>(dependency.getArtifact().getProperties()); 202 properties.remove(ArtifactProperties.LOCAL_PATH); 203 management.setProperties(properties); 204 } 205 } 206 207 if ((JavaScopes.SYSTEM.equals(scope)) 208 || (scope == null && JavaScopes.SYSTEM.equals(dependency.getScope()))) { 209 String localPath = managedLocalPaths.get(key); 210 if (localPath != null) { 211 if (management == null) { 212 management = new DependencyManagement(); 213 } 214 Map<String, String> properties = 215 new HashMap<>(dependency.getArtifact().getProperties()); 216 properties.put(ArtifactProperties.LOCAL_PATH, localPath); 217 management.setProperties(properties); 218 } 219 } 220 221 Boolean optional = managedOptionals.get(key); 222 if (optional != null) { 223 if (management == null) { 224 management = new DependencyManagement(); 225 } 226 management.setOptional(optional); 227 } 228 } 229 230 Collection<Exclusion> exclusions = managedExclusions.get(key); 231 if (exclusions != null) { 232 if (management == null) { 233 management = new DependencyManagement(); 234 } 235 Collection<Exclusion> result = new LinkedHashSet<>(dependency.getExclusions()); 236 result.addAll(exclusions); 237 management.setExclusions(result); 238 } 239 240 return management; 241 } 242 243 @Override 244 public boolean equals(Object obj) { 245 if (this == obj) { 246 return true; 247 } else if (null == obj || !getClass().equals(obj.getClass())) { 248 return false; 249 } 250 251 AbstractDependencyManager that = (AbstractDependencyManager) obj; 252 return depth == that.depth 253 && deriveUntil == that.deriveUntil 254 && applyFrom == that.applyFrom 255 && managedVersions.equals(that.managedVersions) 256 && managedScopes.equals(that.managedScopes) 257 && managedOptionals.equals(that.managedOptionals) 258 && managedExclusions.equals(that.managedExclusions); 259 } 260 261 @Override 262 public int hashCode() { 263 return hashCode; 264 } 265 266 protected static class Key { 267 268 private final Artifact artifact; 269 270 private final int hashCode; 271 272 Key(Artifact artifact) { 273 this.artifact = artifact; 274 this.hashCode = Objects.hash(artifact.getGroupId(), artifact.getArtifactId()); 275 } 276 277 @Override 278 public boolean equals(Object obj) { 279 if (obj == this) { 280 return true; 281 } else if (!(obj instanceof Key)) { 282 return false; 283 } 284 Key that = (Key) obj; 285 return artifact.getArtifactId().equals(that.artifact.getArtifactId()) 286 && artifact.getGroupId().equals(that.artifact.getGroupId()) 287 && artifact.getExtension().equals(that.artifact.getExtension()) 288 && artifact.getClassifier().equals(that.artifact.getClassifier()); 289 } 290 291 @Override 292 public int hashCode() { 293 return hashCode; 294 } 295 } 296}