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.List;
23
24 import com.lowagie.text.Anchor;
25 import com.lowagie.text.BadElementException;
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.Phrase;
33 import com.lowagie.text.pdf.PdfPTable;
34
35 import net.bull.javamelody.internal.common.I18N;
36 import net.bull.javamelody.internal.common.Parameters;
37 import net.bull.javamelody.internal.model.JavaInformations;
38 import net.bull.javamelody.internal.model.MemoryInformations;
39 import net.bull.javamelody.internal.model.TomcatInformations;
40 import net.bull.javamelody.internal.web.html.HtmlJavaInformationsReport;
41
42 /**
43  * Partie du rapport pdf pour les informations systèmes sur le serveur.
44  * @author Emeric Vernat
45  */

46 class PdfJavaInformationsReport extends PdfAbstractReport {
47     private static final String DIVIDE = " / ";
48     private static final String BAR_SEPARATOR = "   ";
49     private final boolean noDatabase = Parameters.isNoDatabase();
50     private final DecimalFormat decimalFormat = I18N.createPercentFormat();
51     private final DecimalFormat integerFormat = I18N.createIntegerFormat();
52     private final List<JavaInformations> javaInformationsList;
53     private final Font cellFont = PdfFonts.TABLE_CELL.getFont();
54     private final Font boldCellFont = PdfFonts.BOLD_CELL.getFont();
55     private PdfPTable currentTable;
56
57     PdfJavaInformationsReport(List<JavaInformations> javaInformationsList, Document document) {
58         super(document);
59         assert javaInformationsList != null;
60
61         this.javaInformationsList = javaInformationsList;
62     }
63
64     @Override
65     void toPdf() throws DocumentException, IOException {
66         for (final JavaInformations javaInformations : javaInformationsList) {
67             currentTable = createJavaInformationsTable();
68             writeSummary(javaInformations);
69             addCell("");
70             addCell("");
71             addToDocument(currentTable);
72         }
73     }
74
75     private static PdfPTable createJavaInformationsTable() throws DocumentException {
76         final PdfPTable table = new PdfPTable(2);
77         table.setHorizontalAlignment(Element.ALIGN_LEFT);
78         table.setWidthPercentage(100);
79         table.setWidths(new int[] { 2, 8 });
80         table.getDefaultCell().setBorder(0);
81         return table;
82     }
83
84     private void writeSummary(JavaInformations javaInformations)
85             throws BadElementException, IOException {
86         addCell(getString("Host") + ':');
87         currentTable.addCell(new Phrase(javaInformations.getHost(), boldCellFont));
88         addCell(getString("memoire_utilisee") + ':');
89         final MemoryInformations memoryInformations = javaInformations.getMemoryInformations();
90         final long usedMemory = memoryInformations.getUsedMemory();
91         final long maxMemory = memoryInformations.getMaxMemory();
92         final Phrase memoryPhrase = new Phrase(integerFormat.format(usedMemory / 1024 / 1024) + ' '
93                 + getString("Mo") + DIVIDE + integerFormat.format(maxMemory / 1024 / 1024) + ' '
94                 + getString("Mo") + BAR_SEPARATOR, cellFont);
95         final Image memoryImage = Image.getInstance(
96                 Bar.toBarWithAlert(memoryInformations.getUsedMemoryPercentage()), null);
97         memoryImage.scalePercent(50);
98         memoryPhrase.add(new Chunk(memoryImage, 0, 0));
99         currentTable.addCell(memoryPhrase);
100         if (javaInformations.getSessionCount() >= 0) {
101             addCell(getString("nb_sessions_http") + ':');
102             addCell(integerFormat.format(javaInformations.getSessionCount()));
103         }
104         addCell(getString("nb_threads_actifs") + "\n(" + getString("Requetes_http_en_cours")
105                 + "):");
106         addCell(integerFormat.format(javaInformations.getActiveThreadCount()));
107         if (!noDatabase) {
108             addCell(getString("nb_connexions_actives") + ':');
109             addCell(integerFormat.format(javaInformations.getActiveConnectionCount()));
110             addCell(getString("nb_connexions_utilisees") + "\n(" + getString("ouvertes") + "):");
111             final int usedConnectionCount = javaInformations.getUsedConnectionCount();
112             final int maxConnectionCount = javaInformations.getMaxConnectionCount();
113             if (maxConnectionCount <= 0) {
114                 addCell(integerFormat.format(usedConnectionCount));
115             } else {
116                 final Phrase usedConnectionCountPhrase = new Phrase(
117                         integerFormat.format(usedConnectionCount) + DIVIDE
118                                 + integerFormat.format(maxConnectionCount) + BAR_SEPARATOR,
119                         cellFont);
120                 final Image usedConnectionCountImage = Image.getInstance(
121                         Bar.toBarWithAlert(javaInformations.getUsedConnectionPercentage()), null);
122                 usedConnectionCountImage.scalePercent(50);
123                 usedConnectionCountPhrase.add(new Chunk(usedConnectionCountImage, 0, 0));
124                 currentTable.addCell(usedConnectionCountPhrase);
125             }
126         }
127         if (javaInformations.getSystemLoadAverage() >= 0) {
128             addCell(getString("Charge_systeme") + ':');
129             addCell(decimalFormat.format(javaInformations.getSystemLoadAverage()));
130         }
131         if (javaInformations.getSystemCpuLoad() >= 0) {
132             addCell(getString("systemCpuLoad") + ':');
133             final Phrase systemCpuLoadPhrase = new Phrase(
134                     decimalFormat.format(javaInformations.getSystemCpuLoad()) + BAR_SEPARATOR,
135                     cellFont);
136             final Image systemCpuLoadImage = Image
137                     .getInstance(Bar.toBarWithAlert(javaInformations.getSystemCpuLoad()), null);
138             systemCpuLoadImage.scalePercent(50);
139             systemCpuLoadPhrase.add(new Chunk(systemCpuLoadImage, 0, 0));
140             currentTable.addCell(systemCpuLoadPhrase);
141         }
142     }
143
144     void writeInformationsDetails() throws DocumentException, IOException {
145         for (final JavaInformations javaInformations : javaInformationsList) {
146             currentTable = createJavaInformationsTable();
147             writeSummary(javaInformations);
148             writeDetails(javaInformations);
149             addToDocument(currentTable);
150         }
151     }
152
153     private void writeDetails(JavaInformations javaInformations)
154             throws BadElementException, IOException {
155         addCell(getString("OS") + ':');
156         final Phrase osPhrase = new Phrase("", cellFont);
157         final String osIconName = HtmlJavaInformationsReport
158                 .getOSIconName(javaInformations.getOS());
159         final String separator = "   ";
160         if (osIconName != null) {
161             final Image osImage = PdfDocumentFactory.getImage("servers/" + osIconName);
162             osImage.scalePercent(40);
163             osPhrase.add(new Chunk(osImage, 0, 0));
164             osPhrase.add(new Chunk(separator));
165         }
166         osPhrase.add(new Chunk(javaInformations.getOS() + " ("
167                 + javaInformations.getAvailableProcessors() + ' ' + getString("coeurs") + ')'));
168         currentTable.addCell(osPhrase);
169         addCell(getString("Java") + ':');
170         addCell(javaInformations.getJavaVersion());
171         addCell(getString("JVM") + ':');
172         final Phrase jvmVersionPhrase = new Phrase(javaInformations.getJvmVersion(), cellFont);
173         if (javaInformations.getJvmVersion().contains("Client")) {
174             jvmVersionPhrase.add(new Chunk(separator));
175             final Image alertImage = PdfDocumentFactory.getImage("alert.png");
176             alertImage.scalePercent(50);
177             jvmVersionPhrase.add(new Chunk(alertImage, 0, -2));
178         }
179         currentTable.addCell(jvmVersionPhrase);
180         addCell(getString("PID") + ':');
181         addCell(javaInformations.getPID());
182         if (javaInformations.getUnixOpenFileDescriptorCount() >= 0) {
183             writeFileDescriptorCounts(javaInformations);
184         }
185         final String serverInfo = javaInformations.getServerInfo();
186         if (serverInfo != null) {
187             writeServerInfo(serverInfo);
188             addCell(getString("Contexte_webapp") + ':');
189             addCell(javaInformations.getContextPath());
190         }
191         addCell(getString("Demarrage") + ':');
192         addCell(I18N.createDateAndTimeFormat().format(javaInformations.getStartDate()));
193         addCell(getString("Arguments_JVM") + ':');
194         addCell(javaInformations.getJvmArguments());
195         if (javaInformations.getSessionCount() >= 0) {
196             addCell(getString("httpSessionsMeanAge") + ':');
197             addCell(integerFormat.format(javaInformations.getSessionMeanAgeInMinutes()));
198         }
199         writeTomcatInformations(javaInformations.getTomcatInformationsList());
200         addCell(getString("Gestion_memoire") + ':');
201         writeMemoryInformations(javaInformations.getMemoryInformations());
202         // on considère que l'espace libre sur le disque dur est celui sur la partition du répertoire temporaire
203         addCell(getString("Free_disk_space") + ':');
204         addCell(integerFormat.format(javaInformations.getFreeDiskSpaceInTemp() / 1024 / 1024) + ' '
205                 + getString("Mo"));
206         addCell(getString("Usable_disk_space") + ':');
207         addCell(integerFormat.format(javaInformations.getUsableDiskSpaceInTemp() / 1024 / 1024)
208                 + ' ' + getString("Mo"));
209         writeDatabaseVersionAndDataSourceDetails(javaInformations);
210         addCell("");
211         addCell("");
212     }
213
214     private void writeServerInfo(String serverInfo) throws BadElementException, IOException {
215         addCell(getString("Serveur") + ':');
216         final Phrase serverInfoPhrase = new Phrase("", cellFont);
217         final String applicationServerIconName = HtmlJavaInformationsReport
218                 .getApplicationServerIconName(serverInfo);
219         if (applicationServerIconName != null) {
220             final Image applicationServerImage = PdfDocumentFactory
221                     .getImage("servers/" + applicationServerIconName);
222             applicationServerImage.scalePercent(40);
223             serverInfoPhrase.add(new Chunk(applicationServerImage, 0, 0));
224             serverInfoPhrase.add(new Chunk("   "));
225         }
226         serverInfoPhrase.add(new Chunk(serverInfo));
227         currentTable.addCell(serverInfoPhrase);
228     }
229
230     private void writeFileDescriptorCounts(JavaInformations javaInformations)
231             throws BadElementException, IOException {
232         final long unixOpenFileDescriptorCount = javaInformations.getUnixOpenFileDescriptorCount();
233         final long unixMaxFileDescriptorCount = javaInformations.getUnixMaxFileDescriptorCount();
234         addCell(getString("nb_fichiers") + ':');
235         final Phrase fileDescriptorCountPhrase = new Phrase(
236                 integerFormat.format(unixOpenFileDescriptorCount) + DIVIDE
237                         + integerFormat.format(unixMaxFileDescriptorCount) + BAR_SEPARATOR,
238                 cellFont);
239         final Image fileDescriptorCountImage = Image.getInstance(
240                 Bar.toBarWithAlert(javaInformations.getUnixOpenFileDescriptorPercentage()), null);
241         fileDescriptorCountImage.scalePercent(50);
242         fileDescriptorCountPhrase.add(new Chunk(fileDescriptorCountImage, 0, 0));
243         currentTable.addCell(fileDescriptorCountPhrase);
244     }
245
246     private void writeDatabaseVersionAndDataSourceDetails(JavaInformations javaInformations) {
247         if (!noDatabase && javaInformations.getDataBaseVersion() != null) {
248             addCell(getString("Base_de_donnees") + ':');
249             addCell(javaInformations.getDataBaseVersion());
250         }
251         if (javaInformations.getDataSourceDetails() != null) {
252             addCell(getString("DataSource_jdbc") + ':');
253             addCell(javaInformations.getDataSourceDetails());
254             addCell("");
255             final Anchor anchor = new Anchor("DataSource reference", PdfFonts.BLUE.getFont());
256             anchor.setName("DataSource reference");
257             anchor.setReference("http://commons.apache.org/proper/commons-dbcp/configuration.html");
258             currentTable.addCell(anchor);
259         }
260     }
261
262     private void writeTomcatInformations(List<TomcatInformations> tomcatInformationsList)
263             throws BadElementException, IOException {
264         for (final TomcatInformations tomcatInformations : tomcatInformationsList) {
265             if (tomcatInformations.getRequestCount() <= 0) {
266                 continue;
267             }
268             addCell("Tomcat " + tomcatInformations.getName() + ':');
269             // rq: on n'affiche pas pour l'instant getCurrentThreadCount
270             final int currentThreadsBusy = tomcatInformations.getCurrentThreadsBusy();
271             final String equal = " = ";
272             final Phrase phrase = new Phrase(getString("busyThreads") + equal
273                     + integerFormat.format(currentThreadsBusy) + DIVIDE
274                     + integerFormat.format(tomcatInformations.getMaxThreads()) + BAR_SEPARATOR,
275                     cellFont);
276             final Image threadsImage = Image.getInstance(Bar.toBarWithAlert(
277                     100d * currentThreadsBusy / tomcatInformations.getMaxThreads()), null);
278             threadsImage.scalePercent(50);
279             phrase.add(new Chunk(threadsImage, 0, 0));
280
281             phrase.add(new Chunk('\n' + getString("bytesReceived") + equal
282                     + integerFormat.format(tomcatInformations.getBytesReceived()) + '\n'
283                     + getString("bytesSent") + equal
284                     + integerFormat.format(tomcatInformations.getBytesSent()) + '\n'
285                     + getString("requestCount") + equal
286                     + integerFormat.format(tomcatInformations.getRequestCount()) + '\n'
287                     + getString("errorCount") + equal
288                     + integerFormat.format(tomcatInformations.getErrorCount()) + '\n'
289                     + getString("processingTime") + equal
290                     + integerFormat.format(tomcatInformations.getProcessingTime()) + '\n'
291                     + getString("maxProcessingTime") + equal
292                     + integerFormat.format(tomcatInformations.getMaxTime())));
293             currentTable.addCell(phrase);
294         }
295     }
296
297     private void writeMemoryInformations(MemoryInformations memoryInformations)
298             throws BadElementException, IOException {
299         addCell(memoryInformations.getMemoryDetails().replace(" Mo", ' ' + getString("Mo")));
300         final long usedPermGen = memoryInformations.getUsedPermGen();
301         if (usedPermGen > 0) {
302             // perm gen est à 0 sous jrockit
303             final long maxPermGen = memoryInformations.getMaxPermGen();
304             addCell(getString("Memoire_Perm_Gen") + ':');
305             if (maxPermGen > 0) {
306                 final Phrase permGenPhrase = new Phrase(
307                         integerFormat.format(usedPermGen / 1024 / 1024) + ' ' + getString("Mo")
308                                 + DIVIDE + integerFormat.format(maxPermGen / 1024 / 1024) + ' '
309                                 + getString("Mo") + BAR_SEPARATOR,
310                         cellFont);
311                 final Image permGenImage = Image.getInstance(
312                         Bar.toBarWithAlert(memoryInformations.getUsedPermGenPercentage()), null);
313                 permGenImage.scalePercent(50);
314                 permGenPhrase.add(new Chunk(permGenImage, 0, 0));
315                 currentTable.addCell(permGenPhrase);
316             } else {
317                 addCell(integerFormat.format(usedPermGen / 1024 / 1024) + ' ' + getString("Mo"));
318             }
319         }
320     }
321
322     private void addCell(String string) {
323         currentTable.addCell(new Phrase(string, cellFont));
324     }
325 }
326