001 package org.apache.maven.repository.metadata;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.util.ArrayList;
023 import java.util.List;
024 import java.util.TreeSet;
025
026 import org.apache.maven.artifact.ArtifactScopeEnum;
027 import org.codehaus.plexus.component.annotations.Component;
028 import org.codehaus.plexus.component.annotations.Requirement;
029
030 /**
031 * Default conflict resolver.Implements closer newer first policy by default, but could be configured via plexus
032 *
033 * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
034 */
035 @Component( role = GraphConflictResolver.class )
036 public class DefaultGraphConflictResolver
037 implements GraphConflictResolver
038 {
039 /**
040 * artifact, closer to the entry point, is selected
041 */
042 @Requirement( role = GraphConflictResolutionPolicy.class )
043 protected GraphConflictResolutionPolicy policy;
044
045 // -------------------------------------------------------------------------------------
046 // -------------------------------------------------------------------------------------
047 public MetadataGraph resolveConflicts( MetadataGraph graph, ArtifactScopeEnum scope )
048 throws GraphConflictResolutionException
049 {
050 if ( policy == null )
051 {
052 throw new GraphConflictResolutionException( "no GraphConflictResolutionPolicy injected" );
053 }
054
055 if ( graph == null )
056 {
057 return null;
058 }
059
060 final MetadataGraphVertex entry = graph.getEntry();
061 if ( entry == null )
062 {
063 return null;
064 }
065
066 if ( graph.isEmpty() )
067 {
068 throw new GraphConflictResolutionException( "graph with an entry, but not vertices do not exist" );
069 }
070
071 if ( graph.isEmptyEdges() )
072 {
073 return null; // no edges - nothing to worry about
074 }
075
076 final TreeSet<MetadataGraphVertex> vertices = graph.getVertices();
077
078 try
079 {
080 // edge case - single vertex graph
081 if ( vertices.size() == 1 )
082 {
083 return new MetadataGraph( entry );
084 }
085
086 final ArtifactScopeEnum requestedScope = ArtifactScopeEnum.checkScope( scope );
087
088 MetadataGraph res = new MetadataGraph( vertices.size() );
089 res.setVersionedVertices( false );
090 res.setScopedVertices( false );
091
092 MetadataGraphVertex resEntry = res.addVertex( entry.getMd() );
093 res.setEntry( resEntry );
094
095 res.setScope( requestedScope );
096
097 for ( MetadataGraphVertex v : vertices )
098 {
099 final List<MetadataGraphEdge> ins = graph.getIncidentEdges( v );
100 final MetadataGraphEdge edge = cleanEdges( v, ins, requestedScope );
101
102 if ( edge == null )
103 { // no edges - don't need this vertex any more
104 if ( entry.equals( v ) )
105 { // unless it's an entry point.
106 // currently processing the entry point - it should not have any entry incident edges
107 res.getEntry().getMd().setWhy( "This is a graph entry point. No links." );
108 }
109 else
110 {
111 // System.out.println("--->"+v.getMd().toDomainString()
112 // +" has been terminated on this entry set\n-------------------\n"
113 // +ins
114 // +"\n-------------------\n"
115 // );
116 }
117 }
118 else
119 {
120 // System.out.println("+++>"+v.getMd().toDomainString()+" still has "+edge.toString() );
121 // fill in domain md with actual version data
122 ArtifactMetadata md = v.getMd();
123 ArtifactMetadata newMd =
124 new ArtifactMetadata( md.getGroupId(), md.getArtifactId(), edge.getVersion(), md.getType(),
125 md.getScopeAsEnum(), md.getClassifier(), edge.getArtifactUri(),
126 edge.getSource() == null ? "" : edge.getSource().getMd().toString(),
127 edge.isResolved(), edge.getTarget() == null ? null
128 : edge.getTarget().getMd().getError() );
129 MetadataGraphVertex newV = res.addVertex( newMd );
130 MetadataGraphVertex sourceV = res.addVertex( edge.getSource().getMd() );
131
132 res.addEdge( sourceV, newV, edge );
133 }
134 }
135 MetadataGraph linkedRes = findLinkedSubgraph( res );
136 // System.err.println("Original graph("+graph.getVertices().size()+"):\n"+graph.toString());
137 // System.err.println("Cleaned("+requestedScope+") graph("+res.getVertices().size()+"):\n"+res.toString());
138 // System.err.println("Linked("+requestedScope+")
139 // subgraph("+linkedRes.getVertices().size()+"):\n"+linkedRes.toString());
140 return linkedRes;
141 }
142 catch ( MetadataResolutionException e )
143 {
144 throw new GraphConflictResolutionException( e );
145 }
146 }
147
148 // -------------------------------------------------------------------------------------
149 private MetadataGraph findLinkedSubgraph( MetadataGraph g )
150 {
151 if ( g.getVertices().size() == 1 )
152 {
153 return g;
154 }
155
156 List<MetadataGraphVertex> visited = new ArrayList<MetadataGraphVertex>( g.getVertices().size() );
157 visit( g.getEntry(), visited, g );
158
159 List<MetadataGraphVertex> dropList = new ArrayList<MetadataGraphVertex>( g.getVertices().size() );
160
161 // collect drop list
162 for ( MetadataGraphVertex v : g.getVertices() )
163 {
164 if ( !visited.contains( v ) )
165 {
166 dropList.add( v );
167 }
168 }
169
170 if ( dropList.size() < 1 )
171 {
172 return g;
173 }
174
175 // now - drop vertices
176 TreeSet<MetadataGraphVertex> vertices = g.getVertices();
177 for ( MetadataGraphVertex v : dropList )
178 {
179 vertices.remove( v );
180 }
181
182 return g;
183 }
184
185 // -------------------------------------------------------------------------------------
186 private void visit( MetadataGraphVertex from, List<MetadataGraphVertex> visited, MetadataGraph graph )
187 {
188 if ( visited.contains( from ) )
189 {
190 return;
191 }
192
193 visited.add( from );
194
195 List<MetadataGraphEdge> exitList = graph.getExcidentEdges( from );
196 // String s = "|---> "+from.getMd().toString()+" - "+(exitList == null ? -1 : exitList.size()) + " exit links";
197 if ( exitList != null && exitList.size() > 0 )
198 {
199 for ( MetadataGraphEdge e : graph.getExcidentEdges( from ) )
200 {
201 visit( e.getTarget(), visited, graph );
202 }
203 }
204 }
205
206 // -------------------------------------------------------------------------------------
207 private MetadataGraphEdge cleanEdges( MetadataGraphVertex v, List<MetadataGraphEdge> edges,
208 ArtifactScopeEnum scope )
209 {
210 if ( edges == null || edges.isEmpty() )
211 {
212 return null;
213 }
214
215 if ( edges.size() == 1 )
216 {
217 MetadataGraphEdge e = edges.get( 0 );
218 if ( scope.encloses( e.getScope() ) )
219 {
220 return e;
221 }
222
223 return null;
224 }
225
226 MetadataGraphEdge res = null;
227
228 for ( MetadataGraphEdge e : edges )
229 {
230 if ( !scope.encloses( e.getScope() ) )
231 {
232 continue;
233 }
234
235 if ( res == null )
236 {
237 res = e;
238 }
239 else
240 {
241 res = policy.apply( e, res );
242 }
243 }
244
245 return res;
246 }
247 // -------------------------------------------------------------------------------------
248 // -------------------------------------------------------------------------------------
249 }