1 package org.apache.maven.archiva.dependency.graph;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
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;
36 import java.util.HashSet;
37 import java.util.Iterator;
38 import java.util.List;
42 * Utilities for manipulating the DependencyGraph.
46 public class DependencyGraphUtils
49 * Standard way to add a model to the graph.
51 * NOTE: Used by archiva-repository-layer runtime and archiva-dependency-graph tests.
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.
57 public static void addNodeFromModel( ArchivaProjectModel model, DependencyGraph graph, DependencyGraphNode fromNode )
61 throw new IllegalStateException( "Unable to add null model for "
62 + DependencyGraphKeys.toKey( fromNode.getArtifact() ) );
65 if ( model.getRelocation() != null )
67 // We need to CHANGE this node.
68 ArtifactReference refTO = new ArtifactReference();
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() );
76 VersionedReference relocation = model.getRelocation();
78 if ( StringUtils.isNotBlank( relocation.getGroupId() ) )
80 refTO.setGroupId( relocation.getGroupId() );
83 if ( StringUtils.isNotBlank( relocation.getArtifactId() ) )
85 refTO.setArtifactId( relocation.getArtifactId() );
88 if ( StringUtils.isNotBlank( relocation.getVersion() ) )
90 refTO.setVersion( relocation.getVersion() );
93 DependencyGraphNode nodeTO = new DependencyGraphNode( refTO );
95 graph.addNode( nodeTO );
96 collapseNodes( graph, fromNode, nodeTO );
100 boolean isRootNode = graph.getRootNode().equals( fromNode );
104 if ( CollectionUtils.isNotEmpty( model.getDependencyManagement() ) )
106 it = model.getDependencyManagement().iterator();
107 while ( it.hasNext() )
109 Dependency dependency = (Dependency) it.next();
110 fromNode.addDependencyManagement( dependency );
114 if ( CollectionUtils.isNotEmpty( model.getDependencies() ) )
116 it = model.getDependencies().iterator();
117 while ( it.hasNext() )
119 Dependency dependency = (Dependency) it.next();
121 String scope = dependency.getScope();
123 // Test scopes *NOT* from root node can be skipped.
124 if ( DependencyScope.TEST.equals( scope ) && !isRootNode )
126 // skip add of test scope
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() );
137 DependencyGraphNode toNode = new DependencyGraphNode( artifactRef );
139 if ( CollectionUtils.isNotEmpty( dependency.getExclusions() ) )
141 Iterator itexclusion = dependency.getExclusions().iterator();
142 while ( itexclusion.hasNext() )
144 Exclusion exclusion = (Exclusion) itexclusion.next();
145 toNode.addExclude( exclusion );
149 if ( dependency.isFromParent() )
151 toNode.setFromParent( true );
155 graph.addNode( toNode );
157 DependencyGraphEdge edge = new DependencyGraphEdge( fromNode.getArtifact(), toNode.getArtifact() );
158 edge.setScope( StringUtils.defaultIfEmpty( dependency.getScope(), DependencyScope.COMPILE ) );
160 if ( dependency.isOptional() )
162 edge.setDisabled( true );
163 edge.setDisabledType( DependencyGraph.DISABLED_OPTIONAL );
164 edge.setDisabledReason( "Optional Dependency" );
167 graph.addEdge( edge );
171 fromNode.setResolved( true );
172 graph.addNode( fromNode );
176 * Clean out any nodes that may have become orphaned in the graph.
178 * @param graph the graph to check.
180 public static void cleanupOrphanedNodes( DependencyGraph graph )
182 boolean done = false;
184 Predicate orphanedNodePredicate = new OrphanedNodePredicate( graph );
185 Predicate notRootNode = NotPredicate.getInstance( new NodePredicate( graph.getRootNode().getArtifact() ) );
186 Predicate orphanedChildNodePredicate = AndPredicate.getInstance( notRootNode, orphanedNodePredicate );
190 // Find orphaned node.
191 DependencyGraphNode orphanedNode = (DependencyGraphNode) CollectionUtils.find( graph.getNodes(),
192 orphanedChildNodePredicate );
194 if ( orphanedNode == null )
200 // Remove edges FROM orphaned node.
201 List edgesFrom = graph.getEdgesFrom( orphanedNode );
203 Iterator it = edgesFrom.iterator();
204 while ( it.hasNext() )
206 DependencyGraphEdge edge = (DependencyGraphEdge) it.next();
207 graph.removeEdge( edge );
210 // Remove orphaned node.
211 graph.removeNode( orphanedNode );
216 * Functionaly similar to {@link #collapseVersions(DependencyGraph, ArtifactReference, String, String)}, but
217 * in a new, easier to use, format.
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)
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
227 public static void collapseNodes( DependencyGraph graph, DependencyGraphNode nodeFROM, DependencyGraphNode nodeTO )
231 Set edgesToRemove = new HashSet();
233 // 1) Remove all of the edge.from references from nodeFROM
234 List fromEdges = graph.getEdgesFrom( nodeFROM );
235 if ( CollectionUtils.isNotEmpty( fromEdges ) )
237 edgesToRemove.addAll( fromEdges );
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() )
247 DependencyGraphEdge edge = (DependencyGraphEdge) it.next();
249 // Identify old edge to remove.
250 edgesToRemove.add( edge );
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 );
260 // Actually remove the old edges.
261 it = edgesToRemove.iterator();
262 while ( it.hasNext() )
264 DependencyGraphEdge edge = (DependencyGraphEdge) it.next();
265 graph.removeEdge( edge );
268 // 3) Remove the nodeFROM
269 graph.removeNode( nodeFROM );
273 * Create a clone of an edge.
275 * @param edge the edge to clone.
276 * @return the cloned edge.
278 public static DependencyGraphEdge clone( DependencyGraphEdge edge )
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() );