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} &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<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    }