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