1 package org.apache.maven.archiva.dependency.graph;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileWriter;
24 import java.io.IOException;
25 import java.io.PrintWriter;
26
27 import junit.framework.Assert;
28
29 import org.apache.commons.collections.CollectionUtils;
30 import org.apache.commons.lang.StringEscapeUtils;
31 import org.apache.commons.lang.StringUtils;
32 import org.apache.maven.archiva.dependency.DependencyGraphFactory;
33 import org.apache.maven.archiva.model.DependencyScope;
34 import org.apache.maven.archiva.model.VersionedReference;
35
36
37
38
39
40
41 public class GraphvizDotTool
42 implements GraphListener
43 {
44 private int phaseNumber = 0;
45
46 protected VersionedReference toVersionedReference( String key )
47 {
48 String parts[] = StringUtils.splitPreserveAllTokens( key, ':' );
49 Assert.assertEquals( "Versioned Reference [" + key + "] part count.", 3, parts.length );
50
51 VersionedReference ref = new VersionedReference();
52 ref.setGroupId( parts[0] );
53 ref.setArtifactId( parts[1] );
54 ref.setVersion( parts[2] );
55 return ref;
56 }
57
58 private DependencyGraph getDependencyGraph( MemoryRepository repository, String rootRefKey )
59 throws GraphTaskException
60 {
61 MemoryRepositoryDependencyGraphBuilder graphBuilder = new MemoryRepositoryDependencyGraphBuilder();
62 graphBuilder.setMemoryRepository( repository );
63
64
65 DependencyGraphFactory factory = new DependencyGraphFactory();
66 factory.setGraphBuilder( graphBuilder );
67 factory.setDesiredScope( DependencyScope.TEST );
68 factory.addGraphListener( this );
69
70
71 VersionedReference rootRef = toVersionedReference( rootRefKey );
72
73
74 phaseNumber = 0;
75 DependencyGraph graph = factory.getGraph( rootRef );
76
77
78 Assert.assertNotNull( "Graph shouldn't be null.", graph );
79
80 return graph;
81 }
82
83 public void testGenerateDots()
84 throws GraphTaskException
85 {
86 getDependencyGraph( new ArchivaWebappMemoryRepository(),
87 "org.apache.maven.archiva:archiva-webapp:1.0-alpha-2-SNAPSHOT" );
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 getDependencyGraph( new DepManDeepVersionMemoryRepository(), "net.example.depman.deepversion:A:1.0" );
104 }
105
106 public void dependencyResolutionEvent( DependencyResolutionEvent event )
107 {
108
109 }
110
111 public void graphError( GraphTaskException e, DependencyGraph currentGraph )
112 {
113
114 }
115
116 public void graphPhaseEvent( GraphPhaseEvent event )
117 {
118 String graphId = event.getGraph().getRootNode().getArtifact().getArtifactId();
119 String title = "Graph: " + graphId;
120
121 switch ( event.getType() )
122 {
123 case GraphPhaseEvent.GRAPH_TASK_POST:
124 phaseNumber++;
125 title += " - Phase: " + phaseNumber + " - Task: " + event.getTask().getTaskId();
126 writeDot( "target/graph_" + graphId + "_" + phaseNumber + "_" + event.getTask().getTaskId() + ".dot",
127 event.getGraph(), title );
128 break;
129 case GraphPhaseEvent.GRAPH_DONE:
130 title += " FINISHED";
131 writeDot( "target/graph_" + graphId + ".dot", event.getGraph(), title );
132 break;
133 }
134 }
135
136 private void writeDot( String outputFilename, DependencyGraph graph, String title )
137 {
138 System.out.println( "Writing Graphviz output: " + outputFilename );
139 try
140 {
141 File outputFile = new File( outputFilename );
142 FileWriter writer = new FileWriter( outputFile );
143 PrintWriter dot = new PrintWriter( writer );
144
145 dot.println( "// Auto generated dot file from plexus-graph-visualizer-graphviz." );
146
147 dot.println( "digraph example {" );
148
149 dot.println( "" );
150
151 dot.println( " // Graph Defaults" );
152 dot.println( " graph [" );
153 dot.println( " bgcolor=\"#ffffff\"," );
154 dot.println( " fontname=\"Helvetica\"," );
155 dot.println( " fontsize=\"11\"," );
156 dot.println( " label=\"" + title + "\"," );
157 dot.println( " labeljust=\"l\"" );
158 dot.println( " rankdir=\"LR\"" );
159 dot.println( " ];" );
160
161
162
163 dot.println( "" );
164 dot.println( " // Node Defaults." );
165 dot.println( " node [" );
166 dot.println( " fontname=\"Helvetica\"," );
167 dot.println( " fontsize=\"11\"," );
168 dot.println( " shape=\"box\"" );
169 dot.println( " ];" );
170
171
172
173 dot.println( "" );
174 dot.println( " // Edge Defaults." );
175 dot.println( " edge [" );
176 dot.println( " arrowsize=\"0.8\"" );
177 dot.println( " fontsize=\"11\"," );
178 dot.println( " ];" );
179
180 for ( DependencyGraphNode node : graph.getNodes() )
181 {
182 writeNode( dot, graph, node );
183 }
184
185 for ( DependencyGraphEdge edge : graph.getEdges() )
186 {
187 DependencyGraphNode from = graph.getNode( edge.getNodeFrom() );
188 DependencyGraphNode to = graph.getNode( edge.getNodeTo() );
189
190 writeEdge( dot, edge, from, to );
191 }
192
193 dot.println( "}" );
194 dot.flush();
195 dot.close();
196 }
197 catch ( IOException e )
198 {
199 System.err.println( "Unable to write GraphViz file " + outputFilename + " : " + e.getMessage() );
200 e.printStackTrace( System.err );
201 }
202 }
203
204 private String toLabel( DependencyGraphNode node )
205 {
206 StringBuffer lbl = new StringBuffer();
207
208 lbl.append( node.getArtifact().getGroupId() ).append( "\n" );
209 lbl.append( node.getArtifact().getArtifactId() ).append( "\n" );
210 lbl.append( node.getArtifact().getVersion() );
211
212 return StringEscapeUtils.escapeJava( lbl.toString() );
213 }
214
215 private String toId( DependencyGraphNode node )
216 {
217 StringBuffer id = new StringBuffer();
218
219 String raw = DependencyGraphKeys.toKey( node.getArtifact() );
220
221 for ( int i = 0; i < raw.length(); i++ )
222 {
223 char c = raw.charAt( i );
224 if ( Character.isLetterOrDigit( c ) )
225 {
226 id.append( Character.toUpperCase( c ) );
227 }
228 else if ( ( c == '-' ) || ( c == '_' ) )
229 {
230 id.append( "_" );
231 }
232 }
233
234 return id.toString();
235 }
236
237 private void writeNode( PrintWriter dot, DependencyGraph graph, DependencyGraphNode node )
238 {
239 dot.println( "" );
240 dot.println( " // Node" );
241 dot.println( " \"" + toId( node ) + "\" [" );
242 dot.println( " label=\"" + toLabel( node ) + "\"," );
243
244 boolean orphan = CollectionUtils.isEmpty( graph.getEdgesTo( node ) );
245
246 if ( node.isFromParent() )
247 {
248 dot.println( " color=\"#FF0000\"," );
249 dot.println( " shape=ellipse," );
250 }
251 else
252 {
253 dot.println( " shape=box," );
254 }
255
256 if ( node.isConflicted() )
257 {
258
259 dot.println( " style=filled," );
260 dot.println( " fillcolor=\"#88FF88\"," );
261 }
262 else if ( orphan )
263 {
264 dot.println( " style=filled," );
265 dot.println( " fillcolor=\"#8888FF\"," );
266 }
267
268 dot.println( " ];" );
269 }
270
271 private void writeEdge( PrintWriter dot, DependencyGraphEdge edge, DependencyGraphNode from, DependencyGraphNode to )
272 {
273 dot.println( "" );
274 dot.println( " // Edge" );
275
276 dot.println( " \"" + toId( from ) + "\" -> \"" + toId( to ) + "\" [" );
277
278 if ( edge.isDisabled() )
279 {
280 switch ( edge.getDisabledType() )
281 {
282 case DependencyGraph.DISABLED_CYCLIC:
283 dot.println( " color=\"#FF0000\"," );
284 break;
285 case DependencyGraph.DISABLED_OPTIONAL:
286 dot.println( " color=\"#FF00FF\"," );
287 break;
288 case DependencyGraph.DISABLED_NEARER_DEP:
289 dot.println( " color=\"#00FF00\"," );
290 break;
291 case DependencyGraph.DISABLED_NEARER_EDGE:
292 dot.println( " color=\"#88FF88\"," );
293 break;
294 default:
295 case DependencyGraph.DISABLED_EXCLUDED:
296 dot.println( " color=\"#0000FF\"," );
297 break;
298 }
299
300 dot.println( " label=\"" + edge.getDisabledReason() + "\"," );
301 dot.println( " fontsize=\"8\"," );
302 }
303 else if ( DependencyScope.TEST.equals( edge.getScope() ) )
304 {
305 dot.println( " style=\"dashed\"," );
306 dot.println( " color=\"#DDDDDD\"," );
307 }
308 else if ( DependencyScope.RUNTIME.equals( edge.getScope() ) )
309 {
310 dot.println( " style=\"dashed\"," );
311 dot.println( " color=\"#DDFFDD\"," );
312 dot.println( " label=\"runtime\"," );
313 dot.println( " fontsize=\"8\"," );
314 }
315 else if ( DependencyScope.PROVIDED.equals( edge.getScope() ) )
316 {
317 dot.println( " style=\"dashed\"," );
318 dot.println( " color=\"#DDDDFF\"," );
319 dot.println( " label=\"provided\"," );
320 dot.println( " fontsize=\"8\"," );
321 }
322 else if ( DependencyScope.SYSTEM.equals( edge.getScope() ) )
323 {
324 dot.println( " style=\"dashed\"," );
325 dot.println( " color=\"#FFDDDD\"," );
326 dot.println( " label=\"system\"," );
327 dot.println( " fontsize=\"8\"," );
328 }
329
330 dot.println( " arrowtail=none," );
331 dot.println( " arrowhead=normal" );
332
333 dot.println( " ];" );
334 }
335
336 }