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  /**
36   * ResolutionNode
37   */
38  public class ResolutionNode
39  {
40      private Artifact artifact;
41  
42      private List<ResolutionNode> children;
43  
44      private final List<Object> parents;
45  
46      private final int depth;
47  
48      private final ResolutionNode parent;
49  
50      private final List<ArtifactRepository> remoteRepositories;
51  
52      private boolean active = true;
53  
54      private List<Artifact> trail;
55  
56      public ResolutionNode( Artifact artifact, List<ArtifactRepository> remoteRepositories )
57      {
58          this.artifact = artifact;
59          this.remoteRepositories = remoteRepositories;
60          depth = 0;
61          parents = Collections.emptyList();
62          parent = null;
63      }
64  
65      public ResolutionNode( Artifact artifact, List<ArtifactRepository> remoteRepositories, ResolutionNode parent )
66      {
67          this.artifact = artifact;
68          this.remoteRepositories = remoteRepositories;
69          depth = parent.depth + 1;
70          parents = new ArrayList<>();
71          parents.addAll( parent.parents );
72          parents.add( parent.getKey() );
73          this.parent = parent;
74      }
75  
76      public Artifact getArtifact()
77      {
78          return artifact;
79      }
80  
81      public Object getKey()
82      {
83          return artifact.getDependencyConflictId();
84      }
85  
86      public void addDependencies( Set<Artifact> artifacts, List<ArtifactRepository> remoteRepositories,
87                                   ArtifactFilter filter )
88          throws CyclicDependencyException, OverConstrainedVersionException
89      {
90          if ( artifacts != null && !artifacts.isEmpty() )
91          {
92              children = new ArrayList<>( artifacts.size() );
93  
94              for ( Artifact a : artifacts )
95              {
96                  if ( parents.contains( a.getDependencyConflictId() ) )
97                  {
98                      a.setDependencyTrail( getDependencyTrail() );
99  
100                     throw new CyclicDependencyException( "A dependency has introduced a cycle", a );
101                 }
102 
103                 children.add( new ResolutionNode( a, remoteRepositories, this ) );
104             }
105             children = Collections.unmodifiableList( children );
106         }
107         else
108         {
109             children = Collections.emptyList();
110         }
111         trail = null;
112     }
113 
114     /**
115      * @return {@link List} &lt; {@link String} &gt; with artifact ids
116      * @throws OverConstrainedVersionException if version specification is over constrained
117      */
118     public List<String> getDependencyTrail()
119         throws OverConstrainedVersionException
120     {
121         List<Artifact> trial = getTrail();
122 
123         List<String> ret = new ArrayList<>( trial.size() );
124 
125         for ( Artifact artifact : trial )
126         {
127             ret.add( artifact.getId() );
128         }
129 
130         return ret;
131     }
132 
133     private List<Artifact> getTrail()
134         throws OverConstrainedVersionException
135     {
136         if ( trail == null )
137         {
138             List<Artifact> ids = new LinkedList<>();
139             ResolutionNode node = this;
140             while ( node != null )
141             {
142                 Artifact artifact = node.getArtifact();
143                 if ( artifact.getVersion() == null )
144                 {
145                     // set the recommended version
146                     ArtifactVersion selected = artifact.getSelectedVersion();
147                     // MNG-2123: null is a valid response to getSelectedVersion, don't
148                     // assume it won't ever be.
149                     if ( selected != null )
150                     {
151                         artifact.selectVersion( selected.toString() );
152                     }
153                     else
154                     {
155                         throw new OverConstrainedVersionException( "Unable to get a selected Version for "
156                             + artifact.getArtifactId(), artifact );
157                     }
158                 }
159 
160                 ids.add( 0, artifact );
161                 node = node.parent;
162             }
163             trail = ids;
164         }
165         return trail;
166     }
167 
168     public boolean isResolved()
169     {
170         return children != null;
171     }
172 
173     /**
174      * Test whether the node is direct or transitive dependency.
175      *
176      * @return whether the node is direct or transitive dependency
177      */
178     public boolean isChildOfRootNode()
179     {
180         return parent != null && parent.parent == null;
181     }
182 
183     public Iterator<ResolutionNode> getChildrenIterator()
184     {
185         return children.iterator();
186     }
187 
188     public int getDepth()
189     {
190         return depth;
191     }
192 
193     public List<ArtifactRepository> getRemoteRepositories()
194     {
195         return remoteRepositories;
196     }
197 
198     public boolean isActive()
199     {
200         return active;
201     }
202 
203     public void enable()
204     {
205         active = true;
206 
207         // TODO if it was null, we really need to go find them now... or is this taken care of by the ordering?
208         if ( children != null )
209         {
210             for ( ResolutionNode node : children )
211             {
212                 node.enable();
213             }
214         }
215     }
216 
217     public void disable()
218     {
219         active = false;
220         if ( children != null )
221         {
222             for ( ResolutionNode node : children )
223             {
224                 node.disable();
225             }
226         }
227     }
228 
229     public boolean filterTrail( ArtifactFilter filter )
230         throws OverConstrainedVersionException
231     {
232         boolean success = true;
233         if ( filter != null )
234         {
235             for ( Artifact artifact : getTrail() )
236             {
237                 if ( !filter.include( artifact ) )
238                 {
239                     success = false;
240                 }
241             }
242         }
243         return success;
244     }
245 
246     @Override
247     public String toString()
248     {
249         return artifact.toString() + " (" + depth + "; " + ( active ? "enabled" : "disabled" ) + ")";
250     }
251 
252     public void setArtifact( Artifact artifact )
253     {
254         this.artifact = artifact;
255     }
256 
257 }