1 package org.apache.maven.archiva.dependency.graph.tasks;
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.MapUtils;
24 import org.apache.commons.collections.Predicate;
25 import org.apache.commons.collections.comparators.ReverseComparator;
26 import org.apache.commons.collections.functors.NotPredicate;
27 import org.apache.commons.collections.list.TypedList;
28 import org.apache.maven.archiva.common.utils.VersionComparator;
29 import org.apache.maven.archiva.dependency.graph.DependencyGraph;
30 import org.apache.maven.archiva.dependency.graph.DependencyGraphEdge;
31 import org.apache.maven.archiva.dependency.graph.DependencyGraphKeys;
32 import org.apache.maven.archiva.dependency.graph.DependencyGraphNode;
33 import org.apache.maven.archiva.dependency.graph.DependencyGraphUtils;
34 import org.apache.maven.archiva.dependency.graph.walk.BaseVisitor;
35 import org.apache.maven.archiva.dependency.graph.walk.DependencyGraphVisitor;
36 import org.apache.maven.archiva.model.ArtifactReference;
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.Comparator;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.List;
50 * RefineConflictsVisitor
54 public class RefineConflictsVisitor
56 implements DependencyGraphVisitor
61 public int compare( Object obj0, Object obj1 )
63 NodeLocation nodeLoc0 = (NodeLocation) obj0;
64 NodeLocation nodeLoc1 = (NodeLocation) obj1;
66 return nodeLoc0.depth - nodeLoc1.depth;
72 public ArtifactReference artifact;
74 public DependencyGraphEdge edge;
78 public NodeLocation( ArtifactReference artifact, DependencyGraphEdge edge, int depth )
80 this.artifact = artifact;
86 class NodeLocationPredicate
89 private ArtifactReference artifact;
91 public NodeLocationPredicate( ArtifactReference artifact )
93 this.artifact = artifact;
96 public NodeLocationPredicate( DependencyGraphNode node )
98 this( node.getArtifact() );
101 public boolean evaluate( Object object )
103 boolean satisfies = false;
105 if ( object instanceof NodeLocation )
107 NodeLocation nodeloc = (NodeLocation) object;
108 satisfies = nodeloc.artifact.equals( artifact );
116 class NodeLocationVersionComparator
117 implements Comparator
119 public int compare( Object o1, Object o2 )
121 if ( o1 == null && o2 == null )
126 if ( o1 == null && o2 != null )
131 if ( o1 != null && o2 == null )
136 if ( ( o1 instanceof NodeLocation ) && ( o2 instanceof NodeLocation ) )
138 String version1 = ( (NodeLocation) o1 ).artifact.getVersion();
139 String version2 = ( (NodeLocation) o2 ).artifact.getVersion();
141 VersionComparator.getInstance().compare( version1, version2 );
148 class DistantNodeLocationPredicate
153 public DistantNodeLocationPredicate( int distantCutoff )
155 this.cutoff = distantCutoff;
158 public boolean evaluate( Object object )
160 boolean satisfies = false;
162 if ( object instanceof NodeLocation )
164 NodeLocation nodeloc = (NodeLocation) object;
165 satisfies = ( nodeloc.depth >= this.cutoff );
172 private List conflictingArtifacts;
174 private Map foundNodesMap = new HashMap();
176 private int currentDepth = 0;
178 private DependencyGraph currentGraph;
180 public RefineConflictsVisitor()
182 conflictingArtifacts = TypedList.decorate( new ArrayList(), ArtifactReference.class );
185 public void discoverGraph( DependencyGraph graph )
187 super.discoverGraph( graph );
188 this.currentGraph = graph;
189 this.foundNodesMap.clear();
192 public void discoverNode( DependencyGraphNode node )
194 super.discoverNode( node );
198 List edgesFrom = currentGraph.getEdgesFrom( node );
199 Iterator it = edgesFrom.iterator();
200 while ( it.hasNext() )
202 DependencyGraphEdge edge = (DependencyGraphEdge) it.next();
203 if ( this.conflictingArtifacts.contains( edge.getNodeTo() ) )
205 String nodeKey = DependencyGraphKeys.toKey( edge.getNodeTo() );
206 // Check for existing NodeLocation with same key
207 NodeLocation nodeloc = (NodeLocation) this.foundNodesMap.get( nodeKey );
209 if ( ( nodeloc == null ) || ( currentDepth < nodeloc.depth ) )
211 nodeloc = new NodeLocation( edge.getNodeTo(), edge, currentDepth );
212 this.foundNodesMap.put( nodeKey, nodeloc );
218 public void finishGraph( DependencyGraph graph )
220 super.finishGraph( graph );
222 if ( MapUtils.isEmpty( this.foundNodesMap ) )
227 // Find winning node.
228 ArtifactReference winningArtifact = findWinningArtifact( this.foundNodesMap.values() );
229 DependencyGraphNode winningNode = graph.getNode( winningArtifact );
231 // Gather up Losing Nodes.
232 Set losingNodes = new HashSet();
233 Predicate losersPredicate = NotPredicate.getInstance( new NodeLocationPredicate( winningArtifact ) );
234 CollectionUtils.select( this.foundNodesMap.values(), losersPredicate, losingNodes );
236 // Swing losing nodes to winning node.
237 Iterator it = losingNodes.iterator();
238 while ( it.hasNext() )
240 NodeLocation losingNodeLoc = (NodeLocation) it.next();
241 DependencyGraphNode losingNode = graph.getNode( losingNodeLoc.artifact );
242 DependencyGraphUtils.collapseNodes( graph, losingNode, winningNode );
246 private ArtifactReference findWinningArtifact( Collection nodes )
248 List remainingNodes = new ArrayList();
249 remainingNodes.addAll( nodes );
251 /* .\ Filter by Depth \.____________________________________________________ */
254 Collections.sort( remainingNodes, new DepthComparator() );
256 // Determine 'closest' node depth.
257 NodeLocation nearestNode = (NodeLocation) remainingNodes.get( 0 );
258 int nearest = nearestNode.depth;
260 // Filter out distant nodes.
261 Predicate distantLocations = new DistantNodeLocationPredicate( nearest );
262 CollectionUtils.filter( remainingNodes, distantLocations );
264 // Do we have 1 node left?
265 if ( remainingNodes.size() == 1 )
268 NodeLocation nodeloc = (NodeLocation) remainingNodes.get( 0 );
269 return nodeloc.artifact;
272 /* .\ Filter by Newest Version \.___________________________________________ */
274 // We have 2 or more nodes that are equal distance from the root.
275 // Determine which one is 'newest' based on version id.
276 Collections.sort( remainingNodes, new ReverseComparator( new NodeLocationVersionComparator() ) );
278 NodeLocation nodeloc = (NodeLocation) remainingNodes.get( 0 );
279 return nodeloc.artifact;
282 public void finishNode( DependencyGraphNode node )
284 super.finishNode( node );
288 public List getConflictingArtifacts()
290 return conflictingArtifacts;
293 public void addAllConflictingArtifacts( Collection nodes )
295 this.conflictingArtifacts.addAll( nodes );
298 public void resetConflictingArtifacts()
300 this.conflictingArtifacts.clear();