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