package org.apache.maven.repository.metadata; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import org.apache.maven.artifact.ArtifactScopeEnum; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; /** * Default conflict resolver.Implements closer newer first policy by default, but could be configured via plexus * * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a> */ @Component( role = GraphConflictResolver.class ) public class DefaultGraphConflictResolver implements GraphConflictResolver { /** * artifact, closer to the entry point, is selected */ @Requirement( role = GraphConflictResolutionPolicy.class ) protected GraphConflictResolutionPolicy policy; // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- public MetadataGraph resolveConflicts( MetadataGraph graph, ArtifactScopeEnum scope ) throws GraphConflictResolutionException { if ( policy == null ) { throw new GraphConflictResolutionException( "no GraphConflictResolutionPolicy injected" ); } if ( graph == null ) { return null; } final MetadataGraphVertex entry = graph.getEntry(); if ( entry == null ) { return null; } if ( graph.isEmpty() ) { throw new GraphConflictResolutionException( "graph with an entry, but not vertices do not exist" ); } if ( graph.isEmptyEdges() ) { return null; // no edges - nothing to worry about } final TreeSet<MetadataGraphVertex> vertices = graph.getVertices(); try { // edge case - single vertex graph if ( vertices.size() == 1 ) { return new MetadataGraph( entry ); } final ArtifactScopeEnum requestedScope = ArtifactScopeEnum.checkScope( scope ); MetadataGraph res = new MetadataGraph( vertices.size() ); res.setVersionedVertices( false ); res.setScopedVertices( false ); MetadataGraphVertex resEntry = res.addVertex( entry.getMd() ); res.setEntry( resEntry ); res.setScope( requestedScope ); for ( MetadataGraphVertex v : vertices ) { final List<MetadataGraphEdge> ins = graph.getIncidentEdges( v ); final MetadataGraphEdge edge = cleanEdges( v, ins, requestedScope ); if ( edge == null ) { // no edges - don't need this vertex any more if ( entry.equals( v ) ) { // unless it's an entry point. // currently processing the entry point - it should not have any entry incident edges res.getEntry().getMd().setWhy( "This is a graph entry point. No links." ); } else { // System.out.println("--->"+v.getMd().toDomainString() // +" has been terminated on this entry set\n-------------------\n" // +ins // +"\n-------------------\n" // ); } } else { // System.out.println("+++>"+v.getMd().toDomainString()+" still has "+edge.toString() ); // fill in domain md with actual version data ArtifactMetadata md = v.getMd(); ArtifactMetadata newMd = new ArtifactMetadata( md.getGroupId(), md.getArtifactId(), edge.getVersion(), md.getType(), md.getScopeAsEnum(), md.getClassifier(), edge.getArtifactUri(), edge.getSource() == null ? "" : edge.getSource().getMd().toString(), edge.isResolved(), edge.getTarget() == null ? null : edge.getTarget().getMd().getError() ); MetadataGraphVertex newV = res.addVertex( newMd ); MetadataGraphVertex sourceV = res.addVertex( edge.getSource().getMd() ); res.addEdge( sourceV, newV, edge ); } } MetadataGraph linkedRes = findLinkedSubgraph( res ); // System.err.println("Original graph("+graph.getVertices().size()+"):\n"+graph.toString()); // System.err.println("Cleaned("+requestedScope+") graph("+res.getVertices().size()+"):\n"+res.toString()); // System.err.println("Linked("+requestedScope+") // subgraph("+linkedRes.getVertices().size()+"):\n"+linkedRes.toString()); return linkedRes; } catch ( MetadataResolutionException e ) { throw new GraphConflictResolutionException( e ); } } // ------------------------------------------------------------------------------------- private MetadataGraph findLinkedSubgraph( MetadataGraph g ) { if ( g.getVertices().size() == 1 ) { return g; } List<MetadataGraphVertex> visited = new ArrayList<MetadataGraphVertex>( g.getVertices().size() ); visit( g.getEntry(), visited, g ); List<MetadataGraphVertex> dropList = new ArrayList<MetadataGraphVertex>( g.getVertices().size() ); // collect drop list for ( MetadataGraphVertex v : g.getVertices() ) { if ( !visited.contains( v ) ) { dropList.add( v ); } } if ( dropList.size() < 1 ) { return g; } // now - drop vertices TreeSet<MetadataGraphVertex> vertices = g.getVertices(); for ( MetadataGraphVertex v : dropList ) { vertices.remove( v ); } return g; } // ------------------------------------------------------------------------------------- private void visit( MetadataGraphVertex from, List<MetadataGraphVertex> visited, MetadataGraph graph ) { if ( visited.contains( from ) ) { return; } visited.add( from ); List<MetadataGraphEdge> exitList = graph.getExcidentEdges( from ); // String s = "|---> "+from.getMd().toString()+" - "+(exitList == null ? -1 : exitList.size()) + " exit links"; if ( exitList != null && exitList.size() > 0 ) { for ( MetadataGraphEdge e : graph.getExcidentEdges( from ) ) { visit( e.getTarget(), visited, graph ); } } } // ------------------------------------------------------------------------------------- private MetadataGraphEdge cleanEdges( MetadataGraphVertex v, List<MetadataGraphEdge> edges, ArtifactScopeEnum scope ) { if ( edges == null || edges.isEmpty() ) { return null; } if ( edges.size() == 1 ) { MetadataGraphEdge e = edges.get( 0 ); if ( scope.encloses( e.getScope() ) ) { return e; } return null; } MetadataGraphEdge res = null; for ( MetadataGraphEdge e : edges ) { if ( !scope.encloses( e.getScope() ) ) { continue; } if ( res == null ) { res = e; } else { res = policy.apply( e, res ); } } return res; } // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- }