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