001package 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 022import java.util.ArrayList; 023import java.util.List; 024import java.util.TreeSet; 025 026import org.apache.maven.artifact.ArtifactScopeEnum; 027import org.codehaus.plexus.component.annotations.Component; 028import 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 ) 036public 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<>( g.getVertices().size() ); 157 visit( g.getEntry(), visited, g ); 158 159 List<MetadataGraphVertex> dropList = new ArrayList<>( 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}