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.html;
19
20 import java.io.IOException;
21 import java.io.Writer;
22 import java.security.SecureRandom;
23
24 import javax.servlet.http.HttpSession;
25
26 import net.bull.javamelody.Parameter;
27 import net.bull.javamelody.SessionListener;
28 import net.bull.javamelody.internal.common.HttpParameter;
29 import net.bull.javamelody.internal.common.I18N;
30 import net.bull.javamelody.internal.common.Parameters;
31 import net.bull.javamelody.internal.model.Base64Coder;
32
33 /**
34  * Parent abstrait des classes de rapport html.
35  * @author Emeric Vernat
36  */

37 public abstract class HtmlAbstractReport {
38     private static final boolean CSRF_PROTECTION_ENABLED = Parameter.CSRF_PROTECTION_ENABLED
39             .getValueAsBoolean();
40     private final Writer writer;
41
42     class HtmlTable {
43         private boolean firstRow = true;
44         private boolean oddRow;
45
46         void beginTable(String summary) throws IOException {
47             writeDirectly("<table class='sortable' width='100%' border='1' summary='");
48             writeDirectly(summary);
49             writeDirectly("'>\n");
50             writeDirectly("<thead><tr>");
51         }
52
53         void nextRow() throws IOException {
54             writeDirectly("</tr>");
55             if (firstRow) {
56                 firstRow = false;
57                 writeDirectly("</thead><tbody>\n");
58             }
59             if (oddRow) {
60                 writeDirectly("<tr class='odd'>\n");
61             } else {
62                 writeDirectly("<tr class='even'>\n");
63             }
64             oddRow = !oddRow; // NOPMD
65         }
66
67         void endTable() throws IOException {
68             writeDirectly("</tr>");
69             if (firstRow) {
70                 firstRow = false;
71                 writeDirectly("</thead><tbody>\n");
72             }
73             writeDirectly("</tbody></table>\n");
74         }
75     }
76
77     HtmlAbstractReport(Writer writer) {
78         super();
79         assert writer != null;
80         this.writer = writer;
81     }
82
83     /**
84      * Perform the default html rendering of the report into the writer.
85      * @throws IOException e
86      */

87     abstract void toHtml() throws IOException;
88
89     Writer getWriter() {
90         return writer;
91     }
92
93     void writeDirectly(String html) throws IOException {
94         writer.write(html);
95     }
96
97     /**
98      * Écrit un texte dans un flux en remplaçant dans le texte les clés entourées de deux '#'
99      * par leurs traductions dans la locale courante.
100      * @param html texte html avec éventuellement des #clé#
101      * @throws IOException e
102      */

103     void write(String html) throws IOException {
104         I18N.writeTo(html, writer);
105     }
106
107     /**
108      * Écrit un texte, puis un retour chariot, dans un flux en remplaçant dans le texte les clés
109      * entourées de deux '#' par leurs traductions dans la locale courante.
110      * @param html texte html avec éventuellement des #clé#
111      * @throws IOException e
112      */

113     void writeln(String html) throws IOException {
114         I18N.writelnTo(html, writer);
115     }
116
117     void writeTitle(String imageFileName, String title) throws IOException {
118         writeDirectly("<span class='chapterTitle'><img src='?resource=");
119         writeDirectly(imageFileName);
120         writeDirectly("' alt=\"");
121         writeDirectly(title);
122         writeDirectly("\" />&nbsp;");
123         writeDirectly("<b>");
124         writeDirectly(title);
125         writeDirectly("</b></span><br/>\n");
126     }
127
128     void writeShowHideLink(String idToShow, String label) throws IOException {
129         writeln("<a href='' class='showHide noPrint' data-show-hide-id='" + idToShow + "' id='"
130                 + idToShow + "A'><img id='" + idToShow
131                 + "Img' src='?resource=bullets/plus.png' alt=''/> " + label + "</a>");
132     }
133
134     /**
135      * Retourne une traduction dans la locale courante.
136      * @param key clé d'un libellé dans les fichiers de traduction
137      * @return String
138      */

139     static String getString(String key) {
140         return I18N.getString(key);
141     }
142
143     /**
144      * Retourne une traduction dans la locale courante et insère les arguments aux positions {i}.
145      * @param key clé d'un libellé dans les fichiers de traduction
146      * @param arguments Valeur à inclure dans le résultat
147      * @return String
148      */

149     static String getFormattedString(String key, Object... arguments) {
150         return I18N.getFormattedString(key, arguments);
151     }
152
153     static String urlEncode(String text) {
154         return I18N.urlEncode(text);
155     }
156
157     /**
158      * Encode pour affichage en html, en encodant les espaces en nbsp (insécables).
159      * @param text message à encoder
160      * @return String
161      */

162     static String htmlEncode(String text) {
163         return I18N.htmlEncode(text, true);
164     }
165
166     /**
167      * Encode pour affichage en html, sans encoder les espaces en nbsp (insécables).
168      * @param text message à encoder
169      * @return String
170      */

171     static String htmlEncodeButNotSpace(String text) {
172         return I18N.htmlEncode(text, false);
173     }
174
175     /**
176      * Encode pour affichage en html, sans encoder les espaces en nbsp (insécables) et les retours chariots en br.
177      * @param text message à encoder
178      * @return String
179      */

180     static String htmlEncodeButNotSpaceAndNewLine(String text) {
181         return I18N.htmlEncode(text, falsefalse);
182     }
183
184     public static String getCsrfTokenUrlPart() {
185         if (CSRF_PROTECTION_ENABLED) {
186             final HttpSession currentSession = SessionListener.getCurrentSession();
187             if (currentSession != null) {
188                 String csrfToken = (String) currentSession
189                         .getAttribute(SessionListener.CSRF_TOKEN_SESSION_NAME);
190                 if (csrfToken == null) {
191                     final byte[] bytes = new byte[16];
192                     new SecureRandom().nextBytes(bytes);
193                     csrfToken = new String(Base64Coder.encode(bytes));
194                     // '+' would break in the url parameters
195                     csrfToken = csrfToken.replace('+', '0').replace('/', '1');
196                     currentSession.setAttribute(SessionListener.CSRF_TOKEN_SESSION_NAME, csrfToken);
197                 }
198                 return "&amp;" + HttpParameter.TOKEN + '=' + csrfToken;
199             }
200         }
201         return "";
202     }
203
204     static boolean isPdfEnabled() {
205         return Parameters.isPdfEnabled();
206     }
207 }
208