001package org.eclipse.aether.util.graph.manager; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.util.Collection; 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.LinkedHashSet; 026import java.util.Map; 027import java.util.Objects; 028 029import org.eclipse.aether.artifact.Artifact; 030import org.eclipse.aether.artifact.ArtifactProperties; 031import org.eclipse.aether.collection.DependencyCollectionContext; 032import org.eclipse.aether.collection.DependencyManagement; 033import org.eclipse.aether.collection.DependencyManager; 034import org.eclipse.aether.graph.Dependency; 035import org.eclipse.aether.graph.Exclusion; 036import org.eclipse.aether.util.artifact.JavaScopes; 037 038import static java.util.Objects.requireNonNull; 039 040/** 041 * A dependency manager managing dependencies on all levels supporting transitive dependency management. 042 * <p> 043 * <b>Note:</b>Unlike the {@code ClassicDependencyManager} and the {@code TransitiveDependencyManager} this 044 * implementation applies management also on the first level. This is considered the resolver's default behaviour. 045 * It ignores all management overrides supported by the {@code MavenModelBuilder}. 046 * </p> 047 * 048 * @author Christian Schulte 049 * @since 1.4.0 050 */ 051public final class DefaultDependencyManager 052 implements DependencyManager 053{ 054 055 private final Map<Object, String> managedVersions; 056 057 private final Map<Object, String> managedScopes; 058 059 private final Map<Object, Boolean> managedOptionals; 060 061 private final Map<Object, String> managedLocalPaths; 062 063 private final Map<Object, Collection<Exclusion>> managedExclusions; 064 065 private int hashCode; 066 067 /** 068 * Creates a new dependency manager without any management information. 069 */ 070 public DefaultDependencyManager() 071 { 072 this( Collections.<Object, String>emptyMap(), Collections.<Object, String>emptyMap(), 073 Collections.<Object, Boolean>emptyMap(), Collections.<Object, String>emptyMap(), 074 Collections.<Object, Collection<Exclusion>>emptyMap() ); 075 } 076 077 private DefaultDependencyManager( 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 { 083 super(); 084 this.managedVersions = managedVersions; 085 this.managedScopes = managedScopes; 086 this.managedOptionals = managedOptionals; 087 this.managedLocalPaths = managedLocalPaths; 088 this.managedExclusions = managedExclusions; 089 } 090 091 public DependencyManager deriveChildManager( final DependencyCollectionContext context ) 092 { 093 requireNonNull( context, "context cannot be null" ); 094 Map<Object, String> versions = this.managedVersions; 095 Map<Object, String> scopes = this.managedScopes; 096 Map<Object, Boolean> optionals = this.managedOptionals; 097 Map<Object, String> localPaths = this.managedLocalPaths; 098 Map<Object, Collection<Exclusion>> exclusions = this.managedExclusions; 099 100 for ( Dependency managedDependency : context.getManagedDependencies() ) 101 { 102 Artifact artifact = managedDependency.getArtifact(); 103 Object key = getKey( artifact ); 104 105 String version = artifact.getVersion(); 106 if ( version.length() > 0 && !versions.containsKey( key ) ) 107 { 108 if ( versions == this.managedVersions ) 109 { 110 versions = new HashMap<>( this.managedVersions ); 111 } 112 versions.put( key, version ); 113 } 114 115 String scope = managedDependency.getScope(); 116 if ( scope.length() > 0 && !scopes.containsKey( key ) ) 117 { 118 if ( scopes == this.managedScopes ) 119 { 120 scopes = new HashMap<>( this.managedScopes ); 121 } 122 scopes.put( key, scope ); 123 } 124 125 Boolean optional = managedDependency.getOptional(); 126 if ( optional != null && !optionals.containsKey( key ) ) 127 { 128 if ( optionals == this.managedOptionals ) 129 { 130 optionals = new HashMap<>( this.managedOptionals ); 131 } 132 optionals.put( key, optional ); 133 } 134 135 String localPath = managedDependency.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ); 136 if ( localPath != null && !localPaths.containsKey( key ) ) 137 { 138 if ( localPaths == this.managedLocalPaths ) 139 { 140 localPaths = new HashMap<>( this.managedLocalPaths ); 141 } 142 localPaths.put( key, localPath ); 143 } 144 145 if ( !managedDependency.getExclusions().isEmpty() ) 146 { 147 if ( exclusions == this.managedExclusions ) 148 { 149 exclusions = new HashMap<>( this.managedExclusions ); 150 } 151 Collection<Exclusion> managed = exclusions.computeIfAbsent( key, k -> new LinkedHashSet<>() ); 152 managed.addAll( managedDependency.getExclusions() ); 153 } 154 } 155 156 return new DefaultDependencyManager( versions, scopes, optionals, localPaths, exclusions ); 157 } 158 159 public DependencyManagement manageDependency( Dependency dependency ) 160 { 161 requireNonNull( dependency, "dependency cannot be null" ); 162 DependencyManagement management = null; 163 164 Object key = getKey( dependency.getArtifact() ); 165 166 String version = managedVersions.get( key ); 167 if ( version != null ) 168 { 169 management = new DependencyManagement(); 170 management.setVersion( version ); 171 } 172 173 String scope = managedScopes.get( key ); 174 if ( scope != null ) 175 { 176 if ( management == null ) 177 { 178 management = new DependencyManagement(); 179 } 180 management.setScope( scope ); 181 182 if ( !JavaScopes.SYSTEM.equals( scope ) 183 && dependency.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) != null ) 184 { 185 Map<String, String> properties = 186 new HashMap<>( dependency.getArtifact().getProperties() ); 187 188 properties.remove( ArtifactProperties.LOCAL_PATH ); 189 management.setProperties( properties ); 190 } 191 } 192 193 if ( ( scope != null && JavaScopes.SYSTEM.equals( scope ) ) 194 || ( scope == null && JavaScopes.SYSTEM.equals( dependency.getScope() ) ) ) 195 { 196 String localPath = managedLocalPaths.get( key ); 197 if ( localPath != null ) 198 { 199 if ( management == null ) 200 { 201 management = new DependencyManagement(); 202 } 203 204 Map<String, String> properties = 205 new HashMap<>( dependency.getArtifact().getProperties() ); 206 207 properties.put( ArtifactProperties.LOCAL_PATH, localPath ); 208 management.setProperties( properties ); 209 } 210 } 211 212 Boolean optional = managedOptionals.get( key ); 213 if ( optional != null ) 214 { 215 if ( management == null ) 216 { 217 management = new DependencyManagement(); 218 } 219 management.setOptional( optional ); 220 } 221 222 Collection<Exclusion> exclusions = managedExclusions.get( key ); 223 if ( exclusions != null ) 224 { 225 if ( management == null ) 226 { 227 management = new DependencyManagement(); 228 } 229 Collection<Exclusion> result = new LinkedHashSet<>( dependency.getExclusions() ); 230 result.addAll( exclusions ); 231 management.setExclusions( result ); 232 } 233 234 return management; 235 } 236 237 private Object getKey( Artifact a ) 238 { 239 return new Key( a ); 240 } 241 242 @Override 243 public boolean equals( final Object obj ) 244 { 245 boolean equal = obj instanceof DefaultDependencyManager; 246 247 if ( equal ) 248 { 249 final DefaultDependencyManager that = (DefaultDependencyManager) obj; 250 equal = Objects.equals( managedVersions, that.managedVersions ) 251 && Objects.equals( managedScopes, that.managedScopes ) 252 && Objects.equals( managedOptionals, that.managedOptionals ) 253 && Objects.equals( managedExclusions, that.managedExclusions ); 254 255 } 256 257 return equal; 258 } 259 260 @Override 261 public int hashCode() 262 { 263 if ( hashCode == 0 ) 264 { 265 hashCode = Objects.hash( managedVersions, managedScopes, managedOptionals, managedExclusions ); 266 } 267 return hashCode; 268 } 269 270 static class Key 271 { 272 273 private final Artifact artifact; 274 275 private final int hashCode; 276 277 Key( final Artifact artifact ) 278 { 279 this.artifact = artifact; 280 this.hashCode = Objects.hash( artifact.getGroupId(), artifact.getArtifactId() ); 281 } 282 283 @Override 284 public boolean equals( final Object obj ) 285 { 286 boolean equal = obj instanceof Key; 287 288 if ( equal ) 289 { 290 final Key that = (Key) obj; 291 return Objects.equals( artifact.getArtifactId(), that.artifact.getArtifactId() ) 292 && Objects.equals( artifact.getGroupId(), that.artifact.getGroupId() ) 293 && Objects.equals( artifact.getExtension(), that.artifact.getExtension() ) 294 && Objects.equals( artifact.getClassifier(), that.artifact.getClassifier() ); 295 296 } 297 298 return false; 299 } 300 301 @Override 302 public int hashCode() 303 { 304 return this.hashCode; 305 } 306 307 } 308 309}