View Javadoc

1   package org.apache.maven.archiva.dependency.graph;
2   
3   /*
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
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
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
19   * under the License.
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   * GraphvizDotTool - testing utility to help understand the graph. 
38   *
39   * @version $Id: GraphvizDotTool.java 755277 2009-03-17 15:18:35Z brett $
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          // Create the factory, and add the test resolver.
65          DependencyGraphFactory factory = new DependencyGraphFactory();
66          factory.setGraphBuilder( graphBuilder );
67          factory.setDesiredScope( DependencyScope.TEST );
68          factory.addGraphListener( this );
69  
70          // Get the model to resolve from
71          VersionedReference rootRef = toVersionedReference( rootRefKey );
72  
73          // Perform the resolution.
74          phaseNumber = 0;
75          DependencyGraph graph = factory.getGraph( rootRef );
76  
77          // Test the results.
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          //        getDependencyGraph( new ArchivaCommonMemoryRepository(),
90          //                            "org.apache.maven.archiva:archiva-common:1.0-alpha-2-SNAPSHOT" );
91          //
92          //        getDependencyGraph( new ArchivaXmlToolsMemoryRepository(),
93          //                            "org.apache.maven.archiva:archiva-xml-tools:1.0-alpha-2-SNAPSHOT" );
94          //
95          //        getDependencyGraph( new ContinuumStoreMemoryRepository(),
96          //                            "org.apache.maven.continuum:continuum-store:1.1-SNAPSHOT" );
97          //
98          //        getDependencyGraph( new MavenProjectInfoReportsPluginMemoryRepository(),
99          //                            "org.apache.maven.plugins:maven-project-info-reports-plugin:2.1-SNAPSHOT" );
100         //
101         //        getDependencyGraph( new WagonManagerMemoryRepository(), "org.apache.maven.wagon:wagon-manager:2.0-SNAPSHOT" );
102 
103         getDependencyGraph( new DepManDeepVersionMemoryRepository(), "net.example.depman.deepversion:A:1.0" );
104     }
105 
106     public void dependencyResolutionEvent( DependencyResolutionEvent event )
107     {
108         /* do nothing */
109     }
110 
111     public void graphError( GraphTaskException e, DependencyGraph currentGraph )
112     {
113         /* do nothing */
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             // Node Defaults.
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             // Edge Defaults.
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             // dot.println( "    fontcolor=\"#FF88FF\"," );
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 }