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 }