]> source.dussan.org Git - archiva.git/blob
acf0a517cb09a4c04c68a4c524fe8dffba472802
[archiva.git] /
1 package org.apache.maven.archiva.dependency.graph.tasks;
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.Collection;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import org.apache.commons.collections.CollectionUtils;
33 import org.apache.commons.collections.MapUtils;
34 import org.apache.commons.collections.Predicate;
35 import org.apache.commons.collections.comparators.ReverseComparator;
36 import org.apache.commons.collections.functors.NotPredicate;
37 import org.apache.commons.collections.list.TypedList;
38 import org.apache.maven.archiva.common.utils.VersionComparator;
39 import org.apache.maven.archiva.dependency.graph.DependencyGraph;
40 import org.apache.maven.archiva.dependency.graph.DependencyGraphEdge;
41 import org.apache.maven.archiva.dependency.graph.DependencyGraphKeys;
42 import org.apache.maven.archiva.dependency.graph.DependencyGraphNode;
43 import org.apache.maven.archiva.dependency.graph.DependencyGraphUtils;
44 import org.apache.maven.archiva.dependency.graph.walk.BaseVisitor;
45 import org.apache.maven.archiva.dependency.graph.walk.DependencyGraphVisitor;
46 import org.apache.maven.archiva.model.ArtifactReference;
47
48 /**
49  * RefineConflictsVisitor 
50  *
51  * @version $Id$
52  */
53 public class RefineConflictsVisitor
54     extends BaseVisitor
55     implements DependencyGraphVisitor
56 {
57     class DepthComparator
58         implements Comparator<NodeLocation>
59     {
60         public int compare( NodeLocation obj0, NodeLocation obj1 )
61         {
62             return obj0.depth - obj1.depth;
63         }
64     }
65
66     class NodeLocation
67     {
68         public ArtifactReference artifact;
69
70         public DependencyGraphEdge edge;
71
72         public int depth;
73
74         public NodeLocation( ArtifactReference artifact, DependencyGraphEdge edge, int depth )
75         {
76             this.artifact = artifact;
77             this.edge = edge;
78             this.depth = depth;
79         }
80     }
81
82     class NodeLocationPredicate
83         implements Predicate
84     {
85         private ArtifactReference artifact;
86
87         public NodeLocationPredicate( ArtifactReference artifact )
88         {
89             this.artifact = artifact;
90         }
91
92         public NodeLocationPredicate( DependencyGraphNode node )
93         {
94             this( node.getArtifact() );
95         }
96
97         public boolean evaluate( Object object )
98         {
99             boolean satisfies = false;
100
101             if ( object instanceof NodeLocation )
102             {
103                 NodeLocation nodeloc = (NodeLocation) object;
104                 satisfies = nodeloc.artifact.equals( artifact );
105             }
106
107             return satisfies;
108         }
109
110     }
111
112     class NodeLocationVersionComparator
113         implements Comparator<NodeLocation>
114     {
115         public int compare( NodeLocation o1, NodeLocation o2 )
116         {
117             if ( o1 == null && o2 == null )
118             {
119                 return 0;
120             }
121
122             if ( o1 == null && o2 != null )
123             {
124                 return 1;
125             }
126
127             if ( o1 != null && o2 == null )
128             {
129                 return -1;
130             }
131
132 //            String version1 = o1.artifact.getVersion();
133 //            String version2 = o2.artifact.getVersion();
134 //
135 //            VersionComparator.getInstance().compare( version1, version2 );
136             
137             return 0;
138         }
139     }
140
141     class DistantNodeLocationPredicate
142         implements Predicate
143     {
144         private int cutoff;
145
146         public DistantNodeLocationPredicate( int distantCutoff )
147         {
148             this.cutoff = distantCutoff;
149         }
150
151         public boolean evaluate( Object object )
152         {
153             boolean satisfies = false;
154
155             if ( object instanceof NodeLocation )
156             {
157                 NodeLocation nodeloc = (NodeLocation) object;
158                 satisfies = ( nodeloc.depth >= this.cutoff );
159             }
160
161             return satisfies;
162         }
163     }
164
165     private List<DependencyGraphNode> conflictingArtifacts;
166
167     private Map<String,NodeLocation> foundNodesMap = new HashMap<String, NodeLocation>();
168
169     private int currentDepth = 0;
170
171     private DependencyGraph currentGraph;
172
173     @SuppressWarnings("unchecked")
174     public RefineConflictsVisitor()
175     {
176         conflictingArtifacts = TypedList.decorate( new ArrayList<ArtifactReference>(), ArtifactReference.class );
177     }
178
179     public void discoverGraph( DependencyGraph graph )
180     {
181         super.discoverGraph( graph );
182         this.currentGraph = graph;
183         this.foundNodesMap.clear();
184     }
185
186     public void discoverNode( DependencyGraphNode node )
187     {
188         super.discoverNode( node );
189
190         currentDepth++;
191
192         List<DependencyGraphEdge> edgesFrom = currentGraph.getEdgesFrom( node );
193         for ( DependencyGraphEdge edge : edgesFrom )
194         {
195             if ( this.conflictingArtifacts.contains( edge.getNodeTo() ) )
196             {
197                 String nodeKey = DependencyGraphKeys.toKey( edge.getNodeTo() );
198                 // Check for existing NodeLocation with same key
199                 NodeLocation nodeloc = this.foundNodesMap.get( nodeKey );
200
201                 if ( ( nodeloc == null ) || ( currentDepth < nodeloc.depth ) )
202                 {
203                     nodeloc = new NodeLocation( edge.getNodeTo(), edge, currentDepth );
204                     this.foundNodesMap.put( nodeKey, nodeloc );
205                 }
206             }
207         }
208     }
209
210     public void finishGraph( DependencyGraph graph )
211     {
212         super.finishGraph( graph );
213
214         if ( MapUtils.isEmpty( this.foundNodesMap ) )
215         {
216             return;
217         }
218
219         // Find winning node.
220         ArtifactReference winningArtifact = findWinningArtifact( this.foundNodesMap.values() );
221         DependencyGraphNode winningNode = graph.getNode( winningArtifact );
222
223         // Gather up Losing Nodes.
224         Set<NodeLocation> losingNodes = new HashSet<NodeLocation>();
225         Predicate losersPredicate = NotPredicate.getInstance( new NodeLocationPredicate( winningArtifact ) );
226         CollectionUtils.select( this.foundNodesMap.values(), losersPredicate, losingNodes );
227
228         // Swing losing nodes to winning node.
229         for ( NodeLocation losingNodeLoc : losingNodes )
230         {
231             DependencyGraphNode losingNode = graph.getNode( losingNodeLoc.artifact );
232             DependencyGraphUtils.collapseNodes( graph, losingNode, winningNode );
233         }
234     }
235
236     @SuppressWarnings("unchecked")
237     private ArtifactReference findWinningArtifact( Collection<NodeLocation> nodes )
238     {
239         List<NodeLocation> remainingNodes = new ArrayList<NodeLocation>();
240         remainingNodes.addAll( nodes );
241
242         /* .\ Filter by Depth \.____________________________________________________ */
243
244         // Sort by depth.
245         Collections.sort( remainingNodes, new DepthComparator() );
246
247         // Determine 'closest' node depth.
248         NodeLocation nearestNode = remainingNodes.get( 0 );
249         int nearest = nearestNode.depth;
250
251         // Filter out distant nodes. 
252         Predicate distantLocations = new DistantNodeLocationPredicate( nearest );
253         CollectionUtils.filter( remainingNodes, distantLocations );
254
255         // Do we have 1 node left?
256         if ( remainingNodes.size() == 1 )
257         {
258             // A winner!
259             NodeLocation nodeloc = remainingNodes.get( 0 );
260             return nodeloc.artifact;
261         }
262
263         /* .\ Filter by Newest Version \.___________________________________________ */
264
265         // We have 2 or more nodes that are equal distance from the root.
266         // Determine which one is 'newest' based on version id.
267         Collections.sort( remainingNodes, new ReverseComparator( new NodeLocationVersionComparator() ) );
268
269         NodeLocation nodeloc = remainingNodes.get( 0 );
270         return nodeloc.artifact;
271     }
272
273     public void finishNode( DependencyGraphNode node )
274     {
275         super.finishNode( node );
276         currentDepth--;
277     }
278
279     public List<DependencyGraphNode> getConflictingArtifacts()
280     {
281         return conflictingArtifacts;
282     }
283
284     public void addAllConflictingArtifacts( Collection<DependencyGraphNode> nodes )
285     {
286         this.conflictingArtifacts.addAll( nodes );
287     }
288
289     public void resetConflictingArtifacts()
290     {
291         this.conflictingArtifacts.clear();
292     }
293 }