1 /*
2  * Copyright 2008-2019 by Emeric Vernat
3  *
4  *     This file is part of Java Melody.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18 package net.bull.javamelody.internal.web.pdf;
19
20 import java.io.IOException;
21 import java.text.DecimalFormat;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.List;
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.Image;
32 import com.lowagie.text.Paragraph;
33 import com.lowagie.text.Phrase;
34 import com.lowagie.text.pdf.PdfPCell;
35
36 import net.bull.javamelody.internal.common.I18N;
37 import net.bull.javamelody.internal.model.JavaInformations;
38 import net.bull.javamelody.internal.model.ThreadInformations;
39 import net.bull.javamelody.internal.web.html.HtmlThreadInformationsReport;
40
41 /**
42  * Partie du rapport pdf pour les threads sur le serveur.
43  * @author Emeric Vernat
44  */

45 class PdfThreadInformationsReport extends PdfAbstractTableReport {
46     private final List<ThreadInformations> threadInformationsList;
47     private final DecimalFormat integerFormat = I18N.createIntegerFormat();
48     private final boolean stackTraceEnabled;
49     private final boolean cpuTimeEnabled;
50     private final Font cellFont = PdfFonts.TABLE_CELL.getFont();
51     private final PdfDocumentFactory pdfDocumentFactory;
52
53     PdfThreadInformationsReport(List<ThreadInformations> threadInformationsList,
54             boolean stackTraceEnabled, PdfDocumentFactory pdfDocumentFactory, Document document) {
55         super(document);
56         assert threadInformationsList != null;
57         assert pdfDocumentFactory != null;
58
59         this.threadInformationsList = threadInformationsList;
60         this.pdfDocumentFactory = pdfDocumentFactory;
61         this.stackTraceEnabled = stackTraceEnabled;
62         this.cpuTimeEnabled = !threadInformationsList.isEmpty()
63                 && threadInformationsList.get(0).getCpuTimeMillis() != -1;
64     }
65
66     @Override
67     void toPdf() throws DocumentException, IOException {
68         writeHeader();
69
70         for (final ThreadInformations threadInformations : threadInformationsList) {
71             nextRow();
72             writeThreadInformations(threadInformations);
73         }
74         addTableToDocument();
75
76         final Paragraph tempsThreads = new Paragraph(getString("Temps_threads") + '\n', cellFont);
77         tempsThreads.setAlignment(Element.ALIGN_RIGHT);
78         addToDocument(tempsThreads);
79
80         // rq stack-trace: on n'inclue pas dans le pdf les stack-traces des threads
81         // car c'est très verbeux et cela remplirait des pages pour pas grand chose
82         // d'autant que si le pdf est généré de nuit pour être envoyé par mail
83         // alors ces stack-traces n'ont pas beaucoup d'intérêt
84         //        if (stackTrace != null && !stackTrace.isEmpty()) {
85         //            // même si stackTraceEnabled, ce thread n'a pas forcément de stack-trace
86         //            writeln(threadInformations.getName());
87         //            for (final StackTraceElement stackTraceElement : stackTrace) {
88         //                writeln(stackTraceElement.toString());
89         //            }
90         //        }
91     }
92
93     void writeIntro(JavaInformations javaInformations) throws DocumentException {
94         final Font boldFont = PdfFonts.BOLD.getFont();
95         final Font normalFont = PdfFonts.NORMAL.getFont();
96         addToDocument(new Phrase(
97                 getFormattedString("Threads_sur", javaInformations.getHost()) + ": ", boldFont));
98         addToDocument(new Phrase(getFormattedString("thread_count",
99                 javaInformations.getThreadCount(), javaInformations.getPeakThreadCount(),
100                 javaInformations.getTotalStartedThreadCount()), normalFont));
101     }
102
103     void writeDeadlocks() throws DocumentException {
104         final List<ThreadInformations> deadlockedThreads = new ArrayList<>();
105         for (final ThreadInformations thread : threadInformationsList) {
106             if (thread.isDeadlocked()) {
107                 deadlockedThreads.add(thread);
108             }
109         }
110         if (!deadlockedThreads.isEmpty()) {
111             final StringBuilder sb = new StringBuilder();
112             sb.append('\n');
113             sb.append(getString("Threads_deadlocks"));
114             String separator = " ";
115             for (final ThreadInformations thread : deadlockedThreads) {
116                 sb.append(separator);
117                 sb.append(thread.getName());
118                 separator = ", ";
119             }
120             sb.append('\n');
121             addToDocument(new Phrase(sb.toString(), PdfFonts.SEVERE_CELL.getFont()));
122         }
123     }
124
125     private void writeHeader() throws DocumentException {
126         final List<String> headers = createHeaders();
127         final int[] relativeWidths = new int[headers.size()];
128         Arrays.fill(relativeWidths, 0, headers.size(), 1);
129         relativeWidths[0] = 3; // thread
130         relativeWidths[3] = 2; // état
131         if (stackTraceEnabled) {
132             relativeWidths[4] = 6; // méthode exécutée
133         }
134
135         initTable(headers, relativeWidths);
136     }
137
138     private List<String> createHeaders() {
139         final List<String> headers = new ArrayList<>();
140         headers.add(getString("Thread"));
141         headers.add(getString("Demon"));
142         headers.add(getString("Priorite"));
143         headers.add(getString("Etat"));
144         if (stackTraceEnabled) {
145             headers.add(getString("Methode_executee"));
146         }
147         if (cpuTimeEnabled) {
148             headers.add(getString("Temps_cpu"));
149             headers.add(getString("Temps_user"));
150         }
151         return headers;
152     }
153
154     private void writeThreadInformations(ThreadInformations threadInformations)
155             throws DocumentException, IOException {
156         final PdfPCell defaultCell = getDefaultCell();
157         defaultCell.setHorizontalAlignment(Element.ALIGN_LEFT);
158         addCell(threadInformations.getName());
159         defaultCell.setHorizontalAlignment(Element.ALIGN_CENTER);
160         if (threadInformations.isDaemon()) {
161             addCell(getString("oui"));
162         } else {
163             addCell(getString("non"));
164         }
165         defaultCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
166         addCell(integerFormat.format(threadInformations.getPriority()));
167         defaultCell.setHorizontalAlignment(Element.ALIGN_LEFT);
168         final PdfPCell cell = new PdfPCell();
169         final Paragraph paragraph = new Paragraph(
170                 getDefaultCell().getLeading() + cellFont.getSize());
171         paragraph.add(new Chunk(
172                 getImage(
173                         "bullets/" + HtmlThreadInformationsReport.getStateIcon(threadInformations)),
174                 0, -1));
175         paragraph.add(new Phrase(String.valueOf(threadInformations.getState()), cellFont));
176         cell.addElement(paragraph);
177         addCell(cell);
178         if (stackTraceEnabled) {
179             addCell(threadInformations.getExecutedMethod());
180         }
181         if (cpuTimeEnabled) {
182             defaultCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
183             addCell(integerFormat.format(threadInformations.getCpuTimeMillis()));
184             addCell(integerFormat.format(threadInformations.getUserTimeMillis()));
185         }
186     }
187
188     private Image getImage(String resourceFileName) throws DocumentException, IOException {
189         return pdfDocumentFactory.getSmallImage(resourceFileName);
190     }
191 }
192