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