]> source.dussan.org Git - archiva.git/blob
d66027234f23605cc8186a14a0cdc211cda54c12
[archiva.git] /
1 package org.apache.maven.archiva.dependency.graph;
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 org.apache.commons.collections.CollectionUtils;
23 import org.apache.commons.collections.Predicate;
24 import org.apache.commons.collections.functors.AndPredicate;
25 import org.apache.commons.collections.functors.NotPredicate;
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.maven.archiva.dependency.graph.functors.NodePredicate;
28 import org.apache.maven.archiva.dependency.graph.functors.OrphanedNodePredicate;
29 import org.apache.maven.archiva.model.ArchivaProjectModel;
30 import org.apache.maven.archiva.model.ArtifactReference;
31 import org.apache.maven.archiva.model.Dependency;
32 import org.apache.maven.archiva.model.DependencyScope;
33 import org.apache.maven.archiva.model.Exclusion;
34 import org.apache.maven.archiva.model.VersionedReference;
35
36 import java.util.HashSet;
37 import java.util.Iterator;
38 import java.util.List;
39 import java.util.Set;
40
41 /**
42  * Utilities for manipulating the DependencyGraph. 
43  *
44  * @version $Id$
45  */
46 public class DependencyGraphUtils
47 {
48     /**
49      * Standard way to add a model to the graph.
50      * 
51      * NOTE: Used by archiva-repository-layer runtime and archiva-dependency-graph tests.
52      * 
53      * @param model the model to add
54      * @param graph the graph to add it to
55      * @param fromNode the node to add it from.
56      */
57     public static void addNodeFromModel( ArchivaProjectModel model, DependencyGraph graph, DependencyGraphNode fromNode )
58     {
59         if ( model == null )
60         {
61             throw new IllegalStateException( "Unable to add null model for "
62                 + DependencyGraphKeys.toKey( fromNode.getArtifact() ) );
63         }
64
65         if ( model.getRelocation() != null )
66         {
67             // We need to CHANGE this node.
68             ArtifactReference refTO = new ArtifactReference();
69
70             refTO.setGroupId( fromNode.getArtifact().getGroupId() );
71             refTO.setArtifactId( fromNode.getArtifact().getArtifactId() );
72             refTO.setVersion( fromNode.getArtifact().getVersion() );
73             refTO.setClassifier( fromNode.getArtifact().getClassifier() );
74             refTO.setType( fromNode.getArtifact().getType() );
75
76             VersionedReference relocation = model.getRelocation();
77
78             if ( StringUtils.isNotBlank( relocation.getGroupId() ) )
79             {
80                 refTO.setGroupId( relocation.getGroupId() );
81             }
82
83             if ( StringUtils.isNotBlank( relocation.getArtifactId() ) )
84             {
85                 refTO.setArtifactId( relocation.getArtifactId() );
86             }
87
88             if ( StringUtils.isNotBlank( relocation.getVersion() ) )
89             {
90                 refTO.setVersion( relocation.getVersion() );
91             }
92
93             DependencyGraphNode nodeTO = new DependencyGraphNode( refTO );
94
95             graph.addNode( nodeTO );
96             collapseNodes( graph, fromNode, nodeTO );
97             return;
98         }
99
100         boolean isRootNode = graph.getRootNode().equals( fromNode );
101
102         Iterator it;
103
104         if ( CollectionUtils.isNotEmpty( model.getDependencyManagement() ) )
105         {
106             it = model.getDependencyManagement().iterator();
107             while ( it.hasNext() )
108             {
109                 Dependency dependency = (Dependency) it.next();
110                 fromNode.addDependencyManagement( dependency );
111             }
112         }
113
114         if ( CollectionUtils.isNotEmpty( model.getDependencies() ) )
115         {
116             it = model.getDependencies().iterator();
117             while ( it.hasNext() )
118             {
119                 Dependency dependency = (Dependency) it.next();
120
121                 String scope = dependency.getScope();
122
123                 // Test scopes *NOT* from root node can be skipped.
124                 if ( DependencyScope.TEST.equals( scope ) && !isRootNode )
125                 {
126                     // skip add of test scope
127                     continue;
128                 }
129
130                 ArtifactReference artifactRef = new ArtifactReference();
131                 artifactRef.setGroupId( dependency.getGroupId() );
132                 artifactRef.setArtifactId( dependency.getArtifactId() );
133                 artifactRef.setVersion( dependency.getVersion() );
134                 artifactRef.setClassifier( dependency.getClassifier() );
135                 artifactRef.setType( dependency.getType() );
136
137                 DependencyGraphNode toNode = new DependencyGraphNode( artifactRef );
138
139                 if ( CollectionUtils.isNotEmpty( dependency.getExclusions() ) )
140                 {
141                     Iterator itexclusion = dependency.getExclusions().iterator();
142                     while ( itexclusion.hasNext() )
143                     {
144                         Exclusion exclusion = (Exclusion) itexclusion.next();
145                         toNode.addExclude( exclusion );
146                     }
147                 }
148
149                 if ( dependency.isFromParent() )
150                 {
151                     toNode.setFromParent( true );
152                 }
153
154                 // Add node (to)
155                 graph.addNode( toNode );
156
157                 DependencyGraphEdge edge = new DependencyGraphEdge( fromNode.getArtifact(), toNode.getArtifact() );
158                 edge.setScope( StringUtils.defaultIfEmpty( dependency.getScope(), DependencyScope.COMPILE ) );
159
160                 if ( dependency.isOptional() )
161                 {
162                     edge.setDisabled( true );
163                     edge.setDisabledType( DependencyGraph.DISABLED_OPTIONAL );
164                     edge.setDisabledReason( "Optional Dependency" );
165                 }
166
167                 graph.addEdge( edge );
168             }
169         }
170
171         fromNode.setResolved( true );
172         graph.addNode( fromNode );
173     }
174
175     /**
176      * Clean out any nodes that may have become orphaned in the graph.
177      * 
178      * @param graph the graph to check.
179      */
180     public static void cleanupOrphanedNodes( DependencyGraph graph )
181     {
182         boolean done = false;
183
184         Predicate orphanedNodePredicate = new OrphanedNodePredicate( graph );
185         Predicate notRootNode = NotPredicate.getInstance( new NodePredicate( graph.getRootNode().getArtifact() ) );
186         Predicate orphanedChildNodePredicate = AndPredicate.getInstance( notRootNode, orphanedNodePredicate );
187
188         while ( !done )
189         {
190             // Find orphaned node.
191             DependencyGraphNode orphanedNode = (DependencyGraphNode) CollectionUtils.find( graph.getNodes(),
192                                                                                            orphanedChildNodePredicate );
193
194             if ( orphanedNode == null )
195             {
196                 done = true;
197                 break;
198             }
199
200             // Remove edges FROM orphaned node.
201             List edgesFrom = graph.getEdgesFrom( orphanedNode );
202
203             Iterator it = edgesFrom.iterator();
204             while ( it.hasNext() )
205             {
206                 DependencyGraphEdge edge = (DependencyGraphEdge) it.next();
207                 graph.removeEdge( edge );
208             }
209
210             // Remove orphaned node.
211             graph.removeNode( orphanedNode );
212         }
213     }
214
215     /**
216      * Functionaly similar to {@link #collapseVersions(DependencyGraph, ArtifactReference, String, String)}, but 
217      * in a new, easier to use, format.
218      * 
219      * 1) Removes the FROM edges connected to the FROM node
220      * 2) Moves the TO edges connected to the FROM node to the TO node.
221      * 3) Removes the FROM node (which is now orphaned)  
222      *  
223      * @param graph the graph to perform operation on
224      * @param nodeFrom the node to collapse from
225      * @param nodeTo the node to collapse to
226      */
227     public static void collapseNodes( DependencyGraph graph, DependencyGraphNode nodeFROM, DependencyGraphNode nodeTO )
228     {
229         Iterator it;
230
231         Set edgesToRemove = new HashSet();
232
233         // 1) Remove all of the edge.from references from nodeFROM
234         List fromEdges = graph.getEdgesFrom( nodeFROM );
235         if ( CollectionUtils.isNotEmpty( fromEdges ) )
236         {
237             edgesToRemove.addAll( fromEdges );
238         }
239
240         // 2) Swing all of the edge.to references from nodeFROM to nodeTO.
241         //        System.out.println( "Swinging incoming edges from " + nodeFROM );
242         //        System.out.println( "                          to " + nodeTO );
243         List toEdges = graph.getEdgesTo( nodeFROM );
244         it = toEdges.iterator();
245         while ( it.hasNext() )
246         {
247             DependencyGraphEdge edge = (DependencyGraphEdge) it.next();
248
249             // Identify old edge to remove.
250             edgesToRemove.add( edge );
251
252             // Clone edge, set edge.to and add to graph.
253             DependencyGraphEdge newedge = clone( edge );
254             newedge.setNodeTo( nodeTO );
255             //            System.out.println( "   edge from: " + edge );
256             //            System.out.println( "          to: " + newedge );
257             graph.addEdge( newedge );
258         }
259
260         // Actually remove the old edges.
261         it = edgesToRemove.iterator();
262         while ( it.hasNext() )
263         {
264             DependencyGraphEdge edge = (DependencyGraphEdge) it.next();
265             graph.removeEdge( edge );
266         }
267
268         // 3) Remove the nodeFROM
269         graph.removeNode( nodeFROM );
270     }
271
272     /**
273      * Create a clone of an edge.
274      * 
275      * @param edge the edge to clone.
276      * @return the cloned edge.
277      */
278     public static DependencyGraphEdge clone( DependencyGraphEdge edge )
279     {
280         DependencyGraphEdge cloned = new DependencyGraphEdge( edge.getNodeFrom(), edge.getNodeTo() );
281         cloned.setDisabled( edge.isDisabled() );
282         cloned.setDisabledReason( edge.getDisabledReason() );
283         cloned.setDisabledType( edge.getDisabledType() );
284         cloned.setScope( edge.getScope() );
285
286         return cloned;
287     }
288 }