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