001: /**
002: *
003: */package clime.messadmin.providers.userdata;
004:
005: import java.lang.reflect.Method;
006:
007: import clime.messadmin.i18n.I18NSupport;
008: import clime.messadmin.providers.spi.ServerDataProvider;
009: import clime.messadmin.utils.StringUtils;
010:
011: /**
012: * Dumps all Threads in a pretty HTML page.
013: * @author Cédrik LIME
014: */
015: public class ThreadsDumper implements ServerDataProvider {
016: private static final String BUNDLE_NAME = ThreadsDumper.class
017: .getName();
018:
019: private static Method getStackTrace;
020: private static Method getId;
021: private static Method getState;
022: private static Method getDefaultUncaughtExceptionHandler;
023: private static Method getUncaughtExceptionHandler;
024:
025: static {
026: // @since 1.5
027: try {
028: getStackTrace = Thread.class.getMethod(
029: "getStackTrace", null);//$NON-NLS-1$
030: getId = Thread.class.getMethod("getId", null);//$NON-NLS-1$
031: getState = Thread.class.getMethod("getState", null);//$NON-NLS-1$
032: getDefaultUncaughtExceptionHandler = Thread.class
033: .getMethod(
034: "getDefaultUncaughtExceptionHandler", null);//$NON-NLS-1$
035: getUncaughtExceptionHandler = Thread.class.getMethod(
036: "getUncaughtExceptionHandler", null);//$NON-NLS-1$
037: } catch (SecurityException e) {
038: } catch (NoSuchMethodException e) {
039: }
040:
041: }
042:
043: /**
044: *
045: */
046: public ThreadsDumper() {
047: super ();
048: }
049:
050: /**
051: * {@inheritDoc}
052: */
053: public int getPriority() {
054: return 50;
055: }
056:
057: /**
058: * {@inheritDoc}
059: */
060: public String getServerDataTitle() {
061: return I18NSupport.getLocalizedMessage(BUNDLE_NAME, null,
062: "title");//$NON-NLS-1$
063: }
064:
065: /**
066: * {@inheritDoc}
067: */
068: public String getXHTMLServerData() {
069: ThreadGroup tg = Thread.currentThread().getThreadGroup();
070: while (tg.getParent() != null) {
071: tg = tg.getParent();
072: }
073: StringBuffer buffer = new StringBuffer(tg.activeCount() * 400
074: + tg.activeGroupCount() * 120);
075: Object defaultUncaughtExceptionHandler = invoke(
076: getDefaultUncaughtExceptionHandler, null, null);
077: if (defaultUncaughtExceptionHandler != null) {
078: buffer.append(I18NSupport.getLocalizedMessage(BUNDLE_NAME,
079: null, "thread_default_uncaught_exception_handler",//$NON-NLS-1$
080: new Object[] { StringUtils
081: .escapeXml(defaultUncaughtExceptionHandler
082: .toString()) }));
083: buffer.append("<br/>\n");
084: }
085: buffer.append("<dl>");
086: dump(tg, buffer);
087: buffer.append("</dl>");
088: return buffer.toString();
089: }
090:
091: private Object invoke(Method m, Object obj, Object[] args) {
092: try {
093: return m.invoke(obj, args);
094: } catch (Exception e) {
095: return null;
096: }
097: }
098:
099: protected void dump(Thread t, StringBuffer out) {
100: ClassLoader cl = t.getContextClassLoader();
101: Long idL = (Long) invoke(getId, t, null);
102: long id = (idL == null ? -1 : idL.longValue());
103: String name = StringUtils.escapeXml(t.getName());
104: int priority = t.getPriority();
105: // Object[] stackTrace = (Object[]) invoke(getStackTrace, t, null);
106: Object state = invoke(getState, t, null);
107: Object uncaughtExceptionHandler = invoke(
108: getUncaughtExceptionHandler, t, null);
109: boolean alive = t.isAlive();
110: boolean daemon = t.isDaemon();
111: boolean interrupted = t.isInterrupted();
112:
113: String style = "";
114: if (daemon) {
115: style += "list-style-type: circle;";
116: } else {
117: style += "list-style-type: disc;";
118: }
119: if (priority > Thread.NORM_PRIORITY) {
120: String color = Integer.toHexString(5 + priority
121: - Thread.NORM_PRIORITY);
122: style += " color: #" + color + color + "0000;";
123: }
124: if (priority < Thread.NORM_PRIORITY) {
125: String color = Integer.toHexString(5 + Thread.NORM_PRIORITY
126: - priority);
127: style += " color: #" + color + color + color + color
128: + color + color + ';';
129: }
130: String infoballoonId = (idL != null ? Long.toString(id) : Long
131: .toString(t.hashCode())
132: + Long.toString(Math.round(100000 * Math.random())));
133:
134: out.append("<li style=\"" + style + "\">");
135: out.append("<span id=\"").append(infoballoonId).append(
136: "\" class=\"infoballoonable\">");
137: out.append(name);
138: out.append(" [");
139: if (id >= 0) {
140: // Java 5+
141: out.append("id=" + id);
142: out.append(", state=" + state);
143: out.append(", ");
144: }
145: out.append("class=" + t.getClass().getName());
146: out.append(", pri=" + priority);
147: if (alive)
148: out.append(", alive");
149: if (daemon)
150: out.append(", daemon");
151: if (interrupted)
152: out.append(", interrupted");
153: out.append(']');
154: out.append("</span>");
155: out.append("<div id=\"").append(infoballoonId).append(
156: "-infoballoon\" class=\"infoballoon\">");
157: out.append("<table border=\"0\">");
158: out.append("<tr><th>ClassLoader</th><td><pre>").append(
159: cl == null ? null : StringUtils
160: .escapeXml(cl.toString())).append(
161: "</pre></td></tr>");
162: if (uncaughtExceptionHandler != null
163: && uncaughtExceptionHandler != t.getThreadGroup()) {
164: out.append("<tr><th>UncaughtExceptionHandler</th><td>");
165: out.append(StringUtils.escapeXml(uncaughtExceptionHandler
166: .toString()));
167: out.append("</td></tr>");
168: }
169: out.append("</table></div>");
170: out.append("</li>\n");
171: }
172:
173: protected void dump(ThreadGroup tg, StringBuffer out) {
174: int maxPriority = tg.getMaxPriority();
175: String name = tg.getName();
176: boolean daemon = tg.isDaemon();
177: boolean destroyed = tg.isDestroyed();
178: out.append("<dt>");
179: out.append(name);
180: out.append(" [class=" + tg.getClass().getName());
181: out.append(", maxpri=" + maxPriority);
182: if (daemon)
183: out.append(", daemon");
184: if (destroyed)
185: out.append(", destroyed");
186: out.append(']');
187: out.append("</dt>\n<dd>");
188: int activeCount = tg.activeCount();
189: if (activeCount > 0) {
190: out.append("Threads: <ul>\n");
191: Thread[] threads = new Thread[activeCount];
192: tg.enumerate(threads, false);
193: for (int i = 0; i < activeCount; ++i) {
194: if (threads[i] != null) {
195: dump(threads[i], out);
196: }
197: }
198: out.append("</ul>\n");
199: }
200: int activeGroupCount = tg.activeGroupCount();
201: if (activeGroupCount > 0) {
202: ThreadGroup[] threadGroups = new ThreadGroup[activeGroupCount];
203: tg.enumerate(threadGroups, false);
204: out.append("ThreadGroups: <dl>");
205: for (int i = 0; i < activeGroupCount; ++i) {
206: if (threadGroups[i] != null) {
207: dump(threadGroups[i], out);
208: }
209: }
210: out.append("</dl>\n");
211: }
212: out.append("</dd>");
213: }
214:
215: }
|