1 /**
2  * -2010
3  */
4 package org.unicode.cldr.web;
5 
6 import java.util.concurrent.LinkedBlockingQueue;
7 
8 /**
9  * @author srl
10  *
11  *         A worker thread that performs various SurveyTool tasks, starting with
12  *         booting.
13  */
14 public class SurveyThread extends Thread {
15 
shouldStop()16     public static boolean shouldStop() {
17         SurveyTask ct = currentTask();
18         if (ct == null) {
19             return false; /* don't know. */
20         } else {
21             return !ct.running();
22         }
23     }
24 
inTask()25     public static boolean inTask() {
26         Thread th = Thread.currentThread();
27         if (th instanceof SurveyThread) {
28             return true;
29         } else {
30             return false;
31         }
32     }
33 
currentTask()34     public static SurveyTask currentTask() {
35         Thread th = Thread.currentThread();
36         if (th instanceof SurveyThread) {
37             SurveyThread st = (SurveyThread) th;
38 
39             return st.current;
40         } else {
41             return null;
42         }
43     }
44 
45     /**
46      * Are we still running?
47      */
48     boolean surveyThreadIsRunning = true;
49 
mainThreadRunning()50     boolean mainThreadRunning() {
51         return surveyThreadIsRunning;
52     }
53 
54     /**
55      * @author srl A SurveyTask is a unit of work that can be done by the
56      *         SurveyThread.
57      *
58      *         Usage: startupThread.addTask(new
59      *         SurveyThread.SurveyTask("startup") { public void run() throws
60      *         Throwable { doStartup(); } });
61      *
62      */
63     public static abstract class SurveyTask implements CLDRProgressIndicator {
64         /**
65          * Name of the task.
66          */
67         public String name;
68 
69         private boolean taskRunning = true;
70 
71         /**
72          * Request this task to stop.
73          */
stop()74         public void stop() {
75             System.err.println(this + " - stop requested.");
76             taskRunning = false;
77         }
78 
79         /**
80          * Kill this task by interrupting. (Doesn't actually kill the thread?)
81          */
kill()82         public void kill() {
83             stop();
84             theThread.interrupt();
85         }
86 
87         protected SurveyThread theThread = null;
88 
89         /**
90          * Is this task still running? Check this periodically.
91          *
92          * @return true if the task is running
93          */
running()94         public boolean running() {
95             if (theThread != null && !theThread.surveyThreadIsRunning)
96                 return false;
97             return taskRunning;
98         }
99 
100         /**
101          * C'tor. The name is the initial name of the task.
102          *
103          * @param taskName
104          */
SurveyTask(String taskName)105         public SurveyTask(String taskName) {
106             name = taskName;
107         }
108 
setName(String taskName)109         void setName(String taskName) {
110             name = taskName;
111 
112             // if possible, update current thread name.
113             Thread th = Thread.currentThread();
114             if (th instanceof SurveyThread) {
115                 SurveyThread st = (SurveyThread) th;
116                 st.setName();
117             }
118         }
119 
120         /**
121          * Get some info about the task.
122          */
123         @Override
toString()124         public String toString() {
125             StringBuilder sb = new StringBuilder(name);
126             if (!running()) {
127                 sb.append(" (not running)");
128             }
129 
130             return sb.toString();
131         }
132 
133         /**
134          * Do the work.
135          *
136          * @throws Throwable
137          *             - any exception will be noted.
138          */
run()139         abstract public void run() throws Throwable;
140 
141         // ----- CLDRProgressIndicator overrides. For now, delegate to
142         // theThread.sm
143         @Override
openProgress(String what)144         public CLDRProgressTask openProgress(String what) {
145             if (running())
146                 return theThread.sm.openProgress(what);
147             return null;
148         }
149 
150         @Override
openProgress(String what, int max)151         public CLDRProgressTask openProgress(String what, int max) {
152             if (running())
153                 return theThread.sm.openProgress(what, max);
154             return null;
155         }
156     }
157 
158     /**
159      * Debugging info on the main loop.
160      */
161     private static boolean DEBUG = false;
162 
163     /**
164      * How many tasks are remaining? 0 if none.
165      *
166      * @return Number of tasks remaining (0 if none)
167      */
tasksRemaining()168     public int tasksRemaining() {
169         return tasks.size();
170     }
171 
172     /**
173      * How many tasks of a certain kind are remaining?
174      */
tasksRemaining(@uppressWarningsR) Class ofClass)175     public int tasksRemaining(@SuppressWarnings("rawtypes") Class ofClass) {
176         int ret = 0;
177         for (SurveyTask t : tasks) {
178             if (ofClass.isInstance(t)) {
179                 ret++;
180             }
181         }
182         return ret;
183     }
184 
185     /**
186      * The current state of the thread.
187      */
188     @Override
toString()189     public String toString() {
190         return "{ST Threads: Tasks waiting:" + tasksRemaining() + ", Current:" + current + ", Running:" + surveyThreadIsRunning
191             + "}";
192     }
193 
194     /**
195      * The status, as HTML
196      */
htmlStatus()197     public String htmlStatus() {
198         if (tasksRemaining() == 0 && current == null)
199             return null;
200         StringBuffer sb = new StringBuffer();
201         if (current != null) {
202             sb.append(current);
203         }
204         if (tasksRemaining() > 0) {
205             if (sb.length() > 0) {
206                 sb.append(" * ");
207             }
208             sb.append("(waiting tasks: " + tasksRemaining() + ")");
209         }
210         return sb.toString();
211     }
212 
213     /**
214      * The current task, or null if none.
215      */
216     SurveyTask current = null;
217 
218     /**
219      * The main run loop. Perform tasks or wait.
220      */
221     @Override
run()222     public void run() {
223         if (DEBUG)
224             System.err.println("SurveyThread: Bootation.");
225         setName();
226         while (this.surveyThreadIsRunning) {
227             try {
228                 if (DEBUG)
229                     System.err.println("SurveyThread: About to take from queue (count:" + tasksRemaining() + "):");
230                 current = tasks.take();
231                 setName();
232                 if (DEBUG)
233                     System.err.println("SurveyThread: Got: " + current);
234                 current.theThread = this; // set the back pointer
235             } catch (InterruptedException e) {
236                 if (DEBUG)
237                     System.err.println("SurveyThread: Interrupted- running=" + surveyThreadIsRunning);
238             }
239             if (current != null)
240                 try {
241                 if (DEBUG)
242                     System.err.println("SurveyThread(count:" + tasksRemaining() + "): About to run: " + current);
243                 current.run();
244                 if (DEBUG)
245                     System.err.println("SurveyThread(count:" + tasksRemaining() + "): Done running : " + current);
246                 } catch (Throwable t) {
247                 if (DEBUG)
248                     System.err.println("SurveyThread(count:" + tasksRemaining() + "): Got exception on: " + current + " - "
249                         + t.toString());
250                 t.printStackTrace();
251                 SurveyMain.busted("While working on task " + current + " - " + t.toString(), t);
252                 }
253             current = null; /* done. */
254             setName();
255         }
256         if (DEBUG)
257             System.err.println("SurveyThread(count:" + tasksRemaining() + "): exitting!");
258     }
259 
260     /**
261      * Add a task to the thread list
262      *
263      * @param name
264      *            a name to override the standard name
265      * @param t
266      *            task to add
267      */
addTask(String name, SurveyTask t)268     public void addTask(String name, SurveyTask t) {
269         t.name = name;
270         this.addTask(t);
271     }
272 
273     /**
274      * Add a task, use the default name. Throws an internal error if for some
275      * reason it couldn't be added.
276      *
277      * @param t
278      */
addTask(SurveyTask t)279     public void addTask(SurveyTask t) {
280         if (!tasks.offer(t)) {
281             String complaint = "SurveyThread: can't add task " + t.name;
282             System.err.println(complaint);
283             throw new InternalError(complaint);
284         }
285     }
286 
removeTask(SurveyTask t)287     public boolean removeTask(SurveyTask t) {
288         return tasks.remove(t);
289     }
290 
291     /**
292      * Request the ST to stop at its next available opportunity.
293      */
requestStop()294     public void requestStop() {
295         surveyThreadIsRunning = false; // shutdown the next time through
296         addTask(new SurveyTask("shutdown") {
297             @Override
298             public void run() throws Throwable {
299                 System.err.println("Shutdown task: stop requested!");
300                 // add other items here.
301             }
302         });
303     }
304 
305     /**
306      *
307      */
interruptStop()308     public void interruptStop() {
309         surveyThreadIsRunning = false;
310         this.interrupt();
311     }
312 
313     /**
314      * Construct the thread. Needs a pointer to the SurveyTool..
315      *
316      * @param sm
317      */
SurveyThread(SurveyMain sm)318     SurveyThread(SurveyMain sm) {
319         this.sm = sm;
320         current = null;
321         setName();
322     }
323 
setName()324     private void setName() {
325         this.setName(toString());
326     }
327 
328     /**
329      * Main list of tasks.
330      */
331     LinkedBlockingQueue<SurveyTask> tasks = new LinkedBlockingQueue<>();
332 
333     /**
334      * Back-pointer.
335      */
336     SurveyMain sm;
337 
338     /**
339      * Try to shut down the threads cleanly.
340      */
attemptCleanShutdown()341     public void attemptCleanShutdown() {
342         boolean clean = true;
343 
344         System.err.println("SurveyThread: attempting shutdown...");
345         try {
346             if (!this.isAlive())
347                 return;
348             System.err.println("attempting requestStop()");
349             this.requestStop();
350             Thread.sleep(1000);
351             if (!this.isAlive())
352                 return;
353 
354             SurveyTask aCurrent = current;
355             if (aCurrent != null) {
356                 System.err.println("Attempting task stop on " + aCurrent + "..");
357                 aCurrent.stop();
358                 Thread.sleep(1000);
359                 if (!this.isAlive())
360                     return;
361             }
362             aCurrent = current; // in case it changed
363             if (aCurrent != null) {
364                 System.err.println("Attempting task kill on " + aCurrent + "..");
365                 aCurrent.kill();
366                 Thread.sleep(1000);
367                 if (!this.isAlive())
368                     return;
369             }
370 
371             System.err.println("Attempting interrupt stop");
372             this.interruptStop();
373             Thread.sleep(1000);
374             if (!this.isAlive())
375                 return;
376 
377             clean = false;
378             System.err.println("Give up. Could not stop thread in time.");
379         } catch (Throwable t) {
380             clean = false;
381             System.err.println("Trying to do a shutdown in SurveyThread: got " + t.toString());
382         } finally {
383             if (clean == true) {
384                 System.err.println("SurveyThread: clean shutdown.");
385             }
386         }
387     }
388 }
389