001package org.eclipse.aether.graph; 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.ArrayList; 023import java.util.Collection; 024import java.util.Collections; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Map; 028import static java.util.Objects.requireNonNull; 029 030import org.eclipse.aether.artifact.Artifact; 031import org.eclipse.aether.repository.RemoteRepository; 032import org.eclipse.aether.version.Version; 033import org.eclipse.aether.version.VersionConstraint; 034 035/** 036 * A node within a dependency graph. 037 */ 038public final class DefaultDependencyNode 039 implements DependencyNode 040{ 041 042 private List<DependencyNode> children; 043 044 private Dependency dependency; 045 046 private Artifact artifact; 047 048 private List<? extends Artifact> relocations; 049 050 private Collection<? extends Artifact> aliases; 051 052 private VersionConstraint versionConstraint; 053 054 private Version version; 055 056 private byte managedBits; 057 058 private List<RemoteRepository> repositories; 059 060 private String context; 061 062 private Map<Object, Object> data; 063 064 /** 065 * Creates a new node with the specified dependency. 066 * 067 * @param dependency The dependency associated with this node, may be {@code null} for a root node. 068 */ 069 public DefaultDependencyNode( Dependency dependency ) 070 { 071 this.dependency = dependency; 072 artifact = ( dependency != null ) ? dependency.getArtifact() : null; 073 children = new ArrayList<>( 0 ); 074 aliases = Collections.emptyList(); 075 relocations = Collections.emptyList(); 076 repositories = Collections.emptyList(); 077 context = ""; 078 data = Collections.emptyMap(); 079 } 080 081 /** 082 * Creates a new root node with the specified artifact as its label. Note that the new node has no dependency, i.e. 083 * {@link #getDependency()} will return {@code null}. Put differently, the specified artifact will not be subject to 084 * dependency collection/resolution. 085 * 086 * @param artifact The artifact to use as label for this node, may be {@code null}. 087 */ 088 public DefaultDependencyNode( Artifact artifact ) 089 { 090 this.artifact = artifact; 091 children = new ArrayList<>( 0 ); 092 aliases = Collections.emptyList(); 093 relocations = Collections.emptyList(); 094 repositories = Collections.emptyList(); 095 context = ""; 096 data = Collections.emptyMap(); 097 } 098 099 /** 100 * Creates a mostly shallow clone of the specified node. The new node has its own copy of any custom data and 101 * initially no children. 102 * 103 * @param node The node to copy, must not be {@code null}. 104 */ 105 public DefaultDependencyNode( DependencyNode node ) 106 { 107 dependency = node.getDependency(); 108 artifact = node.getArtifact(); 109 children = new ArrayList<>( 0 ); 110 setAliases( node.getAliases() ); 111 setRequestContext( node.getRequestContext() ); 112 setManagedBits( node.getManagedBits() ); 113 setRelocations( node.getRelocations() ); 114 setRepositories( node.getRepositories() ); 115 setVersion( node.getVersion() ); 116 setVersionConstraint( node.getVersionConstraint() ); 117 Map<?, ?> data = node.getData(); 118 setData( data.isEmpty() ? null : new HashMap<>( data ) ); 119 } 120 121 public List<DependencyNode> getChildren() 122 { 123 return children; 124 } 125 126 public void setChildren( List<DependencyNode> children ) 127 { 128 if ( children == null ) 129 { 130 this.children = new ArrayList<>( 0 ); 131 } 132 else 133 { 134 this.children = children; 135 } 136 } 137 138 public Dependency getDependency() 139 { 140 return dependency; 141 } 142 143 public Artifact getArtifact() 144 { 145 return artifact; 146 } 147 148 public void setArtifact( Artifact artifact ) 149 { 150 if ( dependency == null ) 151 { 152 throw new IllegalStateException( "node does not have a dependency" ); 153 } 154 dependency = dependency.setArtifact( artifact ); 155 this.artifact = dependency.getArtifact(); 156 } 157 158 public List<? extends Artifact> getRelocations() 159 { 160 return relocations; 161 } 162 163 /** 164 * Sets the sequence of relocations that was followed to resolve this dependency's artifact. 165 * 166 * @param relocations The sequence of relocations, may be {@code null}. 167 */ 168 public void setRelocations( List<? extends Artifact> relocations ) 169 { 170 if ( relocations == null || relocations.isEmpty() ) 171 { 172 this.relocations = Collections.emptyList(); 173 } 174 else 175 { 176 this.relocations = relocations; 177 } 178 } 179 180 public Collection<? extends Artifact> getAliases() 181 { 182 return aliases; 183 } 184 185 /** 186 * Sets the known aliases for this dependency's artifact. 187 * 188 * @param aliases The known aliases, may be {@code null}. 189 */ 190 public void setAliases( Collection<? extends Artifact> aliases ) 191 { 192 if ( aliases == null || aliases.isEmpty() ) 193 { 194 this.aliases = Collections.emptyList(); 195 } 196 else 197 { 198 this.aliases = aliases; 199 } 200 } 201 202 public VersionConstraint getVersionConstraint() 203 { 204 return versionConstraint; 205 } 206 207 /** 208 * Sets the version constraint that was parsed from the dependency's version declaration. 209 * 210 * @param versionConstraint The version constraint for this node, may be {@code null}. 211 */ 212 public void setVersionConstraint( VersionConstraint versionConstraint ) 213 { 214 this.versionConstraint = versionConstraint; 215 } 216 217 public Version getVersion() 218 { 219 return version; 220 } 221 222 /** 223 * Sets the version that was selected for the dependency's target artifact. 224 * 225 * @param version The parsed version, may be {@code null}. 226 */ 227 public void setVersion( Version version ) 228 { 229 this.version = version; 230 } 231 232 public void setScope( String scope ) 233 { 234 if ( dependency == null ) 235 { 236 throw new IllegalStateException( "node does not have a dependency" ); 237 } 238 dependency = dependency.setScope( scope ); 239 } 240 241 public void setOptional( Boolean optional ) 242 { 243 if ( dependency == null ) 244 { 245 throw new IllegalStateException( "node does not have a dependency" ); 246 } 247 dependency = dependency.setOptional( optional ); 248 } 249 250 public int getManagedBits() 251 { 252 return managedBits; 253 } 254 255 /** 256 * Sets a bit field indicating which attributes of this node were subject to dependency management. 257 * 258 * @param managedBits The bit field indicating the managed attributes or {@code 0} if dependency management wasn't 259 * applied. 260 */ 261 public void setManagedBits( int managedBits ) 262 { 263 this.managedBits = (byte) ( managedBits & 0x1F ); 264 } 265 266 public List<RemoteRepository> getRepositories() 267 { 268 return repositories; 269 } 270 271 /** 272 * Sets the remote repositories from which this node's artifact shall be resolved. 273 * 274 * @param repositories The remote repositories to use for artifact resolution, may be {@code null}. 275 */ 276 public void setRepositories( List<RemoteRepository> repositories ) 277 { 278 if ( repositories == null || repositories.isEmpty() ) 279 { 280 this.repositories = Collections.emptyList(); 281 } 282 else 283 { 284 this.repositories = repositories; 285 } 286 } 287 288 public String getRequestContext() 289 { 290 return context; 291 } 292 293 public void setRequestContext( String context ) 294 { 295 this.context = ( context != null ) ? context : ""; 296 } 297 298 public Map<Object, Object> getData() 299 { 300 return data; 301 } 302 303 public void setData( Map<Object, Object> data ) 304 { 305 if ( data == null ) 306 { 307 this.data = Collections.emptyMap(); 308 } 309 else 310 { 311 this.data = data; 312 } 313 } 314 315 public void setData( Object key, Object value ) 316 { 317 requireNonNull( key, "key cannot be null" ); 318 319 if ( value == null ) 320 { 321 if ( !data.isEmpty() ) 322 { 323 data.remove( key ); 324 325 if ( data.isEmpty() ) 326 { 327 data = Collections.emptyMap(); 328 } 329 } 330 } 331 else 332 { 333 if ( data.isEmpty() ) 334 { 335 data = new HashMap<>( 1, 2 ); // nodes can be numerous so let's be space conservative 336 } 337 data.put( key, value ); 338 } 339 } 340 341 public boolean accept( DependencyVisitor visitor ) 342 { 343 if ( visitor.visitEnter( this ) ) 344 { 345 for ( DependencyNode child : children ) 346 { 347 if ( !child.accept( visitor ) ) 348 { 349 break; 350 } 351 } 352 } 353 354 return visitor.visitLeave( this ); 355 } 356 357 @Override 358 public String toString() 359 { 360 Dependency dep = getDependency(); 361 if ( dep == null ) 362 { 363 return String.valueOf( getArtifact() ); 364 } 365 return dep.toString(); 366 } 367 368}