author | pliden |
Tue, 18 Sep 2018 22:46:35 +0200 | |
changeset 51794 | 4129f43607cb |
parent 47216 | 71c04702a3d5 |
child 52993 | 2626982cf4f7 |
permissions | -rw-r--r-- |
36511 | 1 |
/* |
2 |
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. |
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package build.tools.jigsaw; |
|
27 |
||
28 |
import java.io.IOException; |
|
29 |
import java.io.PrintStream; |
|
30 |
import java.lang.module.Configuration; |
|
31 |
import java.lang.module.ModuleDescriptor; |
|
32 |
import java.lang.module.ModuleFinder; |
|
33 |
import java.lang.module.ModuleReference; |
|
34 |
import java.lang.module.ResolvedModule; |
|
35 |
import java.nio.file.Files; |
|
36 |
import java.nio.file.Path; |
|
37 |
import java.nio.file.Paths; |
|
38 |
import java.util.Arrays; |
|
39 |
import java.util.Comparator; |
|
40 |
import java.util.Date; |
|
41 |
import java.util.Enumeration; |
|
42 |
import java.util.HashMap; |
|
43 |
import java.util.HashSet; |
|
44 |
import java.util.Map; |
|
45 |
import java.util.Set; |
|
46 |
import java.util.stream.Collectors; |
|
47 |
import java.util.zip.ZipEntry; |
|
48 |
import java.util.zip.ZipFile; |
|
49 |
import static java.lang.module.ModuleDescriptor.*; |
|
50 |
import static build.tools.jigsaw.ModuleSummary.HtmlDocument.Selector.*; |
|
51 |
import static build.tools.jigsaw.ModuleSummary.HtmlDocument.Division.*; |
|
52 |
||
53 |
public class ModuleSummary { |
|
40261
86a49ba76f52
8136930: Simplify use of module-system options by custom launchers
mchung
parents:
38457
diff
changeset
|
54 |
private static final String USAGE = "Usage: ModuleSummary --module-path <dir> -o <outfile> [--root mn]*"; |
36511 | 55 |
|
56 |
public static void main(String[] args) throws Exception { |
|
57 |
int i=0; |
|
58 |
Path modpath = null; |
|
59 |
Path outfile = null; |
|
60 |
Set<String> roots = new HashSet<>(); |
|
61 |
while (i < args.length && args[i].startsWith("-")) { |
|
62 |
String arg = args[i++]; |
|
63 |
switch (arg) { |
|
40261
86a49ba76f52
8136930: Simplify use of module-system options by custom launchers
mchung
parents:
38457
diff
changeset
|
64 |
case "--module-path": |
36511 | 65 |
modpath = Paths.get(args[i++]); |
66 |
break; |
|
67 |
case "-o": |
|
68 |
outfile = Paths.get(args[i++]); |
|
69 |
break; |
|
40261
86a49ba76f52
8136930: Simplify use of module-system options by custom launchers
mchung
parents:
38457
diff
changeset
|
70 |
case "--root": |
36511 | 71 |
roots.add(args[i++]); |
72 |
default: |
|
73 |
System.err.println(USAGE); |
|
74 |
System.exit(-1); |
|
75 |
} |
|
76 |
} |
|
77 |
if (outfile == null || modpath == null) { |
|
78 |
System.err.println(USAGE); |
|
79 |
System.exit(1); |
|
80 |
} |
|
81 |
Path dir = outfile.getParent() != null ? outfile.getParent() : Paths.get("."); |
|
82 |
Files.createDirectories(dir); |
|
83 |
||
84 |
Map<String, ModuleSummary> modules = new HashMap<>(); |
|
85 |
Set<ModuleReference> mrefs = ModuleFinder.ofSystem().findAll(); |
|
86 |
for (ModuleReference mref : mrefs) { |
|
87 |
String mn = mref.descriptor().name(); |
|
88 |
Path jmod = modpath.resolve(mn + ".jmod"); |
|
89 |
modules.put(mn, new ModuleSummary(mref, jmod)); |
|
90 |
} |
|
91 |
||
92 |
if (roots.isEmpty()) { |
|
93 |
roots.addAll(modules.keySet()); |
|
94 |
} |
|
95 |
genReport(outfile, modules, roots, "JDK Module Summary"); |
|
96 |
} |
|
97 |
||
98 |
static void genReport(Path outfile, Map<String, ModuleSummary> modules, Set<String> roots, String title) |
|
99 |
throws IOException |
|
100 |
{ |
|
101 |
Configuration cf = resolve(roots); |
|
102 |
try (PrintStream out = new PrintStream(Files.newOutputStream(outfile))) { |
|
103 |
HtmlDocument doc = new HtmlDocument(title, modules); |
|
104 |
Set<ModuleDescriptor> descriptors = cf.modules().stream() |
|
105 |
.map(ResolvedModule::reference) |
|
106 |
.map(ModuleReference::descriptor) |
|
107 |
.collect(Collectors.toSet()); |
|
108 |
doc.writeTo(out, descriptors); |
|
109 |
} |
|
110 |
} |
|
111 |
||
112 |
private final String name; |
|
113 |
private final ModuleDescriptor descriptor; |
|
114 |
private final JmodInfo jmodInfo; |
|
115 |
ModuleSummary(ModuleReference mref, Path jmod) throws IOException { |
|
116 |
this.name = mref.descriptor().name(); |
|
117 |
this.descriptor = mref.descriptor(); |
|
118 |
this.jmodInfo = new JmodInfo(jmod); |
|
119 |
} |
|
120 |
||
121 |
String name() { |
|
122 |
return name; |
|
123 |
} |
|
124 |
||
125 |
long uncompressedSize() { |
|
126 |
return jmodInfo.size; |
|
127 |
} |
|
128 |
||
129 |
long jmodFileSize() { |
|
130 |
return jmodInfo.filesize; // estimated compressed size |
|
131 |
} |
|
132 |
||
133 |
ModuleDescriptor descriptor() { |
|
134 |
return descriptor; |
|
135 |
} |
|
136 |
||
137 |
int numClasses() { |
|
138 |
return jmodInfo.classCount; |
|
139 |
} |
|
140 |
||
141 |
long classBytes() { |
|
142 |
return jmodInfo.classBytes; |
|
143 |
} |
|
144 |
||
145 |
int numResources() { |
|
146 |
return jmodInfo.resourceCount; |
|
147 |
} |
|
148 |
||
149 |
long resourceBytes() { |
|
150 |
return jmodInfo.resourceBytes; |
|
151 |
} |
|
152 |
||
153 |
int numConfigs() { |
|
154 |
return jmodInfo.configCount; |
|
155 |
} |
|
156 |
long configBytes() { |
|
157 |
return jmodInfo.configBytes; |
|
158 |
} |
|
159 |
int numCommands() { |
|
160 |
return jmodInfo.nativeCmds.size(); |
|
161 |
} |
|
162 |
||
163 |
long commandBytes() { |
|
164 |
return jmodInfo.nativeCmds.values().stream() |
|
165 |
.mapToLong(l -> l.longValue()).sum() - jmodInfo.debugInfoCmdBytes; |
|
166 |
} |
|
167 |
int numCommandsDebug() { |
|
168 |
return jmodInfo.debugInfoCmdCount; |
|
169 |
} |
|
170 |
long commandDebugBytes() { |
|
171 |
return jmodInfo.debugInfoCmdBytes; |
|
172 |
} |
|
173 |
int numNativeLibraries() { |
|
174 |
return jmodInfo.nativeLibs.size(); |
|
175 |
} |
|
176 |
||
177 |
long nativeLibrariesBytes() { |
|
178 |
return jmodInfo.nativeLibs.values().stream() |
|
179 |
.mapToLong(l -> l.longValue()).sum() - jmodInfo.debugInfoLibBytes; |
|
180 |
} |
|
181 |
int numNativeLibrariesDebug() { |
|
182 |
return jmodInfo.debugInfoLibCount; |
|
183 |
} |
|
184 |
||
185 |
long nativeLibrariesDebugBytes() { |
|
186 |
return jmodInfo.debugInfoLibBytes; |
|
187 |
} |
|
188 |
||
189 |
Map<String,Long> commands() { |
|
190 |
return jmodInfo.nativeCmds; |
|
191 |
} |
|
192 |
||
193 |
Map<String,Long> nativeLibs() { |
|
194 |
return jmodInfo.nativeLibs; |
|
195 |
} |
|
196 |
||
197 |
Map<String,Long> configFiles() { |
|
198 |
return jmodInfo.configFiles; |
|
199 |
} |
|
200 |
||
201 |
||
202 |
static class JmodInfo { |
|
203 |
final long size; |
|
204 |
final long filesize; |
|
205 |
final int classCount; |
|
206 |
final long classBytes; |
|
207 |
final int resourceCount; |
|
208 |
final long resourceBytes; |
|
209 |
final int configCount; |
|
210 |
final long configBytes; |
|
211 |
final int debugInfoLibCount; |
|
212 |
final long debugInfoLibBytes; |
|
213 |
final int debugInfoCmdCount; |
|
214 |
final long debugInfoCmdBytes; |
|
215 |
final Map<String,Long> configFiles = new HashMap<>(); |
|
216 |
final Map<String,Long> nativeCmds = new HashMap<>(); |
|
217 |
final Map<String,Long> nativeLibs = new HashMap<>(); |
|
218 |
||
219 |
JmodInfo(Path jmod) throws IOException { |
|
220 |
long total = 0; |
|
221 |
long cBytes = 0, rBytes = 0, cfBytes = 0, dizLibBytes = 0, dizCmdBytes = 0; |
|
222 |
int cCount = 0, rCount = 0, cfCount = 0, dizLibCount = 0, dizCmdCount = 0; |
|
223 |
try (ZipFile zf = new ZipFile(jmod.toFile())) { |
|
224 |
for (Enumeration<? extends ZipEntry> e = zf.entries(); e.hasMoreElements(); ) { |
|
225 |
ZipEntry ze = e.nextElement(); |
|
226 |
String fn = ze.getName(); |
|
227 |
int pos = fn.indexOf('/'); |
|
228 |
String dir = fn.substring(0, pos); |
|
229 |
String filename = fn.substring(fn.lastIndexOf('/') + 1); |
|
230 |
// name shown in the column |
|
231 |
String name = filename; |
|
232 |
||
233 |
long len = ze.getSize(); |
|
234 |
total += len; |
|
235 |
switch (dir) { |
|
236 |
case NATIVE_LIBS: |
|
237 |
nativeLibs.put(name, len); |
|
238 |
if (filename.endsWith(".diz")) { |
|
239 |
dizLibCount++; |
|
240 |
dizLibBytes += len; |
|
241 |
} |
|
242 |
break; |
|
243 |
case NATIVE_CMDS: |
|
244 |
nativeCmds.put(name, len); |
|
245 |
if (filename.endsWith(".diz")) { |
|
246 |
dizCmdCount++; |
|
247 |
dizCmdBytes += len; |
|
248 |
} |
|
249 |
break; |
|
250 |
case CLASSES: |
|
251 |
if (filename.endsWith(".class")) { |
|
252 |
cCount++; |
|
253 |
cBytes += len; |
|
254 |
} else { |
|
255 |
rCount++; |
|
256 |
rBytes += len; |
|
257 |
} |
|
258 |
break; |
|
259 |
case CONFIG: |
|
260 |
configFiles.put(name, len); |
|
261 |
cfCount++; |
|
262 |
cfBytes += len; |
|
263 |
break; |
|
264 |
default: |
|
265 |
break; |
|
266 |
} |
|
267 |
} |
|
268 |
this.filesize = jmod.toFile().length(); |
|
269 |
this.classCount = cCount; |
|
270 |
this.classBytes = cBytes; |
|
271 |
this.resourceCount = rCount; |
|
272 |
this.resourceBytes = rBytes; |
|
273 |
this.configCount = cfCount; |
|
274 |
this.configBytes = cfBytes; |
|
275 |
this.size = total; |
|
276 |
this.debugInfoLibCount = dizLibCount; |
|
277 |
this.debugInfoLibBytes = dizLibBytes; |
|
278 |
this.debugInfoCmdCount = dizCmdCount; |
|
279 |
this.debugInfoCmdBytes = dizCmdBytes; |
|
280 |
} |
|
281 |
} |
|
282 |
||
283 |
static final String NATIVE_LIBS = "native"; |
|
284 |
static final String NATIVE_CMDS = "bin"; |
|
285 |
static final String CLASSES = "classes"; |
|
286 |
static final String CONFIG = "conf"; |
|
287 |
||
288 |
static final String MODULE_ID = "module/id"; |
|
289 |
static final String MODULE_MAIN_CLASS = "module/main-class"; |
|
290 |
} |
|
291 |
||
292 |
static Configuration resolve(Set<String> roots) { |
|
293 |
return Configuration.empty() |
|
43712
5dfd0950317c
8173393: Module system implementation refresh (2/2017)
alanb
parents:
42338
diff
changeset
|
294 |
.resolve(ModuleFinder.ofSystem(), |
5dfd0950317c
8173393: Module system implementation refresh (2/2017)
alanb
parents:
42338
diff
changeset
|
295 |
ModuleFinder.of(), |
5dfd0950317c
8173393: Module system implementation refresh (2/2017)
alanb
parents:
42338
diff
changeset
|
296 |
roots); |
36511 | 297 |
} |
298 |
||
299 |
static class HtmlDocument { |
|
300 |
final String title; |
|
301 |
final Map<String, ModuleSummary> modules; |
|
42338
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
302 |
boolean requiresTransitiveNote = false; |
36511 | 303 |
boolean aggregatorNote = false; |
304 |
boolean totalBytesNote = false; |
|
305 |
HtmlDocument(String title, Map<String, ModuleSummary> modules) { |
|
306 |
this.title = title; |
|
307 |
this.modules = modules; |
|
308 |
} |
|
309 |
||
310 |
void writeTo(PrintStream out, Set<ModuleDescriptor> selectedModules) { |
|
311 |
out.format("<html><head>%n"); |
|
312 |
out.format("<title>%s</title>%n", title); |
|
313 |
// stylesheet |
|
314 |
Arrays.stream(HtmlDocument.STYLES).forEach(out::println); |
|
315 |
out.format("</head>%n"); |
|
316 |
||
317 |
// body begins |
|
318 |
out.format("<body>%n"); |
|
319 |
||
320 |
// title and date |
|
321 |
out.println(DOCTITLE.toString(title)); |
|
322 |
out.println(VERSION.toString(String.format("%tc", new Date()))); |
|
323 |
||
324 |
// total modules and sizes |
|
325 |
long totalBytes = selectedModules.stream() |
|
326 |
.map(ModuleDescriptor::name) |
|
327 |
.map(modules::get) |
|
328 |
.mapToLong(ModuleSummary::uncompressedSize) |
|
329 |
.sum(); |
|
330 |
String[] sections = new String[] { |
|
331 |
String.format("%s: %d", "Total modules", selectedModules.size()), |
|
332 |
String.format("%s: %,d bytes (%s %s)", "Total size", |
|
333 |
totalBytes, |
|
334 |
System.getProperty("os.name"), |
|
335 |
System.getProperty("os.arch")) |
|
336 |
}; |
|
337 |
out.println(SECTION.toString(sections)); |
|
338 |
||
339 |
// write table and header |
|
340 |
out.println(String.format("<table class=\"%s\">", MODULES)); |
|
341 |
out.println(header("Module", "Requires", "Exports", |
|
342 |
"Services", "Commands/Native Libraries/Configs")); |
|
343 |
||
344 |
// write contents - one row per module |
|
345 |
selectedModules.stream() |
|
346 |
.sorted(Comparator.comparing(ModuleDescriptor::name)) |
|
347 |
.map(m -> modules.get(m.name())) |
|
348 |
.map(ModuleTableRow::new) |
|
349 |
.forEach(table -> table.writeTo(out)); |
|
350 |
||
351 |
out.format("</table>"); // end table |
|
352 |
out.format("</body>"); |
|
353 |
out.println("</html>"); |
|
354 |
} |
|
355 |
||
356 |
String header(String... columns) { |
|
357 |
StringBuilder sb = new StringBuilder(); |
|
358 |
sb.append("<tr>"); |
|
359 |
Arrays.stream(columns) |
|
360 |
.forEach(cn -> sb.append(" <th>").append(cn).append("</th>").append("\n")); |
|
361 |
sb.append("</tr>"); |
|
362 |
return sb.toString(); |
|
363 |
} |
|
364 |
||
365 |
static enum Selector { |
|
366 |
MODULES("modules"), |
|
367 |
MODULE("module"), |
|
368 |
MODULE_DEF("code name def"), |
|
369 |
AGGREGATOR("code name def agg"), |
|
370 |
REQUIRES("code"), |
|
371 |
REQUIRES_PUBLIC("code reexp"), |
|
372 |
BR("br"), |
|
373 |
CODE("code"), |
|
374 |
NUMBER("number"),; |
|
375 |
final String name; |
|
376 |
Selector(String name) { |
|
377 |
this.name = name; |
|
378 |
} |
|
379 |
@Override |
|
380 |
public String toString() { |
|
381 |
return name; |
|
382 |
} |
|
383 |
} |
|
384 |
||
385 |
static enum Division { |
|
386 |
DOCTITLE("doctitle"), |
|
387 |
VERSION("versions"), |
|
388 |
SECTION("section"); |
|
389 |
final String name; |
|
390 |
||
391 |
Division(String name) { |
|
392 |
this.name = name; |
|
393 |
} |
|
394 |
||
395 |
public String toString(String... lines) { |
|
396 |
String value = Arrays.stream(lines).collect(Collectors.joining("<br>\n")); |
|
397 |
return "<div class=\"" + name + "\">" + value + "</div>"; |
|
398 |
} |
|
399 |
} |
|
400 |
||
401 |
class ModuleTableRow { |
|
402 |
private final ModuleSummary ms; |
|
403 |
private final Set<ModuleDescriptor> deps; |
|
404 |
private final int maxRows; |
|
405 |
private final boolean aggregator; |
|
406 |
ModuleTableRow(ModuleSummary ms) { |
|
407 |
this.ms = ms; |
|
408 |
Configuration cf = resolve(Set.of(ms.name())); |
|
409 |
this.deps = cf.modules().stream() |
|
410 |
.map(ResolvedModule::reference) |
|
411 |
.map(ModuleReference::descriptor) |
|
412 |
.collect(Collectors.toSet()); |
|
413 |
int count = (ms.numClasses() > 0 ? 1 : 0) + |
|
414 |
(ms.numResources() > 0 ? 1 : 0) + |
|
415 |
(ms.numConfigs() > 0 ? 1 : 0) + |
|
416 |
(ms.numNativeLibraries() > 0 ? 1 : 0) + |
|
417 |
(ms.numNativeLibrariesDebug() > 0 ? 1 : 0) + |
|
418 |
(ms.numCommands() > 0 ? 1 : 0) + |
|
419 |
(ms.numCommandsDebug() > 0 ? 1 : 0); |
|
420 |
this.aggregator = ms.numClasses() == 1 && count == 1; // only module-info.class |
|
421 |
||
422 |
// 5 fixed rows (name + 2 transitive count/size + 2 blank rows) |
|
423 |
this.maxRows = 5 + count + (aggregator && !aggregatorNote ? 2 : 0); |
|
424 |
} |
|
425 |
||
426 |
public void writeTo(PrintStream out) { |
|
427 |
out.println(String.format("<tr id=\"%s\" class=\"%s\">", ms.name(), MODULE)); |
|
428 |
out.println(moduleColumn()); |
|
429 |
out.println(requiresColumn()); |
|
430 |
out.println(exportsColumn()); |
|
431 |
out.println(servicesColumn()); |
|
432 |
out.println(otherSectionColumn()); |
|
433 |
out.println("</td>"); |
|
434 |
out.println("</tr>"); |
|
435 |
} |
|
436 |
||
437 |
public String moduleColumn() { |
|
438 |
// module name |
|
439 |
StringBuilder sb = new StringBuilder(" "); |
|
440 |
sb.append("<td>"); |
|
441 |
sb.append(String.format("<table class=\"%s\">", MODULE)).append("\n"); |
|
442 |
sb.append(moduleName(ms.name())); |
|
443 |
sb.append(blankRow()); |
|
444 |
// metadata |
|
445 |
sb.append(toTableRow("class", "classes", ms.numClasses(), ms.classBytes())); |
|
446 |
sb.append(toTableRow("resource", "resources", ms.numResources(), ms.resourceBytes())); |
|
447 |
sb.append(toTableRow("config", "configs", ms.numConfigs(), ms.configBytes())); |
|
448 |
sb.append(toTableRow("native library", "native libraries", |
|
449 |
ms.numNativeLibraries(), ms.nativeLibrariesBytes())); |
|
450 |
sb.append(toTableRow("native library debug", "native libraries debug", |
|
451 |
ms.numNativeLibrariesDebug(), ms.nativeLibrariesDebugBytes())); |
|
452 |
sb.append(toTableRow("command", "commands", ms.numCommands(), ms.commandBytes())); |
|
453 |
sb.append(toTableRow("command debug", "commands debug", |
|
454 |
ms.numCommandsDebug(), ms.commandDebugBytes())); |
|
455 |
sb.append(blankRow()); |
|
456 |
||
457 |
// transitive dependencies |
|
458 |
long reqBytes = deps.stream() |
|
459 |
.filter(d -> !d.name().equals(ms.name())) |
|
460 |
.mapToLong(d -> modules.get(d.name()).uncompressedSize()) |
|
461 |
.sum(); |
|
462 |
long reqJmodFileSize = deps.stream() |
|
463 |
.mapToLong(d -> modules.get(d.name()).jmodFileSize()) |
|
464 |
.sum(); |
|
465 |
// size |
|
466 |
if (totalBytesNote) { |
|
467 |
sb.append(toTableRow("Total bytes", ms.uncompressedSize())); |
|
468 |
sb.append(toTableRow("Total bytes of dependencies", reqBytes)); |
|
469 |
} else { |
|
470 |
// print footnote |
|
471 |
sb.append(toTableRow("Total bytes<sup>1</sup>", ms.uncompressedSize())); |
|
472 |
sb.append(toTableRow("Total bytes of dependencies<sup>2</sup>", reqBytes)); |
|
473 |
} |
|
474 |
String files = deps.size() == 1 ? "file" : "files"; |
|
475 |
sb.append(toTableRow(String.format("Total jmod bytes (%d %s)", deps.size(), files), reqJmodFileSize)); |
|
476 |
||
477 |
if (aggregator && !aggregatorNote) { |
|
478 |
aggregatorNote = true; |
|
479 |
sb.append(blankRow()); |
|
480 |
sb.append(toTableRow("<i>* aggregator is a module with module-info.class only</i>", BR)); |
|
481 |
} |
|
482 |
if (!totalBytesNote) { |
|
483 |
totalBytesNote = true; |
|
484 |
sb.append(blankRow()); |
|
485 |
sb.append(toTableRow("<i><sup>1</sup>sum of all files including debug files</i>", BR)); |
|
486 |
sb.append(toTableRow("<i><sup>2</sup>sum of direct and indirect dependencies</i>", BR)); |
|
487 |
} |
|
488 |
sb.append("</table>").append("</td>"); |
|
489 |
return sb.toString(); |
|
490 |
} |
|
491 |
||
492 |
private String moduleName(String mn) { |
|
493 |
if (aggregator) { |
|
494 |
StringBuilder sb = new StringBuilder(); |
|
495 |
sb.append(String.format("<tr><td colspan=\"2\"><span class=\"%s\">", AGGREGATOR)) |
|
496 |
.append(mn) |
|
497 |
.append("</span>").append(" "); |
|
498 |
if (!aggregatorNote) { |
|
499 |
sb.append("(aggregator<sup>*</sup>)"); |
|
500 |
} else { |
|
501 |
sb.append("(aggregator)"); |
|
502 |
} |
|
503 |
sb.append("</td></tr>"); |
|
504 |
return sb.toString(); |
|
505 |
} else { |
|
506 |
return toTableRow(mn, MODULE_DEF); |
|
507 |
} |
|
508 |
} |
|
509 |
||
510 |
public String requiresColumn() { |
|
511 |
StringBuilder sb = new StringBuilder(); |
|
512 |
sb.append(String.format("<td>")); |
|
42338
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
513 |
boolean footnote = requiresTransitiveNote; |
36511 | 514 |
ms.descriptor().requires().stream() |
515 |
.sorted(Comparator.comparing(Requires::name)) |
|
516 |
.forEach(r -> { |
|
42338
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
517 |
boolean requiresTransitive = r.modifiers().contains(Requires.Modifier.TRANSITIVE); |
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
518 |
Selector sel = requiresTransitive ? REQUIRES_PUBLIC : REQUIRES; |
36511 | 519 |
String req = String.format("<a class=\"%s\" href=\"#%s\">%s</a>", |
520 |
sel, r.name(), r.name()); |
|
42338
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
521 |
if (!requiresTransitiveNote && requiresTransitive) { |
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
522 |
requiresTransitiveNote = true; |
36511 | 523 |
req += "<sup>*</sup>"; |
524 |
} |
|
525 |
sb.append(req).append("\n").append("<br>"); |
|
526 |
}); |
|
527 |
||
528 |
if (!ms.name().equals("java.base")) { |
|
529 |
int directDeps = ms.descriptor().requires().size(); |
|
530 |
int indirectDeps = deps.size()-directDeps-1; |
|
531 |
for (int i=directDeps; i< (maxRows-1); i++) { |
|
532 |
sb.append("<br>"); |
|
533 |
} |
|
534 |
sb.append("<br>"); |
|
535 |
sb.append("<i>+").append(indirectDeps).append(" transitive dependencies</i>"); |
|
536 |
} |
|
42338
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
537 |
if (footnote != requiresTransitiveNote) { |
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
538 |
sb.append("<br><br>").append("<i>* bold denotes requires transitive</i>"); |
36511 | 539 |
} |
540 |
sb.append("</td>"); |
|
541 |
return sb.toString(); |
|
542 |
} |
|
543 |
||
544 |
public String exportsColumn() { |
|
545 |
StringBuilder sb = new StringBuilder(); |
|
546 |
sb.append(String.format(" <td class=\"%s\">", CODE)); |
|
547 |
ms.descriptor().exports().stream() |
|
548 |
.sorted(Comparator.comparing(Exports::source)) |
|
549 |
.filter(e -> !e.isQualified()) |
|
550 |
.forEach(e -> sb.append(e.source()).append("<br>").append("\n")); |
|
551 |
sb.append("</td>"); |
|
552 |
return sb.toString(); |
|
553 |
} |
|
554 |
||
555 |
public String servicesColumn() { |
|
556 |
StringBuilder sb = new StringBuilder(); |
|
557 |
sb.append(String.format(" <td class=\"%s\">", CODE)); |
|
558 |
ms.descriptor().uses().stream() |
|
559 |
.sorted() |
|
560 |
.forEach(s -> sb.append("uses ").append(s).append("<br>").append("\n")); |
|
42338
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
561 |
ms.descriptor().provides().stream() |
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
562 |
.sorted(Comparator.comparing(Provides::service)) |
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
563 |
.map(p -> String.format("provides %s<br> with %s", |
a60f280f803c
8169069: Module system implementation refresh (11/2016)
alanb
parents:
40261
diff
changeset
|
564 |
p.service(), p.providers())) |
36511 | 565 |
.forEach(p -> sb.append(p).append("<br>").append("\n")); |
566 |
sb.append("</td>"); |
|
567 |
return sb.toString(); |
|
568 |
} |
|
569 |
||
570 |
public String otherSectionColumn() { |
|
571 |
StringBuilder sb = new StringBuilder(); |
|
572 |
sb.append("<td>"); |
|
573 |
sb.append(String.format("<table class=\"%s\">", MODULE)).append("\n"); |
|
574 |
// commands |
|
575 |
if (ms.numCommands() > 0) { |
|
576 |
sb.append(toTableRow("bin/", CODE)); |
|
577 |
ms.commands().entrySet().stream() |
|
578 |
.sorted(Map.Entry.comparingByKey()) |
|
579 |
.forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE))); |
|
580 |
sb.append(blankRow()); |
|
581 |
} |
|
582 |
||
583 |
// native libraries |
|
584 |
if (ms.numNativeLibraries() > 0) { |
|
585 |
sb.append(toTableRow("lib/", CODE)); |
|
586 |
ms.nativeLibs().entrySet().stream() |
|
587 |
.sorted(Map.Entry.comparingByKey()) |
|
588 |
.forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE))); |
|
589 |
sb.append(blankRow()); |
|
590 |
} |
|
591 |
||
592 |
// config files |
|
593 |
if (ms.numConfigs() > 0) { |
|
594 |
sb.append(toTableRow("conf/", CODE)); |
|
595 |
ms.configFiles().entrySet().stream() |
|
596 |
.sorted(Map.Entry.comparingByKey()) |
|
597 |
.forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE))); |
|
598 |
} |
|
599 |
// totals |
|
600 |
sb.append("</table>").append("</td>"); |
|
601 |
return sb.toString(); |
|
602 |
} |
|
603 |
||
604 |
private String blankRow() { |
|
605 |
return toTableRow(" ", BR); |
|
606 |
} |
|
607 |
||
608 |
private String toTableRow(String col, Selector selector) { |
|
609 |
TableDataBuilder builder = new TableDataBuilder(); |
|
610 |
builder.colspan(selector, 2, col); |
|
611 |
return builder.build(); |
|
612 |
} |
|
613 |
||
614 |
private String toTableRow(String col1, long col2) { |
|
615 |
return toTableRow(col1, col2, BR); |
|
616 |
} |
|
617 |
||
618 |
private String toTableRow(String col1, long col2, Selector selector) { |
|
619 |
TableDataBuilder builder = new TableDataBuilder(); |
|
620 |
builder.data(selector, col1); |
|
621 |
builder.data(col2); |
|
622 |
return builder.build(); |
|
623 |
||
624 |
} |
|
625 |
||
626 |
private String toTableRow(String singular, String plural, int count, long bytes) { |
|
627 |
if (count == 0) { |
|
628 |
return ""; |
|
629 |
} |
|
630 |
TableDataBuilder builder = new TableDataBuilder(); |
|
631 |
if (count == 1) { |
|
632 |
builder.data(count + " " + singular); |
|
633 |
} else { |
|
634 |
builder.data(count + " " + plural); |
|
635 |
} |
|
636 |
builder.data(bytes); |
|
637 |
return builder.build(); |
|
638 |
} |
|
639 |
||
640 |
class TableDataBuilder { |
|
641 |
private final StringBuilder sb; |
|
642 |
TableDataBuilder() { |
|
643 |
this.sb = new StringBuilder("<tr>"); |
|
644 |
} |
|
645 |
TableDataBuilder data(String s) { |
|
646 |
data(BR, s); |
|
647 |
return this; |
|
648 |
} |
|
649 |
TableDataBuilder data(long num) { |
|
650 |
data(NUMBER, String.format("%,d", num)); |
|
651 |
return this; |
|
652 |
} |
|
653 |
TableDataBuilder colspan(Selector selector, int columns, String data) { |
|
654 |
sb.append("<td colspan=\"").append(columns).append("\">"); |
|
655 |
sb.append("<span class=\"").append(selector).append("\">"); |
|
656 |
sb.append(data).append("</span></td>"); |
|
657 |
return this; |
|
658 |
} |
|
659 |
||
660 |
TableDataBuilder data(Selector selector, String data) { |
|
661 |
sb.append("<td class=\"").append(selector).append("\">"); |
|
662 |
sb.append(data).append("</td>"); |
|
663 |
return this; |
|
664 |
} |
|
665 |
String build() { |
|
666 |
sb.append("</tr>"); |
|
667 |
return sb.toString(); |
|
668 |
} |
|
669 |
} |
|
670 |
} |
|
671 |
||
672 |
private static final String[] STYLES = new String[]{ |
|
673 |
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/.fonts/dejavu.css\"/>", |
|
674 |
"<style type=\"text/css\">", |
|
675 |
" HTML, BODY, DIV, SPAN, APPLET, OBJECT, IFRAME, H1, H2, H3, H4, H5, H6, P,", |
|
676 |
" BLOCKQUOTE, PRE, A, ABBR, ACRONYM, ADDRESS, BIG, CITE, CODE, DEL, DFN, EM,", |
|
677 |
" IMG, INS, KBD, Q, S, SAMP, SMALL, STRIKE, STRONG, SUB, SUP, TT, VAR, B, U,", |
|
678 |
" I, CENTER, DL, DT, DD, OL, UL, LI, FIELDSET, FORM, LABEL, LEGEND, TABLE,", |
|
679 |
" CAPTION, TBODY, TFOOT, THEAD, TR, TH, TD, ARTICLE, ASIDE, CANVAS, DETAILS,", |
|
680 |
" EMBED, FIGURE, FIGCAPTION, FOOTER, HEADER, HGROUP, MENU, NAV, OUTPUT, RUBY,", |
|
681 |
" SECTION, SUMMARY, TIME, MARK, AUDIO, VIDEO {", |
|
682 |
" margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit;", |
|
683 |
" vertical-align: baseline; }", |
|
684 |
" ARTICLE, ASIDE, DETAILS, FIGCAPTION, FIGURE, ", |
|
685 |
" FOOTER, HEADER, HGROUP, MENU, NAV, SECTION { display: block; }", |
|
686 |
" BLOCKQUOTE, Q { quotes: none; }", |
|
687 |
" BLOCKQUOTE:before, BLOCKQUOTE:after, Q:before, Q:after {", |
|
688 |
" content: ''; content: none; }", |
|
689 |
" TABLE { border-collapse: collapse; border-spacing: 0; }", |
|
690 |
" A { text-decoration: none; }", |
|
691 |
" A:link { color: #437291; }", |
|
692 |
" A:visited { color: #666666; }", |
|
693 |
" A.anchor:link, A.anchor:visited { color: black; }", |
|
694 |
" A[href]:hover { color: #e76f00; }", |
|
695 |
" A IMG { border-width: 0px; }", |
|
696 |
" HTML { font-size: 20px; } /* baseline grid */", |
|
697 |
" HTML > BODY { font-size: 14px; }", |
|
698 |
" BODY {", |
|
699 |
" background: white;", |
|
700 |
" margin: 40px;", |
|
701 |
" margin-bottom: 150%;", |
|
702 |
" line-height: 20px;", |
|
703 |
" -webkit-text-size-adjust: 100%; /* iOS */", |
|
704 |
" color: #222;", |
|
705 |
" }", |
|
706 |
" BODY { font-family: \"DejaVu Serif\", \"Lucida Bright\", \"Bookman Old Style\",", |
|
707 |
" Georgia, serif; }", |
|
708 |
" CODE, TT, .jref, DIV.spec .open, TABLE.profiles {", |
|
709 |
" font-family: \"DejaVu Sans\", \"Lucida Sans\", Helvetica, sans-serif; }", |
|
710 |
" PRE, .code { font-family: \"DejaVu Sans Mono\", \"Bitstream Vera Sans Mono\",", |
|
711 |
" Monaco, \"Courier New\", monospace; }", |
|
712 |
" H1, H2, H3, H4 { color: green; font-weight: bold; }", |
|
713 |
" I { font-style: italic; }", |
|
714 |
" TH { font-weight: bold; }", |
|
715 |
" P { text-indent: 40px; }", |
|
716 |
" P:first-child, UL + P, OL + P, BLOCKQUOTE + P, TABLE + P, P.subsection,", |
|
717 |
" P.break, DIV.profiles-table + P { text-indent: 0; }", |
|
718 |
" P.break { margin-top: 10px; }", |
|
719 |
" P.subsection { margin-top: 20px; }", |
|
720 |
" P.subsection SPAN.title { font-weight: bold; padding-right: 20px; }", |
|
721 |
" UL, OL { margin: 10px 0; padding-left: 40px; }", |
|
722 |
" LI { margin-bottom: 10px; }", |
|
723 |
" UL.compact LI { margin-bottom: 0; }", |
|
724 |
" PRE { padding: 0; margin: 10px 0 10px 20px; background: #eee; width: 45em; }", |
|
725 |
" BLOCKQUOTE { margin: 10px 0; margin-left: 20px; }", |
|
726 |
" LI BLOCKQUOTE { margin-left: 0; }", |
|
727 |
" UL LI { list-style-type: square; }", |
|
728 |
" .todo { color: darkred; text-align: right; }", |
|
729 |
" .error { color: red; font-weight: bold; }", |
|
730 |
" .warn { color: #ee0000; font-weight: bold; }", |
|
731 |
" DIV.doctitle { margin-top: -13px;", |
|
732 |
" font-size: 22px; line-height: 40px; font-weight: bold; }", |
|
733 |
" DIV.twarn { color: #cc0000; font-weight: bold; margin-bottom: 9px; }", |
|
734 |
" DIV.subtitle { margin-top: 2px; font-size: 18px; font-weight: bold; }", |
|
735 |
" DIV.authors { margin-top: 10px; margin-bottom: 10px; font-size: 16px; }", |
|
736 |
" DIV.author A { font-style: italic; }", |
|
737 |
" DIV.version { margin-top: 10px; font-size: 12px; }", |
|
738 |
" DIV.version, DIV.legal-notice { font-size: 12px; line-height: 15px; }", |
|
739 |
" SPAN.hash { font-size: 9px; }", |
|
740 |
" DIV.version SPAN.modified { color: green; font-weight: bold; }", |
|
741 |
" DIV.head { margin-bottom: 20px; }", |
|
742 |
" DIV.section > DIV.title, DIV.section DIV.number SPAN {", |
|
743 |
" font-size: 15px; font-weight: bold; }", |
|
744 |
" TABLE { border-collapse: collapse; border: none; }", |
|
745 |
" TD.number { text-align: right; }", |
|
746 |
" TD, TH { text-align: left; white-space: nowrap; }", |
|
747 |
" TD.name, SPAN.name { font-weight: bold; }", |
|
748 |
" ", |
|
749 |
" TABLE.module { width: 100%; }", |
|
750 |
" TABLE.module TD:first-child { padding-right: 10px; }", |
|
751 |
" TR.module > TD { padding: 10px 0; border-top: 1px solid black; }", |
|
752 |
" TR > TH { padding-bottom: 10px; }", |
|
753 |
" TR.br TD { padding-top: 20px; }", |
|
754 |
" TABLE.modules { margin-top: 20px; }", |
|
755 |
" TABLE.modules > TBODY > TR > TD:nth-child(even) { background: #eee; }", |
|
756 |
" TABLE.modules > TBODY > TR > TD, TABLE.modules > TBODY > TR > TH {", |
|
757 |
" padding-left: 10px; padding-right: 10px; }", |
|
758 |
" .reexp, .def { font-weight: bold; }", |
|
759 |
" .agg { font-style: italic; }", |
|
760 |
" SUP { height: 0; line-height: 1; position: relative;", |
|
761 |
" vertical-align: baseline; bottom: 1ex; font-size: 11px; }", |
|
762 |
"</style>", |
|
763 |
}; |
|
764 |
} |
|
765 |
} |