View Javadoc
1   package org.apache.maven.artifact.resolver;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.LinkedList;
26  import java.util.List;
27  import java.util.Set;
28  
29  import org.apache.maven.artifact.Artifact;
30  import org.apache.maven.artifact.repository.ArtifactRepository;
31  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
32  import org.apache.maven.artifact.versioning.ArtifactVersion;
33  import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
34  
35  public class ResolutionNode
36  {
37      private Artifact artifact;
38  
39      private List<ResolutionNode> children;
40  
41      private final List<Object> parents;
42  
43      private final int depth;
44  
45      private final ResolutionNode parent;
46  
47      private final List<ArtifactRepository> remoteRepositories;
48  
49      private boolean active = true;
50  
51      private List<Artifact> trail;
52  
53      public ResolutionNode( Artifact artifact, List<ArtifactRepository> remoteRepositories )
54      {
55          this.artifact = artifact;
56          this.remoteRepositories = remoteRepositories;
57          depth = 0;
58          parents = Collections.emptyList();
59          parent = null;
60      }
61  
62      public ResolutionNode( Artifact artifact, List<ArtifactRepository> remoteRepositories, ResolutionNode parent )
63      {
64          this.artifact = artifact;
65          this.remoteRepositories = remoteRepositories;
66          depth = parent.depth + 1;
67          parents = new ArrayList<>();
68          parents.addAll( parent.parents );
69          parents.add( parent.getKey() );
70          this.parent = parent;
71      }
72  
73      public Artifact getArtifact()
74      {
75          return artifact;
76      }
77  
78      public Object getKey()
79      {
80          return artifact.getDependencyConflictId();
81      }
82  
83      public void addDependencies( Set<Artifact> artifacts, List<ArtifactRepository> remoteRepositories,
84                                   ArtifactFilter filter )
85          throws CyclicDependencyException, OverConstrainedVersionException
86      {
87          if ( artifacts != null && !artifacts.isEmpty() )
88          {
89              children = new ArrayList<>( artifacts.size() );
90  
91              for ( Artifact a : artifacts )
92              {
93                  if ( parents.contains( a.getDependencyConflictId() ) )
94                  {
95                      a.setDependencyTrail( getDependencyTrail() );
96  
97                      throw new CyclicDependencyException( "A dependency has introduced a cycle", a );
98                  }
99  
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} &lt; {@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<>( 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<>();
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 }