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
28
29
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
86 out.println(" node [color=gray, style=filled, shape=rectangle];");
87 out.println(" node [fontname=\"Verdana\", size=\"20,20\"];");
88
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
105 writeModules(out,modules,enabled);
106
107
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("<"); break;
150 case '>': escape.append(">"); 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
166 color = colorEnabledBg;
167 }
168 else if (resolved)
169 {
170
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 }