1 package org.apache.maven.repository.metadata;
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.List;
24 import java.util.TreeSet;
25
26 import org.apache.maven.artifact.ArtifactScopeEnum;
27 import org.codehaus.plexus.component.annotations.Component;
28 import org.codehaus.plexus.component.annotations.Requirement;
29
30 /**
31 * Default conflict resolver.Implements closer newer first policy by default, but could be configured via plexus
32 *
33 * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
34 * @version $Id: DefaultGraphConflictResolver.java 958295 2010-06-26 23:16:18Z hboutemy $
35 */
36 @Component( role = GraphConflictResolver.class )
37 public class DefaultGraphConflictResolver
38 implements GraphConflictResolver
39 {
40 /**
41 * artifact, closer to the entry point, is selected
42 */
43 @Requirement( role = GraphConflictResolutionPolicy.class )
44 protected GraphConflictResolutionPolicy policy;
45
46 // -------------------------------------------------------------------------------------
47 // -------------------------------------------------------------------------------------
48 public MetadataGraph resolveConflicts( MetadataGraph graph, ArtifactScopeEnum scope )
49 throws GraphConflictResolutionException
50 {
51 if ( policy == null )
52 {
53 throw new GraphConflictResolutionException( "no GraphConflictResolutionPolicy injected" );
54 }
55
56 if ( graph == null )
57 {
58 return null;
59 }
60
61 final MetadataGraphVertex entry = graph.getEntry();
62 if ( entry == null )
63 {
64 return null;
65 }
66
67 if ( graph.isEmpty() )
68 {
69 throw new GraphConflictResolutionException( "graph with an entry, but not vertices do not exist" );
70 }
71
72 if ( graph.isEmptyEdges() )
73 {
74 return null; // no edges - nothing to worry about
75 }
76
77 final TreeSet<MetadataGraphVertex> vertices = graph.getVertices();
78
79 try
80 {
81 // edge case - single vertex graph
82 if ( vertices.size() == 1 )
83 {
84 return new MetadataGraph( entry );
85 }
86
87 final ArtifactScopeEnum requestedScope = ArtifactScopeEnum.checkScope( scope );
88
89 MetadataGraph res = new MetadataGraph( vertices.size() );
90 res.setVersionedVertices( false );
91 res.setScopedVertices( false );
92
93 MetadataGraphVertex resEntry = res.addVertex( entry.getMd() );
94 res.setEntry( resEntry );
95
96 res.setScope( requestedScope );
97
98 for ( MetadataGraphVertex v : vertices )
99 {
100 final List<MetadataGraphEdge> ins = graph.getIncidentEdges( v );
101 final MetadataGraphEdge edge = cleanEdges( v, ins, requestedScope );
102
103 if ( edge == null )
104 { // no edges - don't need this vertex any more
105 if ( entry.equals( v ) )
106 { // unless it's an entry point.
107 // currently processing the entry point - it should not have any entry incident edges
108 res.getEntry().getMd().setWhy( "This is a graph entry point. No links." );
109 }
110 else
111 {
112 // System.out.println("--->"+v.getMd().toDomainString()
113 // +" has been terminated on this entry set\n-------------------\n"
114 // +ins
115 // +"\n-------------------\n"
116 // );
117 }
118 }
119 else
120 {
121 // System.out.println("+++>"+v.getMd().toDomainString()+" still has "+edge.toString() );
122 // fill in domain md with actual version data
123 ArtifactMetadata md = v.getMd();
124 ArtifactMetadata newMd =
125 new ArtifactMetadata( md.getGroupId(), md.getArtifactId(), edge.getVersion(), md.getType(),
126 md.getScopeAsEnum(), md.getClassifier(), edge.getArtifactUri(),
127 edge.getSource() == null ? "" : edge.getSource().getMd().toString(),
128 edge.isResolved(), edge.getTarget() == null ? null
129 : edge.getTarget().getMd().getError() );
130 MetadataGraphVertex newV = res.addVertex( newMd );
131 MetadataGraphVertex sourceV = res.addVertex( edge.getSource().getMd() );
132
133 res.addEdge( sourceV, newV, edge );
134 }
135 }
136 MetadataGraph linkedRes = findLinkedSubgraph( res );
137 // System.err.println("Original graph("+graph.getVertices().size()+"):\n"+graph.toString());
138 // System.err.println("Cleaned("+requestedScope+") graph("+res.getVertices().size()+"):\n"+res.toString());
139 // System.err.println("Linked("+requestedScope+")
140 // subgraph("+linkedRes.getVertices().size()+"):\n"+linkedRes.toString());
141 return linkedRes;
142 }
143 catch ( MetadataResolutionException e )
144 {
145 throw new GraphConflictResolutionException( e );
146 }
147 }
148
149 // -------------------------------------------------------------------------------------
150 private MetadataGraph findLinkedSubgraph( MetadataGraph g )
151 {
152 if ( g.getVertices().size() == 1 )
153 {
154 return g;
155 }
156
157 List<MetadataGraphVertex> visited = new ArrayList<MetadataGraphVertex>( g.getVertices().size() );
158 visit( g.getEntry(), visited, g );
159
160 List<MetadataGraphVertex> dropList = new ArrayList<MetadataGraphVertex>( g.getVertices().size() );
161
162 // collect drop list
163 for ( MetadataGraphVertex v : g.getVertices() )
164 {
165 if ( !visited.contains( v ) )
166 {
167 dropList.add( v );
168 }
169 }
170
171 if ( dropList.size() < 1 )
172 {
173 return g;
174 }
175
176 // now - drop vertices
177 TreeSet<MetadataGraphVertex> vertices = g.getVertices();
178 for ( MetadataGraphVertex v : dropList )
179 {
180 vertices.remove( v );
181 }
182
183 return g;
184 }
185
186 // -------------------------------------------------------------------------------------
187 private void visit( MetadataGraphVertex from, List<MetadataGraphVertex> visited, MetadataGraph graph )
188 {
189 if ( visited.contains( from ) )
190 {
191 return;
192 }
193
194 visited.add( from );
195
196 List<MetadataGraphEdge> exitList = graph.getExcidentEdges( from );
197 // String s = "|---> "+from.getMd().toString()+" - "+(exitList == null ? -1 : exitList.size()) + " exit links";
198 if ( exitList != null && exitList.size() > 0 )
199 {
200 for ( MetadataGraphEdge e : graph.getExcidentEdges( from ) )
201 {
202 visit( e.getTarget(), visited, graph );
203 }
204 }
205 }
206
207 // -------------------------------------------------------------------------------------
208 private MetadataGraphEdge cleanEdges( MetadataGraphVertex v, List<MetadataGraphEdge> edges,
209 ArtifactScopeEnum scope )
210 {
211 if ( edges == null || edges.isEmpty() )
212 {
213 return null;
214 }
215
216 if ( edges.size() == 1 )
217 {
218 MetadataGraphEdge e = edges.get( 0 );
219 if ( scope.encloses( e.getScope() ) )
220 {
221 return e;
222 }
223
224 return null;
225 }
226
227 MetadataGraphEdge res = null;
228
229 for ( MetadataGraphEdge e : edges )
230 {
231 if ( !scope.encloses( e.getScope() ) )
232 {
233 continue;
234 }
235
236 if ( res == null )
237 {
238 res = e;
239 }
240 else
241 {
242 res = policy.apply( e, res );
243 }
244 }
245
246 return res;
247 }
248 // -------------------------------------------------------------------------------------
249 // -------------------------------------------------------------------------------------
250 }