1
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.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import net.bull.javamelody.internal.common.I18N;
30 import net.bull.javamelody.internal.common.Parameters;
31 import net.bull.javamelody.internal.model.Counter;
32 import net.bull.javamelody.internal.model.CounterRequest;
33 import net.bull.javamelody.internal.model.CounterRequestContext;
34 import net.bull.javamelody.internal.model.PID;
35 import net.bull.javamelody.internal.model.Period;
36 import net.bull.javamelody.internal.model.ThreadInformations;
37
38
42 public class HtmlCounterRequestContextReport extends HtmlAbstractReport {
43 private final List<CounterRequestContext> rootCurrentContexts;
44 private final Map<String, HtmlCounterReport> counterReportsByCounterName;
45 private final Map<Long, ThreadInformations> threadInformationsByThreadId;
46 private final boolean childHitsDisplayed;
47 private final DecimalFormat integerFormat = I18N.createIntegerFormat();
48 private final long timeOfSnapshot = System.currentTimeMillis();
49 private final boolean stackTraceEnabled;
50 private final int maxContextsDisplayed;
51 private final boolean systemActionsEnabled = Parameters.isSystemActionsEnabled();
52 private final HtmlThreadInformationsReport htmlThreadInformationsReport;
53
54
58 public static class CounterRequestContextReportHelper {
59 private final List<CounterRequestContext> contexts;
60 private final boolean childHitsDisplayed;
61 private final Map<String, CounterRequest> counterRequestsByRequestName = new HashMap<>();
62
63 public CounterRequestContextReportHelper(List<CounterRequestContext> contexts,
64 boolean childHitsDisplayed) {
65 super();
66 assert contexts != null;
67 this.contexts = contexts;
68 this.childHitsDisplayed = childHitsDisplayed;
69 }
70
71 public List<int[]> getRequestValues() {
72 final List<int[]> result = new ArrayList<>();
73 final int contextsSize = contexts.size();
74 final int[] durationMeans = new int[contextsSize];
75 final int[] cpuTimes = new int[contextsSize];
76 final int[] cpuTimesMeans = new int[contextsSize];
77
78
79 int i = 0;
80 for (final CounterRequestContext context : contexts) {
81 final CounterRequest counterRequest = getCounterRequest(context);
82 durationMeans[i] = counterRequest.getMean();
83 cpuTimesMeans[i] = counterRequest.getCpuTimeMean();
84 if (cpuTimesMeans[i] >= 0) {
85 cpuTimes[i] = context.getCpuTime();
86 } else {
87 cpuTimes[i] = -1;
88 }
89
90
91
92
93
94
95 i++;
96 }
97 result.add(durationMeans);
98 result.add(cpuTimes);
99 result.add(cpuTimesMeans);
100
101
102 if (childHitsDisplayed) {
103 final int[] totalChildHits = new int[contextsSize];
104 final int[] childHitsMeans = new int[contextsSize];
105 final int[] totalChildDurationsSum = new int[contextsSize];
106 final int[] childDurationsMeans = new int[contextsSize];
107 i = 0;
108 for (final CounterRequestContext context : contexts) {
109 totalChildHits[i] = getValueOrIgnoreIfNoChildHitForContext(context,
110 context.getTotalChildHits());
111 final CounterRequest counterRequest = getCounterRequest(context);
112 childHitsMeans[i] = getValueOrIgnoreIfNoChildHitForContext(context,
113 counterRequest.getChildHitsMean());
114 totalChildDurationsSum[i] = getValueOrIgnoreIfNoChildHitForContext(context,
115 context.getTotalChildDurationsSum());
116 childDurationsMeans[i] = getValueOrIgnoreIfNoChildHitForContext(context,
117 counterRequest.getChildDurationsMean());
118 i++;
119 }
120 result.add(totalChildHits);
121 result.add(childHitsMeans);
122 result.add(totalChildDurationsSum);
123 result.add(childDurationsMeans);
124 }
125 return result;
126 }
127
128 private static int getValueOrIgnoreIfNoChildHitForContext(CounterRequestContext context,
129 int value) {
130 if (context.getParentCounter().getChildCounterName() == null) {
131
132
133
134
135 return -1;
136 }
137 return value;
138 }
139
140 CounterRequest getCounterRequest(CounterRequestContext context) {
141 final String requestName = context.getRequestName();
142 CounterRequest counterRequest = counterRequestsByRequestName.get(requestName);
143 if (counterRequest == null) {
144 counterRequest = context.getParentCounter().getCounterRequest(context);
145 counterRequestsByRequestName.put(requestName, counterRequest);
146 }
147 return counterRequest;
148 }
149 }
150
151 HtmlCounterRequestContextReport(List<CounterRequestContext> rootCurrentContexts,
152 Map<String, HtmlCounterReport> counterReportsByCounterName,
153 List<ThreadInformations> threadInformationsList, boolean stackTraceEnabled,
154 int maxContextsDisplayed, Writer writer) {
155 super(writer);
156 assert rootCurrentContexts != null;
157 assert threadInformationsList != null;
158
159 this.rootCurrentContexts = rootCurrentContexts;
160 if (counterReportsByCounterName == null) {
161 this.counterReportsByCounterName = new HashMap<>();
162 } else {
163 this.counterReportsByCounterName = counterReportsByCounterName;
164 }
165 this.threadInformationsByThreadId = new HashMap<>(threadInformationsList.size());
166 for (final ThreadInformations threadInformations : threadInformationsList) {
167 this.threadInformationsByThreadId.put(threadInformations.getId(), threadInformations);
168 }
169 boolean oneRootHasChild = false;
170 for (final CounterRequestContext rootCurrentContext : rootCurrentContexts) {
171 if (rootCurrentContext.hasChildHits()) {
172 oneRootHasChild = true;
173 break;
174 }
175 }
176 this.childHitsDisplayed = oneRootHasChild;
177 this.htmlThreadInformationsReport = new HtmlThreadInformationsReport(threadInformationsList,
178 stackTraceEnabled, writer);
179 this.stackTraceEnabled = stackTraceEnabled;
180 this.maxContextsDisplayed = maxContextsDisplayed;
181 }
182
183 @Override
184 void toHtml() throws IOException {
185 if (rootCurrentContexts.isEmpty()) {
186 writeln("#Aucune_requete_en_cours#");
187 return;
188 }
189 writeContexts(Collections.singletonList(rootCurrentContexts.get(0)));
190 writeln("<div align='right' class='noPrint'>");
191 writeln(getFormattedString("nb_requete_en_cours",
192 integerFormat.format(rootCurrentContexts.size())));
193 final String separator = " ";
194 if (isPdfEnabled()) {
195 writeln(separator);
196 write("<a href='?part=currentRequests&format=pdf' title='#afficher_PDF#'>");
197 write("<img src='?resource=pdf.png' alt='#PDF#'/> #PDF#</a>");
198 }
199 writeln(separator);
200 if (rootCurrentContexts.size() <= maxContextsDisplayed) {
201 writeln("<a href='?part=currentRequests' title='#Requetes_en_cours#'>");
202 writeln("<img src='?resource=hourglass.png' alt='#Requetes_en_cours#' width='16' height='16'/>");
203 writeln("#Voir_dans_une_nouvelle_page#</a>");
204 writeln(separator);
205
206 final String counterName = rootCurrentContexts.get(0).getParentCounter().getName();
207
208 writeShowHideLink("contextDetails" + counterName + PID.getPID(), "#Details#");
209 writeln(separator);
210 writeln("</div> ");
211 writeln("<div id='contextDetails" + counterName + PID.getPID()
212 + "' class='displayNone'>");
213 writeContexts(rootCurrentContexts);
214 writeln("</div>");
215 } else {
216
217
218 writeln("<a href='?part=currentRequests' title='#Requetes_en_cours#'>#Details#</a>");
219 writeln(separator);
220 writeln("</div> ");
221 }
222 }
223
224 void writeTitleAndDetails() throws IOException {
225 writeTitle("hourglass.png", getString("Requetes_en_cours"));
226 write("<br/>");
227
228 if (rootCurrentContexts.isEmpty()) {
229 writeln("#Aucune_requete_en_cours#");
230 return;
231 }
232 writeContexts(rootCurrentContexts);
233
234 writeln("<div align='right'>");
235 writeln(getFormattedString("nb_requete_en_cours",
236 integerFormat.format(rootCurrentContexts.size())));
237 writeln("</div>");
238 }
239
240 private void writeContexts(List<CounterRequestContext> contexts) throws IOException {
241 boolean displayRemoteUser = false;
242 for (final CounterRequestContext context : contexts) {
243 if (context.getRemoteUser() != null) {
244 displayRemoteUser = true;
245 break;
246 }
247 }
248 final HtmlTable table = new HtmlTable();
249 table.beginTable(getString("Requetes_en_cours"));
250 write("<th>#Thread#</th>");
251 if (displayRemoteUser) {
252 write("<th>#Utilisateur#</th>");
253 }
254 write("<th>#Requete#</th>");
255 write("<th class='sorttable_numeric'>#Duree_ecoulee#</th><th class='sorttable_numeric'>#Temps_moyen#</th>");
256 write("<th class='sorttable_numeric'>#Temps_cpu#</th><th class='sorttable_numeric'>#Temps_cpu_moyen#</th>");
257
258
259
260 if (childHitsDisplayed) {
261 final String childCounterName = contexts.get(0).getParentCounter()
262 .getChildCounterName();
263 write("<th class='sorttable_numeric'>"
264 + getFormattedString("hits_fils", childCounterName));
265 write("</th><th class='sorttable_numeric'>"
266 + getFormattedString("hits_fils_moyens", childCounterName));
267 write("</th><th class='sorttable_numeric'>"
268 + getFormattedString("temps_fils", childCounterName));
269 write("</th><th class='sorttable_numeric'>"
270 + getFormattedString("temps_fils_moyen", childCounterName) + "</th>");
271 }
272 if (stackTraceEnabled) {
273 write("<th>#Methode_executee#</th>");
274 }
275 if (systemActionsEnabled) {
276 writeln("<th class='noPrint'>#Tuer#</th>");
277 }
278 for (final CounterRequestContext context : contexts) {
279 table.nextRow();
280 writeContext(context, displayRemoteUser);
281 }
282 table.endTable();
283 }
284
285 private void writeContext(CounterRequestContext rootContext, boolean displayRemoteUser)
286 throws IOException {
287
288
289 final ThreadInformations threadInformations = threadInformationsByThreadId
290 .get(rootContext.getThreadId());
291 write("<td valign='top'>");
292 final String espace = " ";
293 if (threadInformations == null) {
294 write(espace);
295 } else {
296 htmlThreadInformationsReport.writeThreadWithStackTrace(threadInformations);
297 }
298 if (displayRemoteUser) {
299 write("</td> <td valign='top'>");
300 if (rootContext.getRemoteUser() == null) {
301 write(espace);
302 } else {
303 write(rootContext.getRemoteUser());
304 }
305 }
306 final List<CounterRequestContext> contexts = new ArrayList<>(3);
307 contexts.add(rootContext);
308 contexts.addAll(rootContext.getChildContexts());
309 final CounterRequestContextReportHelper counterRequestContextReportHelper = new CounterRequestContextReportHelper(
310 contexts, childHitsDisplayed);
311 write("</td> <td>");
312 writeRequests(contexts, counterRequestContextReportHelper);
313
314 write("</td> <td align='right' valign='top'>");
315 writeDurations(contexts);
316
317 for (final int[] requestValues : counterRequestContextReportHelper.getRequestValues()) {
318 writeRequestValues(requestValues);
319 }
320
321 if (stackTraceEnabled) {
322 write("</td> <td valign='top'>");
323 if (threadInformations == null) {
324 write(espace);
325 } else {
326 htmlThreadInformationsReport.writeExecutedMethod(threadInformations);
327 }
328 }
329 if (threadInformations == null) {
330 write("</td> <td class='noPrint'>");
331 write(espace);
332 } else {
333 htmlThreadInformationsReport.writeKillThread(threadInformations);
334 }
335 write("</td>");
336 }
337
338 private void writeRequests(List<CounterRequestContext> contexts,
339 CounterRequestContextReportHelper counterRequestContextReportHelper)
340 throws IOException {
341 int margin = 0;
342 for (final CounterRequestContext context : contexts) {
343 write("<div data-margin-left-px='");
344 write(Integer.toString(margin));
345 writeln("' class='wrappedText'>");
346 writeRequest(context, counterRequestContextReportHelper);
347 write("</div>");
348 margin += 10;
349 }
350 }
351
352 private void writeRequest(CounterRequestContext context,
353 CounterRequestContextReportHelper counterRequestContextReportHelper)
354 throws IOException {
355 final Counter parentCounter = context.getParentCounter();
356 if (parentCounter.getIconName() != null) {
357 write("<img src='?resource=");
358 write(parentCounter.getIconName());
359 write("' alt='");
360 write(parentCounter.getName());
361 write("' width='16' height='16' /> ");
362 }
363
364 final HtmlCounterReport counterReport = getCounterReport(parentCounter, Period.TOUT);
365 final CounterRequest counterRequest = counterRequestContextReportHelper
366 .getCounterRequest(context);
367 counterReport.writeRequestName(counterRequest.getId(), context.getCompleteRequestName(),
368 HtmlCounterReport.isRequestGraphDisplayed(parentCounter), true, false);
369 }
370
371 private HtmlCounterReport getCounterReport(Counter parentCounter, Period period) {
372 HtmlCounterReport counterReport = counterReportsByCounterName.get(parentCounter.getName());
373 if (counterReport == null) {
374 counterReport = new HtmlCounterReport(parentCounter, period.getRange(), getWriter());
375 counterReportsByCounterName.put(parentCounter.getName(), counterReport);
376 }
377 return counterReport;
378 }
379
380 private void writeDurations(List<CounterRequestContext> contexts) throws IOException {
381 boolean first = true;
382 for (final CounterRequestContext context : contexts) {
383 if (!first) {
384 writeln("<br/>");
385 }
386 final int duration = context.getDuration(timeOfSnapshot);
387
388 final Counter parentCounter = context.getParentCounter();
389 if (parentCounter.getIconName() != null) {
390
391
392
393 write("<img src='?resource=");
394 write(parentCounter.getIconName());
395 write("' alt='");
396 write(parentCounter.getName());
397 write("' width='16' height='16' /> ");
398 }
399
400 final HtmlCounterReport counterReport = counterReportsByCounterName
401 .get(parentCounter.getName());
402 write("<span class='");
403 write(counterReport.getSlaHtmlClass(duration));
404 write("'>");
405 write(integerFormat.format(duration));
406 write("</span>");
407 first = false;
408 }
409 }
410
411 private void writeRequestValues(int[] requestValues) throws IOException {
412 write("</td> <td align='right' valign='top'>");
413 boolean first = true;
414 for (final int value : requestValues) {
415 if (!first) {
416 writeln("<br/>");
417 }
418 if (value == -1) {
419 write(" ");
420 } else {
421 write(integerFormat.format(value));
422 }
423 first = false;
424 }
425 }
426 }
427