1 package org.apache.maven.archiva.dependency.graph;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
22 import junit.framework.Assert;
23 import org.apache.commons.collections.CollectionUtils;
24 import org.apache.commons.lang.StringEscapeUtils;
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.maven.archiva.dependency.DependencyGraphFactory;
27 import org.apache.maven.archiva.model.DependencyScope;
28 import org.apache.maven.archiva.model.VersionedReference;
31 import java.io.FileWriter;
32 import java.io.IOException;
33 import java.io.PrintWriter;
34 import java.util.Iterator;
35 import java.util.List;
38 * GraphvizDotTool - testing utility to help understand the graph.
42 public class GraphvizDotTool
43 implements GraphListener
45 private int phaseNumber = 0;
47 protected VersionedReference toVersionedReference( String key )
49 String parts[] = StringUtils.splitPreserveAllTokens( key, ':' );
50 Assert.assertEquals( "Versioned Reference [" + key + "] part count.", 3, parts.length );
52 VersionedReference ref = new VersionedReference();
53 ref.setGroupId( parts[0] );
54 ref.setArtifactId( parts[1] );
55 ref.setVersion( parts[2] );
59 private DependencyGraph getDependencyGraph( MemoryRepository repository, String rootRefKey )
60 throws GraphTaskException
62 MemoryRepositoryDependencyGraphBuilder graphBuilder = new MemoryRepositoryDependencyGraphBuilder();
63 graphBuilder.setMemoryRepository( repository );
65 // Create the factory, and add the test resolver.
66 DependencyGraphFactory factory = new DependencyGraphFactory();
67 factory.setGraphBuilder( graphBuilder );
68 factory.setDesiredScope( DependencyScope.TEST );
69 factory.addGraphListener( this );
71 // Get the model to resolve from
72 VersionedReference rootRef = toVersionedReference( rootRefKey );
74 // Perform the resolution.
76 DependencyGraph graph = factory.getGraph( rootRef );
79 Assert.assertNotNull( "Graph shouldn't be null.", graph );
84 public void testGenerateDots()
85 throws GraphTaskException
87 getDependencyGraph( new ArchivaWebappMemoryRepository(),
88 "org.apache.maven.archiva:archiva-webapp:1.0-alpha-2-SNAPSHOT" );
90 // getDependencyGraph( new ArchivaCommonMemoryRepository(),
91 // "org.apache.maven.archiva:archiva-common:1.0-alpha-2-SNAPSHOT" );
93 // getDependencyGraph( new ArchivaXmlToolsMemoryRepository(),
94 // "org.apache.maven.archiva:archiva-xml-tools:1.0-alpha-2-SNAPSHOT" );
96 // getDependencyGraph( new ContinuumStoreMemoryRepository(),
97 // "org.apache.maven.continuum:continuum-store:1.1-SNAPSHOT" );
99 // getDependencyGraph( new MavenProjectInfoReportsPluginMemoryRepository(),
100 // "org.apache.maven.plugins:maven-project-info-reports-plugin:2.1-SNAPSHOT" );
102 // getDependencyGraph( new WagonManagerMemoryRepository(), "org.apache.maven.wagon:wagon-manager:2.0-SNAPSHOT" );
104 getDependencyGraph( new DepManDeepVersionMemoryRepository(), "net.example.depman.deepversion:A:1.0" );
107 public void dependencyResolutionEvent( DependencyResolutionEvent event )
112 public void graphError( GraphTaskException e, DependencyGraph currentGraph )
117 public void graphPhaseEvent( GraphPhaseEvent event )
119 String graphId = event.getGraph().getRootNode().getArtifact().getArtifactId();
120 String title = "Graph: " + graphId;
122 switch ( event.getType() )
124 case GraphPhaseEvent.GRAPH_TASK_POST:
126 title += " - Phase: " + phaseNumber + " - Task: " + event.getTask().getTaskId();
127 writeDot( "target/graph_" + graphId + "_" + phaseNumber + "_" + event.getTask().getTaskId() + ".dot",
128 event.getGraph(), title );
130 case GraphPhaseEvent.GRAPH_DONE:
131 title += " FINISHED";
132 writeDot( "target/graph_" + graphId + ".dot", event.getGraph(), title );
137 private void writeDot( String outputFilename, DependencyGraph graph, String title )
139 System.out.println( "Writing Graphviz output: " + outputFilename );
142 File outputFile = new File( outputFilename );
143 FileWriter writer = new FileWriter( outputFile );
144 PrintWriter dot = new PrintWriter( writer );
146 dot.println( "// Auto generated dot file from plexus-graph-visualizer-graphviz." );
148 dot.println( "digraph example {" );
152 dot.println( " // Graph Defaults" );
153 dot.println( " graph [" );
154 dot.println( " bgcolor=\"#ffffff\"," );
155 dot.println( " fontname=\"Helvetica\"," );
156 dot.println( " fontsize=\"11\"," );
157 dot.println( " label=\"" + title + "\"," );
158 dot.println( " labeljust=\"l\"" );
159 dot.println( " rankdir=\"LR\"" );
160 dot.println( " ];" );
165 dot.println( " // Node Defaults." );
166 dot.println( " node [" );
167 dot.println( " fontname=\"Helvetica\"," );
168 dot.println( " fontsize=\"11\"," );
169 dot.println( " shape=\"box\"" );
170 dot.println( " ];" );
175 dot.println( " // Edge Defaults." );
176 dot.println( " edge [" );
177 dot.println( " arrowsize=\"0.8\"" );
178 dot.println( " fontsize=\"11\"," );
179 dot.println( " ];" );
183 it = graph.getNodes().iterator();
184 while ( it.hasNext() )
186 DependencyGraphNode node = (DependencyGraphNode) it.next();
188 writeNode( dot, graph, node );
191 it = graph.getEdges().iterator();
192 while ( it.hasNext() )
194 DependencyGraphEdge edge = (DependencyGraphEdge) it.next();
196 DependencyGraphNode from = graph.getNode( edge.getNodeFrom() );
197 DependencyGraphNode to = graph.getNode( edge.getNodeTo() );
199 writeEdge( dot, edge, from, to );
206 catch ( IOException e )
208 System.err.println( "Unable to write GraphViz file " + outputFilename + " : " + e.getMessage() );
209 e.printStackTrace( System.err );
213 private String toLabel( DependencyGraphNode node )
215 StringBuffer lbl = new StringBuffer();
217 lbl.append( node.getArtifact().getGroupId() ).append( "\n" );
218 lbl.append( node.getArtifact().getArtifactId() ).append( "\n" );
219 lbl.append( node.getArtifact().getVersion() );
221 return StringEscapeUtils.escapeJava( lbl.toString() );
224 private String toId( DependencyGraphNode node )
226 StringBuffer id = new StringBuffer();
228 String raw = DependencyGraphKeys.toKey( node.getArtifact() );
230 for ( int i = 0; i < raw.length(); i++ )
232 char c = raw.charAt( i );
233 if ( Character.isLetterOrDigit( c ) )
235 id.append( Character.toUpperCase( c ) );
237 else if ( ( c == '-' ) || ( c == '_' ) )
243 return id.toString();
246 private void writeNode( PrintWriter dot, DependencyGraph graph, DependencyGraphNode node )
249 dot.println( " // Node" );
250 dot.println( " \"" + toId( node ) + "\" [" );
251 dot.println( " label=\"" + toLabel( node ) + "\"," );
253 List edgesTo = graph.getEdgesTo( node );
254 boolean orphan = CollectionUtils.isEmpty( edgesTo );
256 if ( node.isFromParent() )
258 dot.println( " color=\"#FF0000\"," );
259 dot.println( " shape=ellipse," );
263 dot.println( " shape=box," );
266 if ( node.isConflicted() )
268 // dot.println( " fontcolor=\"#FF88FF\"," );
269 dot.println( " style=filled," );
270 dot.println( " fillcolor=\"#88FF88\"," );
274 dot.println( " style=filled," );
275 dot.println( " fillcolor=\"#8888FF\"," );
278 dot.println( " ];" );
281 private void writeEdge( PrintWriter dot, DependencyGraphEdge edge, DependencyGraphNode from, DependencyGraphNode to )
284 dot.println( " // Edge" );
286 dot.println( " \"" + toId( from ) + "\" -> \"" + toId( to ) + "\" [" );
288 if ( edge.isDisabled() )
290 switch ( edge.getDisabledType() )
292 case DependencyGraph.DISABLED_CYCLIC:
293 dot.println( " color=\"#FF0000\"," );
295 case DependencyGraph.DISABLED_OPTIONAL:
296 dot.println( " color=\"#FF00FF\"," );
298 case DependencyGraph.DISABLED_NEARER_DEP:
299 dot.println( " color=\"#00FF00\"," );
301 case DependencyGraph.DISABLED_NEARER_EDGE:
302 dot.println( " color=\"#88FF88\"," );
305 case DependencyGraph.DISABLED_EXCLUDED:
306 dot.println( " color=\"#0000FF\"," );
310 dot.println( " label=\"" + edge.getDisabledReason() + "\"," );
311 dot.println( " fontsize=\"8\"," );
313 else if ( DependencyScope.TEST.equals( edge.getScope() ) )
315 dot.println( " style=\"dashed\"," );
316 dot.println( " color=\"#DDDDDD\"," );
318 else if ( DependencyScope.RUNTIME.equals( edge.getScope() ) )
320 dot.println( " style=\"dashed\"," );
321 dot.println( " color=\"#DDFFDD\"," );
322 dot.println( " label=\"runtime\"," );
323 dot.println( " fontsize=\"8\"," );
325 else if ( DependencyScope.PROVIDED.equals( edge.getScope() ) )
327 dot.println( " style=\"dashed\"," );
328 dot.println( " color=\"#DDDDFF\"," );
329 dot.println( " label=\"provided\"," );
330 dot.println( " fontsize=\"8\"," );
332 else if ( DependencyScope.SYSTEM.equals( edge.getScope() ) )
334 dot.println( " style=\"dashed\"," );
335 dot.println( " color=\"#FFDDDD\"," );
336 dot.println( " label=\"system\"," );
337 dot.println( " fontsize=\"8\"," );
340 dot.println( " arrowtail=none," );
341 dot.println( " arrowhead=normal" );
343 dot.println( " ];" );