View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.start;
20  
21  import java.io.File;
22  import java.io.FileWriter;
23  import java.io.IOException;
24  import java.io.PrintWriter;
25  import java.util.Collection;
26  import java.util.List;
27  
28  /**
29   * Generate a graphviz dot graph of the modules found
30   */
31  public class ModuleGraphWriter
32  {
33      private String colorModuleBg;
34      private String colorEnabledBg;
35      private String colorTransitiveBg;
36      private String colorCellBg;
37      private String colorHeaderBg;
38      private String colorModuleFont;
39  
40      public ModuleGraphWriter()
41      {
42          colorModuleBg = "#B8FFB8";
43          colorEnabledBg = "#66FFCC";
44          colorTransitiveBg = "#66CC66";
45          colorCellBg = "#FFFFFF80";
46          colorHeaderBg = "#00000020";
47          colorModuleFont = "#888888";
48      }
49  
50      public void config(Props props)
51      {
52          String prefix = "jetty.graph.";
53          colorModuleBg = getProperty(props,prefix + "color.module.bg",colorModuleBg);
54          colorEnabledBg = getProperty(props,prefix + "color.enabled.bg",colorEnabledBg);
55          colorTransitiveBg = getProperty(props,prefix + "color.transitive.bg",colorTransitiveBg);
56          colorCellBg = getProperty(props,prefix + "color.cell.bg",colorCellBg);
57          colorHeaderBg = getProperty(props,prefix + "color.header.bg",colorHeaderBg);
58          colorModuleFont = getProperty(props,prefix + "color.font",colorModuleFont);
59      }
60  
61      private String getProperty(Props props, String key, String defVal)
62      {
63          String val = props.getString(key,defVal);
64          if (val == null)
65          {
66              return defVal;
67          }
68          val = val.trim();
69          if (val.length() <= 0)
70          {
71              return defVal;
72          }
73          return val;
74      }
75  
76      public void write(Modules modules, File outputFile) throws IOException
77      {
78          try (FileWriter writer = new FileWriter(outputFile,false); PrintWriter out = new PrintWriter(writer);)
79          {
80              writeHeaderMessage(out,outputFile);
81  
82              out.println();
83              out.println("digraph modules {");
84  
85              // Node Style
86              out.println("  node [color=gray, style=filled, shape=rectangle];");
87              out.println("  node [fontname=\"Verdana\", size=\"20,20\"];");
88              // Graph Style
89              out.println("  graph [");
90              out.println("    concentrate=false,");
91              out.println("    fontname=\"Verdana\",");
92              out.println("    fontsize = 20,");
93              out.println("    rankdir = LR,");
94              out.println("    ranksep = 1.5,");
95              out.println("    nodesep = .5,");
96              out.println("    style = bold,");
97              out.println("    labeljust = l,");
98              out.println("    label = \"Jetty Modules\",");
99              out.println("    ssize = \"20,40\"");
100             out.println("  ];");
101 
102             List<Module> enabled = modules.resolveEnabled();
103 
104             // Module Nodes
105             writeModules(out,modules,enabled);
106 
107             // Module Relationships
108             writeRelationships(out,modules,enabled);
109 
110             out.println("}");
111             out.println();
112         }
113     }
114 
115     private void writeHeaderMessage(PrintWriter out, File outputFile)
116     {
117         out.println("/*");
118         out.println(" * GraphViz Graph of Jetty Modules");
119         out.println(" * ");
120         out.println(" * Jetty: http://eclipse.org/jetty/");
121         out.println(" * GraphViz: http://graphviz.org/");
122         out.println(" * ");
123         out.println(" * To Generate Graph image using graphviz:");
124         String filename = outputFile.getName();
125         String basename = filename.substring(0,filename.indexOf('.'));
126         out.printf(" *   $ dot -Tpng -Goverlap=false -o %s.png %s%n",basename,filename);
127         out.println(" */");
128     }
129 
130     private void writeModuleDetailHeader(PrintWriter out, String header)
131     {
132         writeModuleDetailHeader(out,header,1);
133     }
134 
135     private void writeModuleDetailHeader(PrintWriter out, String header, int count)
136     {
137         out.printf("  <TR>");
138         out.printf("<TD BGCOLOR=\"%s\" ALIGN=\"LEFT\"><I>",colorHeaderBg);
139         out.printf("%s%s</I></TD>",header,count > 1?"s":"");
140         out.println("</TR>");
141     }
142 
143     private void writeModuleDetailLine(PrintWriter out, String line)
144     {
145         out.printf("  <TR>");
146         StringBuilder escape = new StringBuilder();
147         for(char c: line.toCharArray()) {
148             switch(c) {
149                 case '<': escape.append("&lt;"); break;
150                 case '>': escape.append("&gt;"); break;
151                 default:
152                     escape.append(c);
153                     break;
154             }
155         }
156         
157         out.printf("<TD BGCOLOR=\"%s\" ALIGN=\"LEFT\">%s</TD></TR>%n",colorCellBg,escape.toString());
158     }
159 
160     private void writeModuleNode(PrintWriter out, Module module, boolean resolved)
161     {
162         String color = colorModuleBg;
163         if (module.isEnabled())
164         {
165             // specifically enabled by config
166             color = colorEnabledBg;
167         }
168         else if (resolved)
169         {
170             // enabled by transitive reasons
171             color = colorTransitiveBg;
172         }
173 
174         out.printf("  \"%s\" [ color=\"%s\" label=<",module.getName(),color);
175         out.printf("<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"2\">%n");
176         out.printf("  <TR><TD ALIGN=\"LEFT\"><B>%s</B></TD></TR>%n",module.getName());
177 
178         if (module.isEnabled())
179         {
180             writeModuleDetailHeader(out,"ENABLED");
181             for (String source : module.getSources())
182             {
183                 writeModuleDetailLine(out,"via: " + source);
184             }
185         }
186         else if (resolved)
187         {
188             writeModuleDetailHeader(out,"TRANSITIVE");
189         }
190 
191         if (!module.getXmls().isEmpty())
192         {
193             List<String> xmls = module.getXmls();
194             writeModuleDetailHeader(out,"XML",xmls.size());
195             for (String xml : xmls)
196             {
197                 writeModuleDetailLine(out,xml);
198             }
199         }
200 
201         if (!module.getLibs().isEmpty())
202         {
203             List<String> libs = module.getLibs();
204             writeModuleDetailHeader(out,"LIB",libs.size());
205             for (String lib : libs)
206             {
207                 writeModuleDetailLine(out,lib);
208             }
209         }
210 
211         if (!module.getInitialise().isEmpty())
212         {
213             List<String> inis = module.getInitialise();
214             writeModuleDetailHeader(out,"INI Template",inis.size());
215         }
216 
217         out.printf("</TABLE>>];%n");
218     }
219 
220     private void writeModules(PrintWriter out, Modules allmodules, List<Module> enabled)
221     {
222         out.println();
223         out.println("  /* Modules */");
224         out.println();
225 
226         out.println("  node [ labeljust = l ];");
227 
228         for (int depth = 0; depth <= allmodules.getMaxDepth(); depth++)
229         {
230             out.println();
231             Collection<Module> depthModules = allmodules.getModulesAtDepth(depth);
232             if (depthModules.size() > 0)
233             {
234                 out.printf("  /* Level %d */%n",depth);
235                 out.println("  { rank = same;");
236                 for (Module module : depthModules)
237                 {
238                     boolean resolved = enabled.contains(module);
239                     writeModuleNode(out,module,resolved);
240                 }
241                 out.println("  }");
242             }
243         }
244     }
245 
246     private void writeRelationships(PrintWriter out, Modules modules, List<Module> enabled)
247     {
248         for (Module module : modules)
249         {
250             for (Module parent : module.getParentEdges())
251             {
252                 out.printf("    \"%s\" -> \"%s\";%n",module.getName(),parent.getName());
253             }
254         }
255     }
256 }