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.text.DecimalFormat;
23 import java.util.List;
24
25 import net.bull.javamelody.internal.common.I18N;
26 import net.bull.javamelody.internal.common.Parameters;
27 import net.bull.javamelody.internal.model.CacheInformations;
28
29 /**
30  * Partie du rapport html pour les caches de données.
31  * @author Emeric Vernat
32  */

33 public class HtmlCacheInformationsReport extends HtmlAbstractReport {
34     private final List<CacheInformations> cacheInformationsList;
35     private final DecimalFormat integerFormat = I18N.createIntegerFormat();
36     private final boolean hitsRatioEnabled;
37     private final boolean configurationEnabled;
38     private final boolean systemActionsEnabled = Parameters.isSystemActionsEnabled();
39
40     HtmlCacheInformationsReport(List<CacheInformations> cacheInformationsList, Writer writer) {
41         super(writer);
42         assert cacheInformationsList != null;
43
44         this.cacheInformationsList = cacheInformationsList;
45         this.hitsRatioEnabled = isHitsRatioEnabled(cacheInformationsList);
46         this.configurationEnabled = isConfigurationEnabled(cacheInformationsList);
47     }
48
49     @Override
50     void toHtml() throws IOException {
51         writeCaches(cacheInformationsList);
52         write("<div align='right' class='noPrint'>");
53         if (!hitsRatioEnabled) {
54             writeln("#caches_statistics_enable#<br/>");
55         }
56         if (systemActionsEnabled) {
57             writeln("<a href='?action=clear_caches" + getCsrfTokenUrlPart()
58                     + "' class='confirm' data-confirm='"
59                     + htmlEncodeButNotSpaceAndNewLine(getString("confirm_purge_caches")) + "'>");
60             writeln("<img src='?resource=user-trash.png' width='18' height='18' alt=\"#Purge_caches#\" /> #Purge_caches#</a>");
61             writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
62         }
63         // writeDirectly pour éviter traduction car # dans l'url
64         writeDirectly(
65                 "<a href='http://www.ehcache.org/apidocs/2.9/net/sf/ehcache/config/CacheConfiguration.html#field_summary'");
66         writeln("target='_blank'>Configuration reference</a></div>");
67     }
68
69     private void writeCaches(List<CacheInformations> cacheInformations) throws IOException {
70         final HtmlTable table = new HtmlTable();
71         table.beginTable(getString("Caches"));
72         write("<th>#Cache#</th>");
73         if (configurationEnabled) {
74             write("<th class='sorttable_numeric'>#Pourcentage_memoire_utilise#</th>");
75         }
76         write("<th class='sorttable_numeric'>#Nb_objets_en_memoire#</th>");
77         write("<th class='sorttable_numeric'>#Nb_objets_sur_disque#</th>");
78         if (hitsRatioEnabled) {
79             write("<th class='sorttable_numeric'>");
80             write(getString("Efficacite_cache_memoire").replace("\n""<br/>"));
81             write("</th><th class='sorttable_numeric'>");
82             write(getString("Efficacite_cache").replace("\n""<br/>"));
83             write("</th>");
84         }
85         if (configurationEnabled) {
86             write("<th>#Configuration#</th>");
87         }
88         if (systemActionsEnabled) {
89             write("<th class='noPrint'>#Purger#</th>");
90         }
91         for (final CacheInformations cacheInfos : cacheInformations) {
92             table.nextRow();
93             writeCacheInformations(cacheInfos);
94         }
95         table.endTable();
96     }
97
98     private void writeCacheInformations(CacheInformations cacheInformations) throws IOException {
99         write("<td>");
100         writeDirectly("<a href='?part=cacheKeys&amp;cacheId="
101                 + urlEncode(cacheInformations.getName()) + "'>");
102         if (cacheInformations.getName().isEmpty()) {
103             // cache name may be empty
104             write("--");
105         } else {
106             writeDirectly(htmlEncodeButNotSpace(cacheInformations.getName()));
107         }
108         writeln("</a>");
109         final String nextColumnAlignRight = "</td> <td align='right'>";
110         if (configurationEnabled) {
111             write(nextColumnAlignRight);
112             write(integerFormat.format(cacheInformations.getInMemoryPercentUsed()));
113         }
114         write(nextColumnAlignRight);
115         write(integerFormat.format(cacheInformations.getInMemoryObjectCount()));
116         write(nextColumnAlignRight);
117         write(integerFormat.format(cacheInformations.getOnDiskObjectCount()));
118         if (hitsRatioEnabled) {
119             write(nextColumnAlignRight);
120             write(integerFormat.format(cacheInformations.getInMemoryHitsRatio()));
121             write(nextColumnAlignRight);
122             write(integerFormat.format(cacheInformations.getHitsRatio()));
123         }
124         if (configurationEnabled) {
125             write("</td> <td>");
126             write(cacheInformations.getConfiguration());
127         }
128
129         write("</td>");
130
131         if (systemActionsEnabled) {
132             write("<td align='center' class='noPrint'>");
133             final String confirmClearCache = htmlEncodeButNotSpaceAndNewLine(
134                     getFormattedString("confirm_purge_cache", cacheInformations.getName()));
135             // writeDirectly pour ne pas gérer de traductions si le nom contient '#'
136             writeDirectly("<a href='?action=clear_cache&amp;cacheId="
137                     + urlEncode(cacheInformations.getName()) + getCsrfTokenUrlPart()
138                     + "' class='confirm' data-confirm='" + confirmClearCache + "'>");
139             final String title = htmlEncode(
140                     getFormattedString("Purge_cache", cacheInformations.getName()));
141             writeDirectly("<img src='?resource=user-trash.png' width='16' height='16' alt='" + title
142                     + "' title='" + title + "' /></a>");
143             write("</td>");
144         }
145     }
146
147     public static boolean isHitsRatioEnabled(List<CacheInformations> cacheInformationsList) {
148         for (final CacheInformations cacheInformations : cacheInformationsList) {
149             if (cacheInformations.getHitsRatio() >= 0
150                     || cacheInformations.getInMemoryHitsRatio() >= 0) {
151                 return true;
152             }
153         }
154         return false;
155     }
156
157     public static boolean isConfigurationEnabled(List<CacheInformations> cacheInformationsList) {
158         for (final CacheInformations cacheInformations : cacheInformationsList) {
159             if (cacheInformations.getConfiguration() != null) {
160                 return true;
161             }
162         }
163         return false;
164     }
165
166     void writeCacheWithKeys(String cacheId, boolean withoutHeaders) throws IOException {
167         assert cacheInformationsList.size() == 1;
168         if (!withoutHeaders) {
169             writeBackAndRefreshLinksForCache(cacheId);
170             writeln("<br/>");
171
172             writeTitle("caches.png",
173                     getFormattedString("Keys_cache", htmlEncodeButNotSpace(cacheId)));
174         }
175         writeCaches(cacheInformationsList);
176
177         writeln("<br/><b>#Keys#</b>");
178         writeCacheKeys(cacheInformationsList.get(0));
179     }
180
181     private void writeBackAndRefreshLinksForCache(String cacheId) throws IOException {
182         writeln("<div class='noPrint'>");
183         writeln("<a class='back' href=''><img src='?resource=action_back.png' alt='#Retour#'/> #Retour#</a>");
184         writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
185         writeDirectly("<a href='?part=cacheKeys&amp;cacheId=" + urlEncode(cacheId) + "'>");
186         writeln("<img src='?resource=action_refresh.png' alt='#Actualiser#'/> #Actualiser#</a>");
187         writeln("</div>");
188     }
189
190     private void writeCacheKeys(CacheInformations cacheInformations) throws IOException {
191         final List<?> cacheKeys = cacheInformations.getCacheKeys();
192         assert cacheKeys != null;
193         if (cacheKeys.isEmpty()) {
194             write("<br/>#No_keys#");
195             return;
196         }
197         if (cacheKeys.size() > 20) {
198             writeln("<div align='right'>" + cacheKeys.size() + " #Keys#</div>");
199             writeln("<br/>");
200         }
201         final HtmlTable table = new HtmlTable();
202         table.beginTable(getString("Keys"));
203         write("<th>#Keys#</th>");
204         if (systemActionsEnabled) {
205             write("<th class='noPrint'>#Purger#</th>");
206         }
207         final String cacheNameEncoded = urlEncode(cacheInformations.getName());
208         final String csrfTokenUrlPart = getCsrfTokenUrlPart();
209         final String confirmClearCache = htmlEncodeButNotSpaceAndNewLine(
210                 getFormattedString("confirm_purge_cache", cacheInformations.getName()));
211         final String title = htmlEncode(
212                 getFormattedString("Purge_cache", cacheInformations.getName()));
213         for (final Object key : cacheKeys) {
214             if (key != null) {
215                 final String myKey = key.toString();
216                 table.nextRow();
217                 writeDirectly("<td>");
218                 writeDirectly(htmlEncodeButNotSpace(myKey));
219                 writeDirectly("</td>");
220                 if (systemActionsEnabled) {
221                     writeDirectly("<td class='noPrint containingIcon'>");
222                     writeDirectly(
223                             "<a href='?part=cacheKeys&amp;action=clear_cache_key&amp;cacheId=");
224                     writeDirectly(cacheNameEncoded);
225                     writeDirectly("&amp;cacheKey=");
226                     writeDirectly(urlEncode(myKey));
227                     writeDirectly(csrfTokenUrlPart);
228                     writeDirectly("' class='confirm' data-confirm='");
229                     writeDirectly(confirmClearCache);
230                     writeDirectly("'>");
231                     writeDirectly(
232                             "<img src='?resource=user-trash.png' width='16' height='16' alt='");
233                     writeDirectly(title);
234                     writeDirectly("' title='");
235                     writeDirectly(title);
236                     writeDirectly("' /></a>");
237                     writeDirectly("</td>");
238                 }
239             }
240         }
241         table.endTable();
242         writeln("<br/>");
243         writeln("<div align='right'>" + cacheKeys.size() + " #Keys#</div>");
244     }
245 }
246