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; 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 that mimics the way Maven 2.x works. 041 */ 042public final class ClassicDependencyManager 043 implements DependencyManager 044{ 045 046 private final int depth; 047 048 private final Map<Object, String> managedVersions; 049 050 private final Map<Object, String> managedScopes; 051 052 private final Map<Object, Boolean> managedOptionals; 053 054 private final Map<Object, String> managedLocalPaths; 055 056 private final Map<Object, Collection<Exclusion>> managedExclusions; 057 058 private int hashCode; 059 060 /** 061 * Creates a new dependency manager without any management information. 062 */ 063 public ClassicDependencyManager() 064 { 065 this( 0, Collections.<Object, String>emptyMap(), Collections.<Object, String>emptyMap(), 066 Collections.<Object, Boolean>emptyMap(), Collections.<Object, String>emptyMap(), 067 Collections.<Object, Collection<Exclusion>>emptyMap() ); 068 } 069 070 private ClassicDependencyManager( int depth, Map<Object, String> managedVersions, 071 Map<Object, String> managedScopes, Map<Object, Boolean> managedOptionals, 072 Map<Object, String> managedLocalPaths, 073 Map<Object, Collection<Exclusion>> managedExclusions ) 074 { 075 this.depth = depth; 076 this.managedVersions = managedVersions; 077 this.managedScopes = managedScopes; 078 this.managedOptionals = managedOptionals; 079 this.managedLocalPaths = managedLocalPaths; 080 this.managedExclusions = managedExclusions; 081 } 082 083 public DependencyManager deriveChildManager( DependencyCollectionContext context ) 084 { 085 requireNonNull( context, "context cannot be null" ); 086 if ( depth >= 2 ) 087 { 088 return this; 089 } 090 else if ( depth == 1 ) 091 { 092 return new ClassicDependencyManager( depth + 1, managedVersions, managedScopes, managedOptionals, 093 managedLocalPaths, managedExclusions ); 094 } 095 096 Map<Object, String> managedVersions = this.managedVersions; 097 Map<Object, String> managedScopes = this.managedScopes; 098 Map<Object, Boolean> managedOptionals = this.managedOptionals; 099 Map<Object, String> managedLocalPaths = this.managedLocalPaths; 100 Map<Object, Collection<Exclusion>> managedExclusions = this.managedExclusions; 101 102 for ( Dependency managedDependency : context.getManagedDependencies() ) 103 { 104 Artifact artifact = managedDependency.getArtifact(); 105 Object key = getKey( artifact ); 106 107 String version = artifact.getVersion(); 108 if ( version.length() > 0 && !managedVersions.containsKey( key ) ) 109 { 110 if ( managedVersions == this.managedVersions ) 111 { 112 managedVersions = new HashMap<>( this.managedVersions ); 113 } 114 managedVersions.put( key, version ); 115 } 116 117 String scope = managedDependency.getScope(); 118 if ( scope.length() > 0 && !managedScopes.containsKey( key ) ) 119 { 120 if ( managedScopes == this.managedScopes ) 121 { 122 managedScopes = new HashMap<>( this.managedScopes ); 123 } 124 managedScopes.put( key, scope ); 125 } 126 127 Boolean optional = managedDependency.getOptional(); 128 if ( optional != null && !managedOptionals.containsKey( key ) ) 129 { 130 if ( managedOptionals == this.managedOptionals ) 131 { 132 managedOptionals = new HashMap<>( this.managedOptionals ); 133 } 134 managedOptionals.put( key, optional ); 135 } 136 137 String localPath = managedDependency.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ); 138 if ( localPath != null && !managedLocalPaths.containsKey( key ) ) 139 { 140 if ( managedLocalPaths == this.managedLocalPaths ) 141 { 142 managedLocalPaths = new HashMap<>( this.managedLocalPaths ); 143 } 144 managedLocalPaths.put( key, localPath ); 145 } 146 147 Collection<Exclusion> exclusions = managedDependency.getExclusions(); 148 if ( !exclusions.isEmpty() ) 149 { 150 if ( managedExclusions == this.managedExclusions ) 151 { 152 managedExclusions = new HashMap<>( this.managedExclusions ); 153 } 154 Collection<Exclusion> managed = managedExclusions.computeIfAbsent( key, k -> new LinkedHashSet<>() ); 155 managed.addAll( exclusions ); 156 } 157 } 158 159 return new ClassicDependencyManager( depth + 1, managedVersions, managedScopes, managedOptionals, 160 managedLocalPaths, managedExclusions ); 161 } 162 163 public DependencyManagement manageDependency( Dependency dependency ) 164 { 165 requireNonNull( dependency, "dependency cannot be null" ); 166 DependencyManagement management = null; 167 168 Object key = getKey( dependency.getArtifact() ); 169 170 if ( depth >= 2 ) 171 { 172 String version = managedVersions.get( key ); 173 if ( version != null ) 174 { 175 management = new DependencyManagement(); 176 management.setVersion( version ); 177 } 178 179 String scope = managedScopes.get( key ); 180 if ( scope != null ) 181 { 182 if ( management == null ) 183 { 184 management = new DependencyManagement(); 185 } 186 management.setScope( scope ); 187 188 if ( !JavaScopes.SYSTEM.equals( scope ) 189 && dependency.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) != null ) 190 { 191 Map<String, String> properties = 192 new HashMap<>( dependency.getArtifact().getProperties() ); 193 properties.remove( ArtifactProperties.LOCAL_PATH ); 194 management.setProperties( properties ); 195 } 196 } 197 198 if ( ( JavaScopes.SYSTEM.equals( scope ) ) 199 || ( scope == null && JavaScopes.SYSTEM.equals( dependency.getScope() ) ) ) 200 { 201 String localPath = managedLocalPaths.get( key ); 202 if ( localPath != null ) 203 { 204 if ( management == null ) 205 { 206 management = new DependencyManagement(); 207 } 208 Map<String, String> properties = 209 new HashMap<>( dependency.getArtifact().getProperties() ); 210 properties.put( ArtifactProperties.LOCAL_PATH, localPath ); 211 management.setProperties( properties ); 212 } 213 } 214 215 Boolean optional = managedOptionals.get( key ); 216 if ( optional != null ) 217 { 218 if ( management == null ) 219 { 220 management = new DependencyManagement(); 221 } 222 management.setOptional( optional ); 223 } 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( Object obj ) 248 { 249 if ( this == obj ) 250 { 251 return true; 252 } 253 else if ( null == obj || !getClass().equals( obj.getClass() ) ) 254 { 255 return false; 256 } 257 258 ClassicDependencyManager that = (ClassicDependencyManager) obj; 259 return depth == that.depth && managedVersions.equals( that.managedVersions ) 260 && managedScopes.equals( that.managedScopes ) && managedOptionals.equals( that.managedOptionals ) 261 && managedExclusions.equals( that.managedExclusions ); 262 } 263 264 @Override 265 public int hashCode() 266 { 267 if ( hashCode == 0 ) 268 { 269 int hash = 17; 270 hash = hash * 31 + depth; 271 hash = hash * 31 + managedVersions.hashCode(); 272 hash = hash * 31 + managedScopes.hashCode(); 273 hash = hash * 31 + managedOptionals.hashCode(); 274 hash = hash * 31 + managedExclusions.hashCode(); 275 hashCode = hash; 276 } 277 return hashCode; 278 } 279 280 static class Key 281 { 282 283 private final Artifact artifact; 284 285 private final int hashCode; 286 287 Key( Artifact artifact ) 288 { 289 this.artifact = artifact; 290 291 int hash = 17; 292 hash = hash * 31 + artifact.getGroupId().hashCode(); 293 hash = hash * 31 + artifact.getArtifactId().hashCode(); 294 hashCode = hash; 295 } 296 297 @Override 298 public boolean equals( Object obj ) 299 { 300 if ( obj == this ) 301 { 302 return true; 303 } 304 else if ( !( obj instanceof Key ) ) 305 { 306 return false; 307 } 308 Key that = (Key) obj; 309 return artifact.getArtifactId().equals( that.artifact.getArtifactId() ) 310 && artifact.getGroupId().equals( that.artifact.getGroupId() ) 311 && artifact.getExtension().equals( that.artifact.getExtension() ) 312 && artifact.getClassifier().equals( that.artifact.getClassifier() ); 313 } 314 315 @Override 316 public int hashCode() 317 { 318 return hashCode; 319 } 320 321 } 322 323}