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 managing dependencies on all levels supporting transitive dependency management. 041 * <p> 042 * <b>Note:</b>Unlike the {@code ClassicDependencyManager} and the {@code TransitiveDependencyManager} this 043 * implementation applies management also on the first level. This is considered the resolver's default behaviour. 044 * It ignores all management overrides supported by the {@code MavenModelBuilder}. 045 * </p> 046 * 047 * @author Christian Schulte 048 * @since 1.4.0 049 */ 050public final class DefaultDependencyManager implements DependencyManager { 051 052 private final Map<Object, String> managedVersions; 053 054 private final Map<Object, String> managedScopes; 055 056 private final Map<Object, Boolean> managedOptionals; 057 058 private final Map<Object, String> managedLocalPaths; 059 060 private final Map<Object, Collection<Exclusion>> managedExclusions; 061 062 private int hashCode; 063 064 /** 065 * Creates a new dependency manager without any management information. 066 */ 067 public DefaultDependencyManager() { 068 this( 069 Collections.<Object, String>emptyMap(), 070 Collections.<Object, String>emptyMap(), 071 Collections.<Object, Boolean>emptyMap(), 072 Collections.<Object, String>emptyMap(), 073 Collections.<Object, Collection<Exclusion>>emptyMap()); 074 } 075 076 private DefaultDependencyManager( 077 final Map<Object, String> managedVersions, 078 final Map<Object, String> managedScopes, 079 final Map<Object, Boolean> managedOptionals, 080 final Map<Object, String> managedLocalPaths, 081 final Map<Object, Collection<Exclusion>> managedExclusions) { 082 super(); 083 this.managedVersions = managedVersions; 084 this.managedScopes = managedScopes; 085 this.managedOptionals = managedOptionals; 086 this.managedLocalPaths = managedLocalPaths; 087 this.managedExclusions = managedExclusions; 088 } 089 090 public DependencyManager deriveChildManager(final DependencyCollectionContext context) { 091 requireNonNull(context, "context cannot be null"); 092 Map<Object, String> versions = this.managedVersions; 093 Map<Object, String> scopes = this.managedScopes; 094 Map<Object, Boolean> optionals = this.managedOptionals; 095 Map<Object, String> localPaths = this.managedLocalPaths; 096 Map<Object, Collection<Exclusion>> exclusions = this.managedExclusions; 097 098 for (Dependency managedDependency : context.getManagedDependencies()) { 099 Artifact artifact = managedDependency.getArtifact(); 100 Object key = getKey(artifact); 101 102 String version = artifact.getVersion(); 103 if (version.length() > 0 && !versions.containsKey(key)) { 104 if (versions == this.managedVersions) { 105 versions = new HashMap<>(this.managedVersions); 106 } 107 versions.put(key, version); 108 } 109 110 String scope = managedDependency.getScope(); 111 if (scope.length() > 0 && !scopes.containsKey(key)) { 112 if (scopes == this.managedScopes) { 113 scopes = new HashMap<>(this.managedScopes); 114 } 115 scopes.put(key, scope); 116 } 117 118 Boolean optional = managedDependency.getOptional(); 119 if (optional != null && !optionals.containsKey(key)) { 120 if (optionals == this.managedOptionals) { 121 optionals = new HashMap<>(this.managedOptionals); 122 } 123 optionals.put(key, optional); 124 } 125 126 String localPath = managedDependency.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null); 127 if (localPath != null && !localPaths.containsKey(key)) { 128 if (localPaths == this.managedLocalPaths) { 129 localPaths = new HashMap<>(this.managedLocalPaths); 130 } 131 localPaths.put(key, localPath); 132 } 133 134 if (!managedDependency.getExclusions().isEmpty()) { 135 if (exclusions == this.managedExclusions) { 136 exclusions = new HashMap<>(this.managedExclusions); 137 } 138 Collection<Exclusion> managed = exclusions.computeIfAbsent(key, k -> new LinkedHashSet<>()); 139 managed.addAll(managedDependency.getExclusions()); 140 } 141 } 142 143 return new DefaultDependencyManager(versions, scopes, optionals, localPaths, exclusions); 144 } 145 146 public DependencyManagement manageDependency(Dependency dependency) { 147 requireNonNull(dependency, "dependency cannot be null"); 148 DependencyManagement management = null; 149 150 Object key = getKey(dependency.getArtifact()); 151 152 String version = managedVersions.get(key); 153 if (version != null) { 154 management = new DependencyManagement(); 155 management.setVersion(version); 156 } 157 158 String scope = managedScopes.get(key); 159 if (scope != null) { 160 if (management == null) { 161 management = new DependencyManagement(); 162 } 163 management.setScope(scope); 164 165 if (!JavaScopes.SYSTEM.equals(scope) 166 && dependency.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) { 167 Map<String, String> properties = 168 new HashMap<>(dependency.getArtifact().getProperties()); 169 170 properties.remove(ArtifactProperties.LOCAL_PATH); 171 management.setProperties(properties); 172 } 173 } 174 175 if ((scope != null && JavaScopes.SYSTEM.equals(scope)) 176 || (scope == null && JavaScopes.SYSTEM.equals(dependency.getScope()))) { 177 String localPath = managedLocalPaths.get(key); 178 if (localPath != null) { 179 if (management == null) { 180 management = new DependencyManagement(); 181 } 182 183 Map<String, String> properties = 184 new HashMap<>(dependency.getArtifact().getProperties()); 185 186 properties.put(ArtifactProperties.LOCAL_PATH, localPath); 187 management.setProperties(properties); 188 } 189 } 190 191 Boolean optional = managedOptionals.get(key); 192 if (optional != null) { 193 if (management == null) { 194 management = new DependencyManagement(); 195 } 196 management.setOptional(optional); 197 } 198 199 Collection<Exclusion> exclusions = managedExclusions.get(key); 200 if (exclusions != null) { 201 if (management == null) { 202 management = new DependencyManagement(); 203 } 204 Collection<Exclusion> result = new LinkedHashSet<>(dependency.getExclusions()); 205 result.addAll(exclusions); 206 management.setExclusions(result); 207 } 208 209 return management; 210 } 211 212 private Object getKey(Artifact a) { 213 return new Key(a); 214 } 215 216 @Override 217 public boolean equals(final Object obj) { 218 boolean equal = obj instanceof DefaultDependencyManager; 219 220 if (equal) { 221 final DefaultDependencyManager that = (DefaultDependencyManager) obj; 222 equal = Objects.equals(managedVersions, that.managedVersions) 223 && Objects.equals(managedScopes, that.managedScopes) 224 && Objects.equals(managedOptionals, that.managedOptionals) 225 && Objects.equals(managedExclusions, that.managedExclusions); 226 } 227 228 return equal; 229 } 230 231 @Override 232 public int hashCode() { 233 if (hashCode == 0) { 234 hashCode = Objects.hash(managedVersions, managedScopes, managedOptionals, managedExclusions); 235 } 236 return hashCode; 237 } 238 239 static class Key { 240 241 private final Artifact artifact; 242 243 private final int hashCode; 244 245 Key(final Artifact artifact) { 246 this.artifact = artifact; 247 this.hashCode = Objects.hash(artifact.getGroupId(), artifact.getArtifactId()); 248 } 249 250 @Override 251 public boolean equals(final Object obj) { 252 boolean equal = obj instanceof Key; 253 254 if (equal) { 255 final Key that = (Key) obj; 256 return Objects.equals(artifact.getArtifactId(), that.artifact.getArtifactId()) 257 && Objects.equals(artifact.getGroupId(), that.artifact.getGroupId()) 258 && Objects.equals(artifact.getExtension(), that.artifact.getExtension()) 259 && Objects.equals(artifact.getClassifier(), that.artifact.getClassifier()); 260 } 261 262 return false; 263 } 264 265 @Override 266 public int hashCode() { 267 return this.hashCode; 268 } 269 } 270}