JAL-3032 adds Java 8 functionality (2/2)
[jalview.git] / src2 / javajs / util / JSThread.java
1 package javajs.util;
2
3 import java.awt.Toolkit;
4 import java.awt.event.InvocationEvent;
5
6 //import javajs.J2SRequireImport;
7 import javajs.api.JSFunction;
8
9
10 /**
11  * An abstract class that takes care of simple threading in Java or JavaScript.
12  * 
13  * To use it, subclass it and complete the necessary methods.
14  * 
15  * 
16  * There are three states: INIT, LOOP, and DONE.
17  * 
18  * These states are passed into run1
19  * 
20  * 
21  * @author Bob Hanson
22  * 
23  */
24 //@J2SRequireImport(swingjs.JSToolkit.class)
25 public abstract class JSThread extends Thread implements JSFunction {
26
27         public static final int INIT = 0;
28         public static final int LOOP = 1;
29         public static final int DONE = 2;
30         
31         public static int threadCount = 0;
32
33         protected boolean isJS;
34         
35         public JSThread() {
36                 this(null, "JSThread-" + (++threadCount));
37         }
38         
39         public JSThread(String name) {
40                 this(null, name);
41         }
42         
43         public JSThread(ThreadGroup group, String name) {
44                 super(group, name);
45                 /**
46                  * @j2sNative
47                  * 
48                  * this.isJS = true;
49                  */
50                 {}
51         }
52
53         @Override
54         public void run() {
55                 run1(INIT);
56         }
57
58         @Override
59         public synchronized void start() {
60
61                 
62                 /**
63                  * @j2sNative
64                  * 
65                  *                        Clazz.load("swingjs.JSToolkit").dispatch$O$I$I(this, 1, 0);
66                  * 
67                  */
68                 {
69                         super.start();
70                 }
71
72         }
73
74         /**
75          * thread initialization
76          * 
77          * @return false to exit thread before any looping
78          */
79         protected abstract boolean myInit();
80         
81         /**
82          * check for continuing to loop
83          * 
84          * @return true if we are to continue looping
85          */
86         protected abstract boolean isLooping();
87         
88         /**
89          * 
90          * @return false to handle sleepAndReturn yourself
91          */
92         protected abstract boolean myLoop();
93         /**
94          * what to do when the DONE state is reached
95          * 
96          */
97         protected abstract void whenDone();
98         
99         /**
100          * 
101          * @return the sleep time in milliseconds
102          */
103         protected abstract int getDelayMillis();
104         
105         /**
106          * handle an exception -- state will be set to DONE no matter what you do here
107          * 
108          * @param e
109          */
110         protected abstract void onException(Exception e);
111         
112         /**
113          * anything you want done in  try{}catch(}finally().
114          * Note that this method is not fired if we are in JavaScript
115          * mode and the normal return from sleepAndReturn() is taken. 
116          *  
117          */
118         protected abstract void doFinally();
119         
120         /**
121          * a generic method that loops until done, either in Java or JavaScript.
122          * 
123          * In JavaScript it will reenter and continue at the appropriate spot.
124          * 
125          * This method may be overridden if desired.
126          * 
127          * @see org.uwi.SimThread
128          * 
129          * @param state
130          */
131         protected void run1(int state) {
132                 boolean executeFinally = true;
133                 // called by thisThread.run();
134                 try {
135                         while (!interrupted()) {
136                                 switch (state) {
137                                 case INIT:
138                                         if (!myInit())
139                                                 return;
140                                         // initial code here
141                                         state = LOOP;
142                                         continue;
143                                 case LOOP:
144                                         // to stop looping, return false from isLooping()
145                                         if (!isLooping()) {
146                                                 state = DONE;
147                                                 continue;
148                                         }
149                                         // To handle sleepAndReturn yourself, or to skip the
150                                         // sleep when desired, return false from myLoop();
151                                         // Note that doFinally must not be executed in this case.
152                                         // This is because JavaScript will do a return here
153                                         // for every loop, and Java will not.
154                                         if (myLoop() && sleepAndReturn(getDelayMillis(), state)) {
155                                                 executeFinally = false;
156                                                 return;                                         
157                                         }
158                                         continue;
159                                 case DONE:
160                                         whenDone();
161                                         // whatever
162                                         return;
163                                 }
164                         }
165                 } catch (Exception e) {
166                         onException(e);
167                         state = DONE;
168                 } finally {
169                         if (executeFinally)
170                                 doFinally();
171                 }
172                 // normal exit
173         }
174
175         /**
176          * 
177          * @param r2
178          * @param state
179          * @return true if we should interrupt (i.e. JavaScript)
180          * @throws InterruptedException
181          */
182         protected boolean sleepAndReturn(final int delay, final int state)
183                         throws InterruptedException {
184                 if (!isJS) {
185                         sleep(delay);
186                         return false;
187                 }
188
189                 // in JavaScript, we need to do this through the system event queue,
190                 // which in JSToolkit takes care of all the "thread" handling.
191
192                 final JSThread me = this;
193                 Runnable r = new Runnable() {
194                         @Override
195                         public void run() {
196                                 me.run1(state);
197                         }
198                 };
199                 /**
200                  * @j2sNative
201                  * 
202                  *            setTimeout(
203                  *              function() {
204                  *              java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent$java_awt_AWTEvent(
205                  *              Clazz.new_(java.awt.event.InvocationEvent.c$$O$Runnable,[me, r]))}, 
206                  *              delay);
207                  * 
208                  */
209                 {
210                         Toolkit.getDefaultToolkit().getSystemEventQueue()
211                                         .postEvent(new InvocationEvent(me, r));
212                 }
213                 return true;
214         }
215         
216 }