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