package javajs.util; import java.awt.Toolkit; import java.awt.event.InvocationEvent; //import javajs.J2SRequireImport; import javajs.api.JSFunction; /** * An abstract class that takes care of simple threading in Java or JavaScript. * * To use it, subclass it and complete the necessary methods. * * * There are three states: INIT, LOOP, and DONE. * * These states are passed into run1 * * * @author Bob Hanson * */ //@J2SRequireImport(swingjs.JSToolkit.class) public abstract class JSThread extends Thread { public static final int INIT = 0; public static final int LOOP = 1; public static final int DONE = 2; public static int threadCount = 0; protected boolean isJS = /** @j2sNative true || */false; public JSThread() { this(null, "JSThread-" + (++threadCount)); } public JSThread(String name) { this(null, name); } public JSThread(ThreadGroup group, String name) { super(group, name); } @Override public void run() { run1(INIT); } @Override public synchronized void start() { /** * @j2sNative * * Clazz.load("swingjs.JSToolkit").dispatch$O$I$I(this, 1, 0); * */ { super.start(); } } /** * thread initialization * * @return false to exit thread before any looping */ protected abstract boolean myInit(); /** * check for continuing to loop * * @return true if we are to continue looping */ protected abstract boolean isLooping(); /** * * @return false to handle sleepAndReturn yourself */ protected abstract boolean myLoop(); /** * what to do when the DONE state is reached * */ protected abstract void whenDone(); /** * * @return the sleep time in milliseconds */ protected abstract int getDelayMillis(); /** * handle an exception -- state will be set to DONE no matter what you do here * * @param e */ protected abstract void onException(Exception e); /** * anything you want done in try{}catch(}finally(). * Note that this method is not fired if we are in JavaScript * mode and the normal return from sleepAndReturn() is taken. * */ protected abstract void doFinally(); /** * a generic method that loops until done, either in Java or JavaScript. * * In JavaScript it will reenter and continue at the appropriate spot. * * This method may be overridden if desired. * * @see org.uwi.SimThread * * @param state */ protected void run1(int state) { boolean executeFinally = true; // called by thisThread.run(); try { while (!interrupted()) { switch (state) { case INIT: if (!myInit()) return; // initial code here state = LOOP; continue; case LOOP: // to stop looping, return false from isLooping() if (!isLooping()) { state = DONE; continue; } // To handle sleepAndReturn yourself, or to skip the // sleep when desired, return false from myLoop(); // Note that doFinally must not be executed in this case. // This is because JavaScript will do a return here // for every loop, and Java will not. if (myLoop() && sleepAndReturn(getDelayMillis(), state)) { executeFinally = false; return; } continue; case DONE: whenDone(); // whatever return; } } } catch (Exception e) { onException(e); state = DONE; } finally { if (executeFinally) doFinally(); } // normal exit } /** * * @param r2 * @param state * @return true if we should interrupt (i.e. JavaScript) * @throws InterruptedException */ protected boolean sleepAndReturn(final int delay, final int state) throws InterruptedException { if (!isJS) { sleep(delay); return false; } // in JavaScript, we need to do this through the system event queue, // which in JSToolkit takes care of all the "thread" handling. final JSThread me = this; Runnable r = new Runnable() { @Override public void run() { me.run1(state); } }; /** * @j2sNative * * setTimeout( * function() { * java.awt.Toolkit.getDefaultToolkit$().getSystemEventQueue$().postEvent$java_awt_AWTEvent( * Clazz.new_(java.awt.event.InvocationEvent.c$$O$Runnable,[me, r]))}, * delay); * */ { Toolkit.getDefaultToolkit().getSystemEventQueue() .postEvent(new InvocationEvent(me, r)); } return true; } }