JAL-3032 adds Java 8 functionality (2/2)
[jalview.git] / src2 / javajs / util / JSThread.java
diff --git a/src2/javajs/util/JSThread.java b/src2/javajs/util/JSThread.java
new file mode 100644 (file)
index 0000000..be94c00
--- /dev/null
@@ -0,0 +1,216 @@
+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 implements JSFunction {
+
+       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;
+       
+       public JSThread() {
+               this(null, "JSThread-" + (++threadCount));
+       }
+       
+       public JSThread(String name) {
+               this(null, name);
+       }
+       
+       public JSThread(ThreadGroup group, String name) {
+               super(group, name);
+               /**
+                * @j2sNative
+                * 
+                * this.isJS = true;
+                */
+               {}
+       }
+
+       @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;
+       }
+       
+}