001 package org.apache.maven.artifact.resolver; 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 022 import java.util.ArrayList; 023 import java.util.Collections; 024 import java.util.Iterator; 025 import java.util.LinkedList; 026 import java.util.List; 027 import java.util.Set; 028 029 import org.apache.maven.artifact.Artifact; 030 import org.apache.maven.artifact.repository.ArtifactRepository; 031 import org.apache.maven.artifact.resolver.filter.ArtifactFilter; 032 import org.apache.maven.artifact.versioning.ArtifactVersion; 033 import org.apache.maven.artifact.versioning.OverConstrainedVersionException; 034 035 public class ResolutionNode 036 { 037 private Artifact artifact; 038 039 private List<ResolutionNode> children; 040 041 private final List<Object> parents; 042 043 private final int depth; 044 045 private final ResolutionNode parent; 046 047 private final List<ArtifactRepository> remoteRepositories; 048 049 private boolean active = true; 050 051 private List<Artifact> trail; 052 053 public ResolutionNode( Artifact artifact, List<ArtifactRepository> remoteRepositories ) 054 { 055 this.artifact = artifact; 056 this.remoteRepositories = remoteRepositories; 057 depth = 0; 058 parents = Collections.emptyList(); 059 parent = null; 060 } 061 062 public ResolutionNode( Artifact artifact, List<ArtifactRepository> remoteRepositories, ResolutionNode parent ) 063 { 064 this.artifact = artifact; 065 this.remoteRepositories = remoteRepositories; 066 depth = parent.depth + 1; 067 parents = new ArrayList<Object>(); 068 parents.addAll( parent.parents ); 069 parents.add( parent.getKey() ); 070 this.parent = parent; 071 } 072 073 public Artifact getArtifact() 074 { 075 return artifact; 076 } 077 078 public Object getKey() 079 { 080 return artifact.getDependencyConflictId(); 081 } 082 083 public void addDependencies( Set<Artifact> artifacts, List<ArtifactRepository> remoteRepositories, 084 ArtifactFilter filter ) 085 throws CyclicDependencyException, OverConstrainedVersionException 086 { 087 if ( artifacts != null && !artifacts.isEmpty() ) 088 { 089 children = new ArrayList<ResolutionNode>( artifacts.size() ); 090 091 for ( Artifact a : artifacts ) 092 { 093 if ( parents.contains( a.getDependencyConflictId() ) ) 094 { 095 a.setDependencyTrail( getDependencyTrail() ); 096 097 throw new CyclicDependencyException( "A dependency has introduced a cycle", a ); 098 } 099 100 children.add( new ResolutionNode( a, remoteRepositories, this ) ); 101 } 102 } 103 else 104 { 105 children = Collections.emptyList(); 106 } 107 trail = null; 108 } 109 110 /** 111 * @return {@link List} < {@link String} > with artifact ids 112 * @throws OverConstrainedVersionException 113 */ 114 public List<String> getDependencyTrail() 115 throws OverConstrainedVersionException 116 { 117 List<Artifact> trial = getTrail(); 118 119 List<String> ret = new ArrayList<String>( trial.size() ); 120 121 for ( Artifact artifact : trial ) 122 { 123 ret.add( artifact.getId() ); 124 } 125 126 return ret; 127 } 128 129 private List<Artifact> getTrail() 130 throws OverConstrainedVersionException 131 { 132 if ( trail == null ) 133 { 134 List<Artifact> ids = new LinkedList<Artifact>(); 135 ResolutionNode node = this; 136 while ( node != null ) 137 { 138 Artifact artifact = node.getArtifact(); 139 if ( artifact.getVersion() == null ) 140 { 141 // set the recommended version 142 ArtifactVersion selected = artifact.getSelectedVersion(); 143 // MNG-2123: null is a valid response to getSelectedVersion, don't 144 // assume it won't ever be. 145 if ( selected != null ) 146 { 147 artifact.selectVersion( selected.toString() ); 148 } 149 else 150 { 151 throw new OverConstrainedVersionException( "Unable to get a selected Version for " 152 + artifact.getArtifactId(), artifact ); 153 } 154 } 155 156 ids.add( 0, artifact ); 157 node = node.parent; 158 } 159 trail = ids; 160 } 161 return trail; 162 } 163 164 public boolean isResolved() 165 { 166 return children != null; 167 } 168 169 /** 170 * Test whether the node is direct or transitive dependency. 171 */ 172 public boolean isChildOfRootNode() 173 { 174 return parent != null && parent.parent == null; 175 } 176 177 public Iterator<ResolutionNode> getChildrenIterator() 178 { 179 return children.iterator(); 180 } 181 182 public int getDepth() 183 { 184 return depth; 185 } 186 187 public List<ArtifactRepository> getRemoteRepositories() 188 { 189 return remoteRepositories; 190 } 191 192 public boolean isActive() 193 { 194 return active; 195 } 196 197 public void enable() 198 { 199 active = true; 200 201 // TODO: if it was null, we really need to go find them now... or is this taken care of by the ordering? 202 if ( children != null ) 203 { 204 for ( ResolutionNode node : children ) 205 { 206 node.enable(); 207 } 208 } 209 } 210 211 public void disable() 212 { 213 active = false; 214 if ( children != null ) 215 { 216 for ( ResolutionNode node : children ) 217 { 218 node.disable(); 219 } 220 } 221 } 222 223 public boolean filterTrail( ArtifactFilter filter ) 224 throws OverConstrainedVersionException 225 { 226 boolean success = true; 227 if ( filter != null ) 228 { 229 for ( Artifact artifact : getTrail() ) 230 { 231 if ( !filter.include( artifact ) ) 232 { 233 success = false; 234 } 235 } 236 } 237 return success; 238 } 239 240 @Override 241 public String toString() 242 { 243 return artifact.toString() + " (" + depth + "; " + ( active ? "enabled" : "disabled" ) + ")"; 244 } 245 246 public void setArtifact( Artifact artifact ) 247 { 248 this.artifact = artifact; 249 } 250 251 }