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.List;
25
26 import net.bull.javamelody.internal.common.I18N;
27 import net.bull.javamelody.internal.common.Parameters;
28 import net.bull.javamelody.internal.model.ThreadInformations;
29
30
34 public class HtmlThreadInformationsReport extends HtmlAbstractReport {
35 private final List<ThreadInformations> threadInformationsList;
36 private final DecimalFormat integerFormat = I18N.createIntegerFormat();
37 private final boolean stackTraceEnabled;
38 private final boolean cpuTimeEnabled;
39 private final boolean systemActionsEnabled = Parameters.isSystemActionsEnabled();
40
41 public HtmlThreadInformationsReport(List<ThreadInformations> threadInformationsList,
42 boolean stackTraceEnabled, Writer writer) {
43 super(writer);
44 assert threadInformationsList != null;
45
46 this.threadInformationsList = threadInformationsList;
47 this.stackTraceEnabled = stackTraceEnabled;
48 this.cpuTimeEnabled = !threadInformationsList.isEmpty()
49 && threadInformationsList.get(0).getCpuTimeMillis() != -1;
50 }
51
52 @Override
53 void toHtml() throws IOException {
54 final HtmlTable table = new HtmlTable();
55 table.beginTable(getString("Threads"));
56 write("<th>#Thread#</th>");
57 write("<th>#Demon#</th><th class='sorttable_numeric'>#Priorite#</th><th>#Etat#</th>");
58 if (stackTraceEnabled) {
59 write("<th>#Methode_executee#</th>");
60 }
61 if (cpuTimeEnabled) {
62 write("<th class='sorttable_numeric'>#Temps_cpu#</th><th class='sorttable_numeric'>#Temps_user#</th>");
63 }
64 if (systemActionsEnabled) {
65 writeln("<th class='noPrint'>#Interrupt#</th>");
66 writeln("<th class='noPrint'>#Tuer#</th>");
67 }
68 for (final ThreadInformations threadInformations : threadInformationsList) {
69 table.nextRow();
70 writeThreadInformations(threadInformations);
71 }
72 table.endTable();
73 writeln("<div align='right'>");
74 writeln("#Temps_threads#");
75 writeln("</div>");
76 }
77
78 void writeDeadlocks() throws IOException {
79 final List<ThreadInformations> deadlockedThreads = getDeadLockedThreads();
80 if (!deadlockedThreads.isEmpty()) {
81 write("<div class='severe'>#Threads_deadlocks#");
82 String separator = " ";
83 for (final ThreadInformations thread : deadlockedThreads) {
84 writeDirectly(separator);
85 writeDirectly(htmlEncode(thread.getName()));
86 separator = ", ";
87 }
88 write("</div>");
89 }
90 }
91
92 public void writeThreadsDump() throws IOException {
93 final List<ThreadInformations> deadlockedThreads = getDeadLockedThreads();
94 if (!deadlockedThreads.isEmpty()) {
95 write("#Threads_deadlocks#");
96 String separator = " ";
97 for (final ThreadInformations thread : deadlockedThreads) {
98 writeDirectly(separator);
99 writeDirectly(thread.getName());
100 separator = ", ";
101 }
102 writeDirectly("\n\n");
103 }
104 if (stackTraceEnabled) {
105 for (final ThreadInformations threadInformations : threadInformationsList) {
106 writeDirectly("\"");
107 writeDirectly(threadInformations.getName());
108 writeDirectly("\"");
109 if (threadInformations.isDaemon()) {
110 writeDirectly(" daemon");
111 }
112 writeDirectly(" prio=");
113 writeDirectly(String.valueOf(threadInformations.getPriority()));
114 writeDirectly(" ");
115 writeDirectly(String.valueOf(threadInformations.getState()));
116 final List<StackTraceElement> stackTrace = threadInformations.getStackTrace();
117 if (stackTrace != null && !stackTrace.isEmpty()) {
118 for (final StackTraceElement element : stackTrace) {
119 writeDirectly("\n\t");
120 writeDirectly(element.toString());
121 }
122 }
123 writeDirectly("\n\n");
124 }
125 writeDirectly("\n");
126 }
127 }
128
129 private List<ThreadInformations> getDeadLockedThreads() {
130 final List<ThreadInformations> deadlockedThreads = new ArrayList<>();
131 for (final ThreadInformations thread : threadInformationsList) {
132 if (thread.isDeadlocked()) {
133 deadlockedThreads.add(thread);
134 }
135 }
136 return deadlockedThreads;
137 }
138
139 private void writeThreadInformations(ThreadInformations threadInformations) throws IOException {
140 write("<td>");
141 writeThreadWithStackTrace(threadInformations);
142 write("</td> <td align='center'>");
143 if (threadInformations.isDaemon()) {
144 write("#oui#");
145 } else {
146 write("#non#");
147 }
148 write("</td> <td align='right'>");
149 write(integerFormat.format(threadInformations.getPriority()));
150 write("</td> <td>");
151 write("<img src='?resource=bullets/");
152 write(getStateIcon(threadInformations));
153 write("' alt='");
154 write(String.valueOf(threadInformations.getState()));
155 write("'/>");
156 write(String.valueOf(threadInformations.getState()));
157 if (stackTraceEnabled) {
158 write("</td> <td>");
159 writeExecutedMethod(threadInformations);
160 }
161 if (cpuTimeEnabled) {
162 write("</td> <td align='right'>");
163 write(integerFormat.format(threadInformations.getCpuTimeMillis()));
164 write("</td> <td align='right'>");
165 write(integerFormat.format(threadInformations.getUserTimeMillis()));
166 }
167 writeSendThreadInterrupt(threadInformations);
168 writeKillThread(threadInformations);
169 write("</td>");
170 }
171
172 public static String getStateIcon(ThreadInformations threadInformations) {
173 switch (threadInformations.getState()) {
174 case RUNNABLE:
175 return "green.png";
176 case WAITING:
177 return "yellow.png";
178 case TIMED_WAITING:
179 if (isSleeping(threadInformations)) {
180 return "blue.png";
181 }
182 return "yellow.png";
183 case BLOCKED:
184 return "red.png";
185 case NEW:
186 case TERMINATED:
187 return "gray.png";
188 default:
189 throw new IllegalArgumentException("state inconnu" + threadInformations.getState());
190 }
191 }
192
193 private static boolean isSleeping(ThreadInformations threadInformations) {
194 final List<StackTraceElement> stackTrace = threadInformations.getStackTrace();
195 return stackTrace != null && !stackTrace.isEmpty()
196 && "sleep".equals(stackTrace.get(0).getMethodName())
197 && "java.lang.Thread".equals(stackTrace.get(0).getClassName());
198 }
199
200 void writeThreadWithStackTrace(ThreadInformations threadInformations) throws IOException {
201 final List<StackTraceElement> stackTrace = threadInformations.getStackTrace();
202 final String encodedName = htmlEncode(threadInformations.getName());
203 if (stackTrace != null && !stackTrace.isEmpty()) {
204
205 writeln("<div class='tooltip'>");
206 writeln("<em>");
207
208 writeDirectly(encodedName);
209 writeln("<br/>");
210 for (final StackTraceElement stackTraceElement : stackTrace) {
211 writeDirectly(
212 HtmlSourceReport.htmlEncodeStackTraceElement(stackTraceElement.toString()));
213 writeDirectly("<br/>");
214 }
215 writeln("</em>");
216 writeDirectly(encodedName);
217 writeln("</div>");
218 } else {
219
220 writeDirectly(encodedName);
221 }
222 }
223
224 void writeExecutedMethod(ThreadInformations threadInformations) throws IOException {
225 final String executedMethod = threadInformations.getExecutedMethod();
226 if (executedMethod != null && !executedMethod.isEmpty()) {
227 writeDirectly(HtmlSourceReport
228 .htmlEncodeStackTraceElement(threadInformations.getExecutedMethod()));
229 } else {
230 writeDirectly(" ");
231 }
232 }
233
234 void writeSendThreadInterrupt(ThreadInformations threadInformations) throws IOException {
235 if (systemActionsEnabled) {
236 write("</td> <td align='center' class='noPrint'>");
237 write("<a href='?action=send_thread_interrupt&threadId=");
238 write(threadInformations.getGlobalThreadId());
239 write(getCsrfTokenUrlPart());
240 final String confirmSendThreadInterrupt = htmlEncodeButNotSpaceAndNewLine(
241 getFormattedString("confirm_send_thread_interrupt",
242 threadInformations.getName()));
243
244 writeDirectly("' class='confirm' data-confirm='" + confirmSendThreadInterrupt + "'>");
245 final String title = htmlEncodeButNotSpaceAndNewLine(
246 getFormattedString("send_thread_interrupt", threadInformations.getName()));
247 writeDirectly("<img width='16' height='16' src='?resource=action_interrupt.png' alt='"
248 + title + "' title='" + title + "' />");
249 write("</a>");
250 }
251 }
252
253 void writeKillThread(ThreadInformations threadInformations) throws IOException {
254 if (systemActionsEnabled) {
255 write("</td> <td align='center' class='noPrint'>");
256 write("<a href='?action=kill_thread&threadId=");
257 write(threadInformations.getGlobalThreadId());
258 write(getCsrfTokenUrlPart());
259 final String confirmKillThread = htmlEncodeButNotSpaceAndNewLine(
260 getFormattedString("confirm_kill_thread", threadInformations.getName()));
261
262 writeDirectly("' class='confirm' data-confirm='" + confirmKillThread + "'>");
263 final String title = htmlEncode(
264 getFormattedString("kill_thread", threadInformations.getName()));
265 writeDirectly("<img width='16' height='16' src='?resource=stop.png' alt='" + title
266 + "' title='" + title + "' />");
267 write("</a>");
268 }
269 }
270 }
271