1
18 package net.bull.javamelody.internal.web.pdf;
19
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.Map;
25
26 import com.lowagie.text.Chunk;
27 import com.lowagie.text.Document;
28 import com.lowagie.text.DocumentException;
29 import com.lowagie.text.Element;
30 import com.lowagie.text.Font;
31 import com.lowagie.text.FontFactory;
32 import com.lowagie.text.Image;
33 import com.lowagie.text.Paragraph;
34 import com.lowagie.text.Phrase;
35 import com.lowagie.text.pdf.PdfPTable;
36
37 import net.bull.javamelody.internal.common.I18N;
38 import net.bull.javamelody.internal.common.Parameters;
39 import net.bull.javamelody.internal.model.CacheInformations;
40 import net.bull.javamelody.internal.model.Collector;
41 import net.bull.javamelody.internal.model.Counter;
42 import net.bull.javamelody.internal.model.CounterRequestContext;
43 import net.bull.javamelody.internal.model.JCacheInformations;
44 import net.bull.javamelody.internal.model.JRobin;
45 import net.bull.javamelody.internal.model.JavaInformations;
46 import net.bull.javamelody.internal.model.JobInformations;
47 import net.bull.javamelody.internal.model.Period;
48 import net.bull.javamelody.internal.model.Range;
49
50
54 public class PdfCoreReport extends PdfAbstractReport {
55 public static final int SMALL_GRAPH_WIDTH = 200;
56 public static final int SMALL_GRAPH_HEIGHT = 50;
57 public static final int LARGE_GRAPH_WIDTH = 960;
58 public static final int LARGE_GRAPH_HEIGHT = 370;
59 private final Collector collector;
60 private final List<JavaInformations> javaInformationsList;
61 private final Range range;
62 private Range counterRange;
63 private List<CounterRequestContext> currentRequests;
64 private final boolean collectorServer;
65 private final PdfDocumentFactory pdfDocumentFactory;
66 private final Font normalFont = PdfFonts.NORMAL.getFont();
67 private final Font cellFont = PdfFonts.TABLE_CELL.getFont();
68 private final Font boldFont = PdfFonts.BOLD.getFont();
69 private final long start = System.currentTimeMillis();
70 private Map<String, byte[]> smallGraphs;
71 private Map<String, byte[]> smallOtherGraphs;
72 private Map<String, byte[]> largeGraphs;
73
74 PdfCoreReport(Collector collector, boolean collectorServer,
75 List<JavaInformations> javaInformationsList, Range range,
76 PdfDocumentFactory pdfDocumentFactory, Document document) {
77 super(document);
78 assert collector != null;
79 assert javaInformationsList != null && !javaInformationsList.isEmpty();
80 assert range != null;
81 assert pdfDocumentFactory != null;
82
83 this.collector = collector;
84 this.collectorServer = collectorServer;
85 this.javaInformationsList = javaInformationsList;
86 this.range = range;
87 this.counterRange = range;
88 this.pdfDocumentFactory = pdfDocumentFactory;
89 }
90
91
92 void preInitGraphs(Map<String, byte[]> newSmallGraphs, Map<String, byte[]> newSmallOtherGraphs,
93 Map<String, byte[]> newLargeGraphs) {
94 this.smallGraphs = newSmallGraphs;
95 this.smallOtherGraphs = newSmallOtherGraphs;
96 this.largeGraphs = newLargeGraphs;
97 }
98
99
100 void setCounterRange(Range counterRange) {
101 this.counterRange = counterRange;
102 }
103
104
105 void setCurrentRequests(List<CounterRequestContext> currentRequests) {
106 this.currentRequests = currentRequests;
107 }
108
109 @Override
110 void toPdf() throws IOException, DocumentException {
111 addParagraph(buildSummary(), "systemmonitor.png");
112 writeGraphs(collector.getDisplayedCounterJRobins(), smallGraphs);
113
114 final List<Counter> counters = collector.getRangeCountersToBeDisplayed(counterRange);
115 final List<PdfCounterReport> pdfCounterReports = writeCounters(counters);
116
117 final List<PdfCounterRequestContextReport> pdfCounterRequestContextReports = new ArrayList<>();
118 if (!collectorServer) {
119 addParagraph(getString("Requetes_en_cours"), "hourglass.png");
120
121 pdfCounterRequestContextReports.addAll(
122 writeCurrentRequests(javaInformationsList.get(0), counters, pdfCounterReports));
123 }
124
125 addToDocument(new Phrase("\n", normalFont));
126 addParagraph(getString("Informations_systemes"), "systeminfo.png");
127 new PdfJavaInformationsReport(javaInformationsList, getDocument()).toPdf();
128
129 addParagraph(getString("Threads"), "threads.png");
130 writeThreads(false);
131
132 PdfCounterReport pdfJobCounterReport = null;
133 Counter rangeJobCounter = null;
134 if (isJobEnabled()) {
135 rangeJobCounter = collector.getRangeCounter(counterRange, Counter.JOB_COUNTER_NAME);
136 addToDocument(new Phrase("\n", normalFont));
137 addParagraph(getString("Jobs"), "jobs.png");
138 writeJobs(rangeJobCounter, false);
139 pdfJobCounterReport = writeCounter(rangeJobCounter);
140 }
141
142 if (isCacheEnabled() || isJCacheEnabled()) {
143 addToDocument(new Phrase("\n", normalFont));
144 addParagraph(getString("Caches"), "caches.png");
145 writeCaches(false);
146 writeJCaches(false);
147 }
148
149 newPage();
150 addParagraph(getString("Statistiques_detaillees"), "systemmonitor.png");
151 writeGraphs(collector.getDisplayedOtherJRobins(), smallOtherGraphs);
152 writeGraphDetails();
153
154 writeCountersDetails(pdfCounterReports);
155
156 if (!collectorServer) {
157 addParagraph(getString("Requetes_en_cours_detaillees"), "hourglass.png");
158
159 writeCurrentRequestsDetails(pdfCounterRequestContextReports);
160 }
161
162 addParagraph(getString("Informations_systemes_detaillees"), "systeminfo.png");
163 new PdfJavaInformationsReport(javaInformationsList, getDocument())
164 .writeInformationsDetails();
165
166 addParagraph(getString("Threads_detailles"), "threads.png");
167 writeThreads(true);
168
169 if (isJobEnabled()) {
170 addToDocument(new Phrase("\n", normalFont));
171 addParagraph(getString("Jobs_detailles"), "jobs.png");
172 writeJobs(rangeJobCounter, true);
173 writeCounterDetails(pdfJobCounterReport);
174 }
175
176 if (isCacheEnabled() || isJCacheEnabled()) {
177 addToDocument(new Phrase("\n", normalFont));
178 addParagraph(getString("Caches_detailles"), "caches.png");
179 writeCaches(true);
180 writeJCaches(true);
181 }
182
183 writeDurationAndOverhead();
184 }
185
186 private String buildSummary() {
187 final String tmp;
188 if (range.getPeriod() == Period.TOUT) {
189 final String startDate = I18N.createDateAndTimeFormat()
190 .format(collector.getCounters().get(0).getStartDate());
191 tmp = getFormattedString("Statistiques", "JavaMelody", I18N.getCurrentDateAndTime(),
192 startDate, collector.getApplication());
193 } else {
194 tmp = getFormattedString("Statistiques_sans_depuis", "JavaMelody",
195 I18N.getCurrentDateAndTime(), collector.getApplication());
196 }
197 if (javaInformationsList.get(0).getContextDisplayName() != null) {
198 return tmp + " (" + javaInformationsList.get(0).getContextDisplayName() + ')';
199 }
200 return tmp;
201 }
202
203 private void writeGraphs(Collection<JRobin> jrobins, Map<String, byte[]> mySmallGraphs)
204 throws IOException, DocumentException {
205 if (collector.isStopped()) {
206
207
208 final String message = getString("collect_server_misusage");
209 final Paragraph jrobinParagraph = new Paragraph(message, PdfFonts.BOLD.getFont());
210 jrobinParagraph.setAlignment(Element.ALIGN_CENTER);
211 addToDocument(jrobinParagraph);
212 return;
213 }
214 if (collector.isStorageUsedByMultipleInstances()) {
215 final String message = getString("storage_used_by_multiple_instances") + "\n\n";
216 final Paragraph jrobinParagraph = new Paragraph(message, PdfFonts.BOLD.getFont());
217 jrobinParagraph.setAlignment(Element.ALIGN_CENTER);
218 addToDocument(jrobinParagraph);
219 }
220 final Paragraph jrobinParagraph = new Paragraph("",
221 FontFactory.getFont(FontFactory.HELVETICA, 9f, Font.NORMAL));
222 jrobinParagraph.setAlignment(Element.ALIGN_CENTER);
223 jrobinParagraph.add(new Phrase("\n\n\n\n"));
224 final Collection<byte[]> graphs;
225 if (mySmallGraphs != null) {
226
227 graphs = mySmallGraphs.values();
228 } else {
229 if (jrobins.isEmpty()) {
230 return;
231 }
232 graphs = new ArrayList<>(jrobins.size());
233 for (final JRobin jrobin : jrobins) {
234 graphs.add(jrobin.graph(range, SMALL_GRAPH_WIDTH, SMALL_GRAPH_HEIGHT));
235 }
236 }
237 int i = 0;
238 for (final byte[] graph : graphs) {
239 if (i % 3 == 0 && i != 0) {
240
241 jrobinParagraph.add(new Phrase("\n\n\n\n\n"));
242 }
243 final Image image = Image.getInstance(graph);
244 image.scalePercent(50);
245 jrobinParagraph.add(new Phrase(new Chunk(image, 0, 0)));
246 jrobinParagraph.add(new Phrase(" "));
247 i++;
248 }
249 jrobinParagraph.add(new Phrase("\n"));
250 addToDocument(jrobinParagraph);
251 }
252
253 private void writeGraphDetails() throws IOException, DocumentException {
254 if (collector.isStopped()) {
255 return;
256 }
257 final PdfPTable jrobinTable = new PdfPTable(1);
258 jrobinTable.setHorizontalAlignment(Element.ALIGN_CENTER);
259 jrobinTable.setWidthPercentage(100);
260 jrobinTable.getDefaultCell().setBorder(0);
261 if (largeGraphs != null) {
262
263 for (final byte[] imageData : largeGraphs.values()) {
264 final Image image = Image.getInstance(imageData);
265 jrobinTable.addCell(image);
266 }
267 } else {
268 final Collection<JRobin> counterJRobins = collector.getDisplayedCounterJRobins();
269 if (counterJRobins.isEmpty()) {
270 return;
271 }
272 for (final JRobin jrobin : counterJRobins) {
273
274 final Image image = Image
275 .getInstance(jrobin.graph(range, LARGE_GRAPH_WIDTH, LARGE_GRAPH_HEIGHT));
276 jrobinTable.addCell(image);
277 }
278 }
279 newPage();
280 addToDocument(jrobinTable);
281 newPage();
282 }
283
284 private List<PdfCounterReport> writeCounters(List<Counter> counters)
285 throws IOException, DocumentException {
286 final List<PdfCounterReport> pdfCounterReports = new ArrayList<>();
287 for (final Counter counter : counters) {
288 pdfCounterReports.add(writeCounter(counter));
289 }
290 return pdfCounterReports;
291 }
292
293 private PdfCounterReport writeCounter(Counter counter) throws DocumentException, IOException {
294 final String counterLabel = getString(counter.getName() + "Label");
295 addParagraph(addRangeLabel(getFormattedString("Statistiques_compteur", counterLabel)),
296 counter.getIconName());
297 final PdfCounterReport pdfCounterReport = new PdfCounterReport(collector, counter, range,
298 false, getDocument());
299 pdfCounterReport.toPdf();
300 return pdfCounterReport;
301 }
302
303 private String addRangeLabel(String s) {
304 return s + " - " + range.getLabel() + ' ' + getString("depuis_minuit");
305 }
306
307 private void writeCountersDetails(List<PdfCounterReport> pdfCounterReports)
308 throws DocumentException, IOException {
309 for (final PdfCounterReport pdfCounterReport : pdfCounterReports) {
310 writeCounterDetails(pdfCounterReport);
311 }
312 }
313
314 private void writeCounterDetails(PdfCounterReport pdfCounterReport)
315 throws DocumentException, IOException {
316 final String counterLabel = getString(pdfCounterReport.getCounterName() + "Label");
317 addParagraph(
318 addRangeLabel(getFormattedString("Statistiques_compteur_detaillees", counterLabel)),
319 pdfCounterReport.getCounterIconName());
320 pdfCounterReport.writeRequestDetails();
321 if (pdfCounterReport.isErrorCounter()) {
322 addParagraph(addRangeLabel(getString(pdfCounterReport.getCounterName() + "ErrorLabel")),
323 pdfCounterReport.getCounterIconName());
324 pdfCounterReport.writeErrorDetails();
325 }
326 }
327
328 private List<PdfCounterRequestContextReport> writeCurrentRequests(
329 JavaInformations javaInformations, List<Counter> counters,
330 List<PdfCounterReport> pdfCounterReports) throws IOException, DocumentException {
331 final List<PdfCounterRequestContextReport> pdfCounterRequestContextReports = new ArrayList<>();
332 final List<CounterRequestContext> rootCurrentContexts;
333 if (currentRequests == null) {
334 rootCurrentContexts = collector.getRootCurrentContexts(counters);
335 } else {
336 rootCurrentContexts = currentRequests;
337 }
338 if (rootCurrentContexts.isEmpty()) {
339 addToDocument(new Phrase(getString("Aucune_requete_en_cours"), normalFont));
340 } else {
341 final PdfCounterRequestContextReport pdfCounterRequestContextReport = new PdfCounterRequestContextReport(
342 rootCurrentContexts, pdfCounterReports,
343 javaInformations.getThreadInformationsList(),
344 javaInformations.isStackTraceEnabled(), pdfDocumentFactory, getDocument());
345 pdfCounterRequestContextReport.toPdf();
346 pdfCounterRequestContextReports.add(pdfCounterRequestContextReport);
347 }
348 return pdfCounterRequestContextReports;
349 }
350
351 private void writeCurrentRequestsDetails(
352 List<PdfCounterRequestContextReport> pdfCounterRequestContextReports)
353 throws IOException, DocumentException {
354 for (final PdfCounterRequestContextReport pdfCounterRequestContextReport : pdfCounterRequestContextReports) {
355 pdfCounterRequestContextReport.writeContextDetails();
356 }
357 if (pdfCounterRequestContextReports.isEmpty()) {
358 addToDocument(new Phrase(getString("Aucune_requete_en_cours"), normalFont));
359 }
360 }
361
362 private void writeThreads(boolean includeDetails) throws DocumentException, IOException {
363 String eol = "";
364 for (final JavaInformations javaInformations : javaInformationsList) {
365 addToDocument(new Phrase(eol, normalFont));
366 final PdfThreadInformationsReport pdfThreadInformationsReport = new PdfThreadInformationsReport(
367 javaInformations.getThreadInformationsList(),
368 javaInformations.isStackTraceEnabled(), pdfDocumentFactory, getDocument());
369 pdfThreadInformationsReport.writeIntro(javaInformations);
370 pdfThreadInformationsReport.writeDeadlocks();
371
372 if (includeDetails) {
373 pdfThreadInformationsReport.toPdf();
374 }
375 eol = "\n";
376 }
377 }
378
379 private void writeCaches(boolean includeDetails) throws DocumentException {
380 String eol = "";
381 for (final JavaInformations javaInformations : javaInformationsList) {
382 if (!javaInformations.isCacheEnabled()) {
383 continue;
384 }
385 final List<CacheInformations> cacheInformationsList = javaInformations
386 .getCacheInformationsList();
387 final String msg = getFormattedString("caches_sur", cacheInformationsList.size(),
388 javaInformations.getHost(), javaInformations.getCurrentlyExecutingJobCount());
389 addToDocument(new Phrase(eol + msg, boldFont));
390
391 if (includeDetails) {
392 new PdfCacheInformationsReport(cacheInformationsList, getDocument()).toPdf();
393 }
394 eol = "\n";
395 }
396 }
397
398 private boolean isCacheEnabled() {
399 for (final JavaInformations javaInformations : javaInformationsList) {
400 if (javaInformations.isCacheEnabled()) {
401 return true;
402 }
403 }
404 return false;
405 }
406
407 private void writeJCaches(boolean includeDetails) throws DocumentException {
408 String eol = "";
409 if (isCacheEnabled()) {
410
411 eol = "\n";
412 }
413 for (final JavaInformations javaInformations : javaInformationsList) {
414 if (!javaInformations.isJCacheEnabled()) {
415 continue;
416 }
417 final List<JCacheInformations> jcacheInformationsList = javaInformations
418 .getJCacheInformationsList();
419 final String msg = getFormattedString("caches_sur", jcacheInformationsList.size(),
420 javaInformations.getHost());
421 addToDocument(new Phrase(eol + msg, boldFont));
422
423 if (includeDetails) {
424 new PdfJCacheInformationsReport(jcacheInformationsList, getDocument()).toPdf();
425 }
426 eol = "\n";
427 }
428 }
429
430 private boolean isJCacheEnabled() {
431 for (final JavaInformations javaInformations : javaInformationsList) {
432 if (javaInformations.isJCacheEnabled()) {
433 return true;
434 }
435 }
436 return false;
437 }
438
439 private void writeJobs(Counter rangeJobCounter, boolean includeDetails)
440 throws DocumentException, IOException {
441 String eol = "";
442 for (final JavaInformations javaInformations : javaInformationsList) {
443 if (!javaInformations.isJobEnabled()) {
444 continue;
445 }
446 final List<JobInformations> jobInformationsList = javaInformations
447 .getJobInformationsList();
448 final String msg = getFormattedString("jobs_sur", jobInformationsList.size(),
449 javaInformations.getHost(), javaInformations.getCurrentlyExecutingJobCount());
450 addToDocument(new Phrase(eol + msg, boldFont));
451
452 if (includeDetails) {
453 new PdfJobInformationsReport(jobInformationsList, rangeJobCounter, getDocument())
454 .toPdf();
455 }
456 eol = "\n";
457 }
458 }
459
460 private boolean isJobEnabled() {
461 for (final JavaInformations javaInformations : javaInformationsList) {
462 if (javaInformations.isJobEnabled()) {
463 return true;
464 }
465 }
466 return false;
467 }
468
469 private void writeDurationAndOverhead() throws DocumentException {
470 final long displayDuration = System.currentTimeMillis() - start;
471 final String tmp = "\n\n" + getString("temps_derniere_collecte") + ": "
472 + collector.getLastCollectDuration() + ' ' + getString("ms") + '\n'
473 + getString("temps_affichage") + ": " + displayDuration + ' ' + getString("ms")
474 + '\n' + getString("Estimation_overhead_memoire") + ": < "
475 + (collector.getEstimatedMemorySize() / 1024 / 1024 + 1) + ' ' + getString("Mo")
476 + '\n' + getString("Usage_disque") + ": "
477 + (collector.getDiskUsage() / 1024 / 1024 + 1) + ' ' + getString("Mo");
478 final String string;
479 if (Parameters.JAVAMELODY_VERSION != null) {
480 string = tmp + "\n\n" + "JavaMelody " + Parameters.JAVAMELODY_VERSION;
481 } else {
482 string = tmp;
483 }
484 addToDocument(new Phrase(string, cellFont));
485 }
486
487 private void addParagraph(String paragraphTitle, String iconName)
488 throws DocumentException, IOException {
489 addToDocument(pdfDocumentFactory.createParagraphElement(paragraphTitle, iconName));
490 }
491 }
492