001: /***
002: * Retrotranslator: a Java bytecode transformer that translates Java classes
003: * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
004: *
005: * Copyright (c) 2005 - 2008 Taras Puchko
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * 3. Neither the name of the copyright holders nor the names of its
017: * contributors may be used to endorse or promote products derived from
018: * this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
024: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
025: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
026: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
027: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
028: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
029: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
030: * THE POSSIBILITY OF SUCH DAMAGE.
031: */package net.sf.retrotranslator.runtime.java.lang;
032:
033: import static java.lang.Thread.UncaughtExceptionHandler;
034: import java.util.*;
035: import net.sf.retrotranslator.registry.Advanced;
036: import net.sf.retrotranslator.runtime.impl.WeakIdentityTable;
037:
038: /**
039: * @author Taras Puchko
040: */
041: public class _Thread {
042:
043: private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
044:
045: private static final WeakIdentityTable<Thread, _Thread> threads = new WeakIdentityTable<Thread, _Thread>() {
046: protected _Thread initialValue() {
047: return new _Thread();
048: }
049: };
050:
051: private static long lastId;
052: private static UncaughtExceptionHandler defaultHandler;
053:
054: private volatile long id;
055: private volatile boolean started;
056: private UncaughtExceptionHandler handler;
057:
058: public static class BasicThreadBuilder {
059:
060: private ThreadGroup group;
061: private Runnable target;
062:
063: protected BasicThreadBuilder(ThreadGroup group, Runnable target) {
064: this .group = group;
065: this .target = target;
066: }
067:
068: public ThreadGroup argument1() {
069: return group;
070: }
071:
072: public Runnable argument2() {
073: return target;
074: }
075: }
076:
077: public static class AdvancedThreadBuilder {
078:
079: private ThreadGroup group;
080: private Runnable target;
081: private String name;
082: private long stackSize;
083:
084: protected AdvancedThreadBuilder(ThreadGroup group,
085: Runnable target, String name, long stackSize) {
086: this .group = group;
087: this .target = target;
088: this .name = name;
089: this .stackSize = stackSize;
090: }
091:
092: public ThreadGroup argument1() {
093: return group;
094: }
095:
096: public Runnable argument2() {
097: return target;
098: }
099:
100: public String argument3() {
101: return name;
102: }
103:
104: public long argument4() {
105: return stackSize;
106: }
107: }
108:
109: private static class RunnableWrapper implements Runnable {
110:
111: private Runnable target;
112:
113: private RunnableWrapper(Runnable target) {
114: this .target = target;
115: }
116:
117: public void run() {
118: try {
119: target.run();
120: } catch (Throwable e) {
121: processException(e);
122: }
123: }
124:
125: protected static Runnable wrap(Runnable target) {
126: return target == null || target instanceof RunnableWrapper ? target
127: : new RunnableWrapper(target);
128: }
129: }
130:
131: // Referenced from translated bytecode
132: public static void handleUncaughtException(Throwable throwable) {
133: processException(throwable);
134: }
135:
136: protected static void processException(Throwable throwable) {
137: if (new Exception().getStackTrace().length <= 4) {
138: Thread thread = Thread.currentThread();
139: UncaughtExceptionHandler handler = threads.obtain(thread)
140: .getHandler();
141: if (handler == null) {
142: handler = getDefaultUncaughtExceptionHandler();
143: }
144: if (handler != null) {
145: handler.uncaughtException(thread, throwable);
146: return;
147: }
148: }
149: try {
150: throw throwable;
151: } catch (RuntimeException e) {
152: throw e;
153: } catch (Error e) {
154: throw e;
155: } catch (Throwable t) {
156: throw new Error(t);
157: }
158: }
159:
160: @Advanced({"Thread.setDefaultUncaughtExceptionHandler","Thread.setUncaughtExceptionHandler"})
161: public static Runnable convertConstructorArguments(Runnable target) {
162: return RunnableWrapper.wrap(target);
163: }
164:
165: @Advanced({"Thread.setDefaultUncaughtExceptionHandler","Thread.setUncaughtExceptionHandler"})
166: public static BasicThreadBuilder createInstanceBuilder(
167: ThreadGroup group, Runnable target) {
168: return new BasicThreadBuilder(group, RunnableWrapper
169: .wrap(target));
170: }
171:
172: @Advanced({"Thread.setDefaultUncaughtExceptionHandler","Thread.setUncaughtExceptionHandler"})
173: public static AdvancedThreadBuilder createInstanceBuilder(
174: Runnable target, String name) {
175: return new AdvancedThreadBuilder(null, RunnableWrapper
176: .wrap(target), name, 0);
177: }
178:
179: @Advanced({"Thread.setDefaultUncaughtExceptionHandler","Thread.setUncaughtExceptionHandler"})
180: public static AdvancedThreadBuilder createInstanceBuilder(
181: ThreadGroup group, Runnable target, String name) {
182: return new AdvancedThreadBuilder(group, RunnableWrapper
183: .wrap(target), name, 0);
184: }
185:
186: @Advanced({"Thread.setDefaultUncaughtExceptionHandler","Thread.setUncaughtExceptionHandler"})
187: public static AdvancedThreadBuilder createInstanceBuilder(
188: ThreadGroup group, Runnable target, String name,
189: long stackSize) {
190: return new AdvancedThreadBuilder(group, RunnableWrapper
191: .wrap(target), name, stackSize);
192: }
193:
194: public static synchronized UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
195: return defaultHandler;
196: }
197:
198: @Advanced("Thread.setDefaultUncaughtExceptionHandler")
199: public static synchronized void setDefaultUncaughtExceptionHandler(
200: UncaughtExceptionHandler handler) {
201: defaultHandler = handler;
202: }
203:
204: public static long getId(Thread thread) {
205: return threads.obtain(thread).getId();
206: }
207:
208: private long getId() {
209: if (id == 0) {
210: synchronized (threads) {
211: while (id == 0) {
212: id = ++lastId;
213: }
214: }
215: }
216: return id;
217: }
218:
219: public static StackTraceElement[] getStackTrace(Thread thread) {
220: return thread == Thread.currentThread() ? getStackTrace()
221: : EMPTY_STACK_TRACE;
222: }
223:
224: private static StackTraceElement[] getStackTrace() {
225: return new Throwable().getStackTrace();
226: }
227:
228: public static UncaughtExceptionHandler getUncaughtExceptionHandler(
229: Thread thread) {
230: UncaughtExceptionHandler handler = threads.obtain(thread)
231: .getHandler();
232: return handler != null ? handler : thread.getThreadGroup();
233: }
234:
235: @Advanced("Thread.setUncaughtExceptionHandler")
236: public static void setUncaughtExceptionHandler(Thread thread,
237: UncaughtExceptionHandler handler) {
238: threads.obtain(thread).setHandler(handler);
239: }
240:
241: private synchronized UncaughtExceptionHandler getHandler() {
242: return handler;
243: }
244:
245: private synchronized void setHandler(
246: UncaughtExceptionHandler handler) {
247: this .handler = handler;
248: }
249:
250: @Advanced("Thread.getState")
251: public static void start(Thread thread) {
252: thread.start();
253: threads.obtain(thread).started = true;
254: }
255:
256: @Advanced("Thread.getState")
257: public static Thread.State getState(Thread thread) {
258: if (thread.isAlive()) {
259: return Thread.State.RUNNABLE;
260: }
261: if (threads.obtain(thread).started) {
262: return Thread.State.TERMINATED;
263: }
264: return Thread.State.NEW;
265: }
266:
267: public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
268: HashMap<Thread, StackTraceElement[]> result = new HashMap<Thread, StackTraceElement[]>();
269: Thread currentThread = Thread.currentThread();
270: ThreadGroup group = currentThread.getThreadGroup();
271: ThreadGroup parent;
272: while ((parent = group.getParent()) != null) {
273: group = parent;
274: }
275: Thread[] threads = new Thread[group.activeCount() + 1];
276: int count = group.enumerate(threads);
277: while (count == threads.length) {
278: threads = new Thread[threads.length * 2];
279: count = group.enumerate(threads);
280: }
281: for (int i = 0; i < count; i++) {
282: Thread thread = threads[i];
283: if (thread.isAlive()) {
284: result.put(thread,
285: thread == currentThread ? getStackTrace()
286: : EMPTY_STACK_TRACE);
287: }
288: }
289: return result;
290: }
291:
292: }
|