001: /**
002: * The XMOJO Project 5
003: * Copyright © 2003 XMOJO.org. All rights reserved.
004:
005: * NO WARRANTY
006:
007: * BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
008: * THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
009: * OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
010: * PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
011: * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
012: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
013: * TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE
014: * LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
015: * REPAIR OR CORRECTION.
016:
017: * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
018: * ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
019: * THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
020: * GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
021: * USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF
022: * DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
023: * PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE),
024: * EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
025: * SUCH DAMAGES.
026: **/package javax.management.timer;
027:
028: import java.util.*;
029: import java.io.*;
030:
031: /**
032: * A scheduler for running tasks in a Java VM.
033: * This class can be used to schedule a particular task at a
034: * specified time. This is basically to control effectively a number of tasks
035: * using a limited number of threads
036: */
037:
038: public class Scheduler extends Thread {
039:
040: /**
041: * The maximum numer of threads to be used in executing tasks for this
042: * scheduler
043: */
044: int MAX_THREADS = 4;
045:
046: /*
047: * To get the number of threads that this scheduler controls
048: */
049:
050: public int getMaxThreads() {
051: return MAX_THREADS;
052: }
053:
054: private static int DEFAULT_MAX_THREADS = 4;
055:
056: /*
057: * In case a scheduler is initialized without specifying the max number
058: * of threads neither in the conf file , nor in the arguments passed
059: * to the method , then what should the default number
060: */
061:
062: public static int getDefaultMaxThreads() {
063: return DEFAULT_MAX_THREADS;
064: }
065:
066: /*
067: * In case a scheduler is initialized without specifying the max number
068: * of threads neither in the conf file , nor in the arguments passed
069: * to the method , then what should the default number
070: */
071:
072: public static void setDefaultMaxThreads(int i) {
073: if ((i >= 0) && (i < 100)) {
074: DEFAULT_MAX_THREADS = i;
075: }
076: }
077:
078: /*
079: * To set/change the number of threads that this scheduler controls .
080: * Note this can be done only when the scheduler has been stopped by
081: * the stopThis or stopAll methods .
082: * The boolean returned will indicate whether the operation was successful
083: * or not .
084: */
085:
086: public boolean setMaxThreads(int i) {
087: if (isAlive())
088: return false;
089: if ((i >= 0) && (i < 100)) {
090: MAX_THREADS = i;
091: return true;
092: }
093: return false;
094: }
095:
096: /*
097: * The total number of threads which are scheduled via schedulers . that is
098: * the combined total of all active schedulers .
099: */
100: static int TOTAL_THREADS = 0;
101:
102: /*
103: * To get the total number of active threads that all the schedulers
104: * put together control.
105: */
106:
107: public static int getTotalThreads() {
108: return TOTAL_THREADS;
109: }
110:
111: // The boolean for one to be able to stop all schedulers
112: static boolean STOP_ALL = false;
113:
114: // The boolean for one to be able to stop this scheduler alone
115: boolean STOP_THIS = false;
116:
117: // the number of threads that have been stopped for this scheduler alone
118: int NUM_THREADS_STOPPED = 0;
119:
120: Vector runnables = new Vector(); // The tasks to be run
121: Vector times = new Vector(); // when to run them
122: Vector workers = new Vector(); // the guys who do the work
123: Vector ready_tasks = new Vector(); // the tasks to be run immediately
124:
125: // We will store internally reference to all the schedulers when they
126: // are instantiated . Schedulers can no longer be instantiated publicly
127:
128: private static Hashtable schedulers = new Hashtable(15);
129:
130: private static Hashtable maxThreads = new Hashtable(15);
131:
132: // The conffile which should be used to read the details of the number
133: // of threads etc .
134: private static String confFile = "conf/threads.conf";
135:
136: private static boolean readConfFile = false;
137:
138: public static String getConfFile() {
139: return confFile;
140: }
141:
142: public static void setConfFile(String s) {
143: confFile = s;
144: }
145:
146: private static synchronized void readTheConfFile() {
147: if (readConfFile)
148: return;
149: BufferedReader is = null;
150: String line = null;
151: try {
152: File ff = new File(confFile);
153: if (!ff.exists()) {
154: //System.err.println(" in 135 Scheduler "+confFile+" does not exist");
155: readConfFile = true;
156: return;
157: }
158: is = new BufferedReader(new FileReader(ff));
159: while ((line = is.readLine()) != null) {
160: if (line.trim().equals(""))
161: continue;
162: else if (line.startsWith("#"))
163: continue;
164: else {
165: StringTokenizer tok = new StringTokenizer(line);
166: if (tok.countTokens() == 2) {
167: String s = tok.nextToken();
168: int numb = -1;
169: try {
170: numb = Integer.parseInt(tok.nextToken());
171: } catch (NumberFormatException nfe) {
172: }
173: if ((numb < 0) || (numb > 100)) {
174: System.err
175: .println(" Invalid line in the conf file "
176: + confFile + " :" + line);
177: continue;
178: }
179: maxThreads.put(s, new Integer(numb));
180: } else {
181: System.err
182: .println(" Invalid line in the conf file "
183: + confFile + " :" + line);
184: }
185: }
186: }
187: } catch (IOException e) {
188: System.err.println("Scheduler File read Error:" + confFile
189: + ": " + e);
190: } catch (SecurityException anye) {
191: }
192: readConfFile = true;
193: }
194:
195: public static Scheduler createScheduler(String nam) {
196: return createScheduler(nam, -1);
197: }
198:
199: /*
200: * This is the method to create a new instance of the Scheduler
201: * and give it . If there already exists a scheduler with that name
202: * then that is returned .
203: */
204:
205: public static Scheduler createScheduler(String nam,
206: int maxThreadNumber) {
207: synchronized (schedulers) {
208: if (nam == null)
209: return null;
210: Scheduler sch = getScheduler(nam);
211: if (sch != null)
212: return sch;
213: readTheConfFile();
214: if ((maxThreadNumber <= 0) || (maxThreadNumber > 100)) {
215: Integer integ = (Integer) maxThreads.get(nam);
216: if (integ != null)
217: sch = new Scheduler(nam, integ.intValue());
218: else
219: sch = new Scheduler(nam);
220: } else
221: sch = new Scheduler(nam, maxThreadNumber);
222: schedulers.put(nam, sch);
223: //commentSystem.out.println("Instantiated "+sch.getName()+" scheduler with "+
224: //comment sch.MAX_THREADS +" threads ");
225: return sch;
226: }
227: }
228:
229: /*
230: * One should use this method to get a reference to the scheduler . If
231: * a scheduler with the given name does not exist then it returns null;
232: * I agree this method is dangerous in the sense that malicious code can call
233: * this method get reference and say suspend all scheduling .So should be
234: * used with care
235: */
236:
237: public static Scheduler getScheduler(String nam) {
238: if (nam == null)
239: return null;
240: return (Scheduler) schedulers.get(nam);
241: }
242:
243: /**
244: * The constructor initializes the worker threads which invokes the task
245: * to be scheduled at a specific time.
246: */
247: private Scheduler(String name, int maxThreads) {
248: super (name);
249: MAX_THREADS = maxThreads;
250: }
251:
252: /**
253: * The constructor initializes the worker threads which invokes the task
254: * to be scheduled at a specific time.
255: */
256: private Scheduler(String name) {
257: this (name, DEFAULT_MAX_THREADS);
258: }
259:
260: /**
261: * This methood schedules a one-time task at the specified time
262: */
263: public synchronized void scheduleTask(Runnable task, Date when) {
264: if (when == null)
265: when = new Date();
266: for (int i = 0; i < times.size(); i++) {
267: Date d = (Date) times.elementAt(i);
268: if (d.after(when)) {
269: times.insertElementAt(when, i);
270: runnables.insertElementAt(task, i);
271: return;
272: }
273: }
274: times.addElement(when);
275: runnables.addElement(task);
276: notifyAll();
277: }
278:
279: /**
280: * This methood is used to remove a task from being scheduled.
281: */
282:
283: public synchronized void removeTask(Runnable task) {
284: if (task == null)
285: return;
286: for (int i = 0; i < runnables.size(); i++) {
287: Runnable r = (Runnable) runnables.elementAt(i);
288: if (task.equals(r)) {
289: runnables.removeElement(r);
290: times.removeElementAt(i);
291: i--;
292: }
293: }
294: }
295:
296: /*
297: * If you have used stopAll method to suspend all schedulers , then using this
298: * will restart all of them
299: */
300:
301: public boolean resumeAll() {
302: synchronized (schedulers) {
303: if (!STOP_ALL)
304: return false;
305: STOP_ALL = false;
306: for (Enumeration en = schedulers.elements(); en
307: .hasMoreElements();) {
308: Scheduler sch = (Scheduler) en.nextElement();
309: sch.start();
310: }
311: }
312: return false;
313: }
314:
315: //Stops and destroys the schduler and its worker threads
316: //Cannot reuse scheduler when this method is called
317: public void killScheduler() {
318: if (STOP_ALL)
319: return;
320: STOP_THIS = true;
321: STOP_ALL = true;
322: try {
323: for (int i = 0; i < workers.size(); i++) {
324: WorkerThread worker = (WorkerThread) workers
325: .elementAt(i);
326: worker.wakeUp();
327: }
328: } catch (Throwable th) {
329: th.printStackTrace();
330: }
331: //waits at the max 1sec for the this scheduler thread to die
332: for (int i = 0; i < 50; i++) {
333: if (isAlive()) {
334: try {
335: Thread.sleep(20);
336: } catch (Exception e) {
337: }
338: } else
339: break;
340: }
341: }
342:
343: /*
344: * This method will stop not only this but all schedulers threads .
345: * so be very careful in using this .
346: * Will return false if it could not stop any thread
347: */
348:
349: public static boolean stopAll() {
350: synchronized (schedulers) {
351: if (STOP_ALL)
352: return false;
353: int count = 0;
354: STOP_ALL = true;
355: int totalorg = TOTAL_THREADS;
356: while (TOTAL_THREADS > 0) {
357: if (count >= STOP_TIME_OUT) {
358: System.err
359: .println("Schedulers did not stop properly: "
360: + (totalorg - TOTAL_THREADS)
361: + " threads stopped out of "
362: + totalorg);
363: System.err.println("The remaining " + TOTAL_THREADS
364: + " threads did not stop in "
365: + STOP_TIME_OUT + " seconds ");
366: return false;
367: }
368: try {
369: Thread.sleep(1000);
370: count++;
371: } catch (Exception e) {
372: }
373: }
374: System.out.println((totalorg - TOTAL_THREADS) + " of the "
375: + totalorg + " active threads in the control "
376: + " of the schedulers stopped");
377:
378: TOTAL_THREADS = 0;
379: return true;
380: }
381: }
382:
383: /*
384: * This method will stop this scheduler alone . The scheduler will not
385: * clean up the runnables queue by calling this method . One can restart
386: * by invoking the start method . If you want this scheduler to get
387: * cleaned up invoke the cleanup method after invoking this method
388: * Will return false if it could not stop any thread
389: */
390:
391: public boolean stopThis() {
392: int count = 0;
393: STOP_THIS = true;
394: while (NUM_THREADS_STOPPED < MAX_THREADS) {
395: if (count >= STOP_TIME_OUT) {
396: System.err.println("Scheduler:" + getName()
397: + " did not stop properly: "
398: + NUM_THREADS_STOPPED
399: + " threads stopped out of " + MAX_THREADS);
400: System.err.println("The remaining "
401: + (MAX_THREADS - NUM_THREADS_STOPPED)
402: + " threads of scheduler:" + getName()
403: + "did not stop in " + STOP_TIME_OUT
404: + " seconds ");
405:
406: return false;
407: }
408: try {
409: Thread.sleep(1000);
410: count++;
411: } catch (Exception e) {
412: }
413: }
414: System.out.println(NUM_THREADS_STOPPED + "out of "
415: + MAX_THREADS + " active threads stopped in "
416: + " Scheduler:" + getName());
417:
418: return true;
419: }
420:
421: /*
422: * This method should be used if you want to cleanup the scheduler and
423: * release all resources from it. Remember the external code has to take
424: * care of the references it has to this object .This should be called
425: * when you do a stopThis on a scheduler and you have no intentions
426: * on using it (that is restarting it) again .
427: */
428:
429: public boolean cleanUp() {
430: //if (isAlive())
431: //{
432: // System.out.println(" *********** Returning from cleanUp isAlive is true "+this.getName());
433: // return false;
434: //}
435: synchronized (schedulers) {
436: times.removeAllElements();
437: runnables.removeAllElements();
438: ready_tasks.removeAllElements();
439: workers.removeAllElements();
440: schedulers.remove(getName());
441: return true;
442: }
443: }
444:
445: static int STOP_TIME_OUT = 15;
446:
447: /*
448: * The time in seconds that the calling thread should wait while invoking
449: * the stopALl or stopThis methods . That is when these two methods are
450: * invoked the method will block for a maximum of this time before
451: * printing a message that all the threads could not be stopped . Of course
452: * if all the releveant threads stop then the method will return immediately
453: */
454:
455: public void setStopTimeout(int timeout) {
456: STOP_TIME_OUT = timeout;
457: }
458:
459: /** something to let this thread rest when nothing to do **/
460: synchronized Runnable getTheWork() {
461: while (times.size() == 0)
462: try {
463: wait(10);
464: if ((STOP_ALL) || (STOP_THIS))
465: return null;
466: } catch (InterruptedException iex) {
467: }
468:
469: Date first = (Date) times.firstElement();
470: Date now = new Date();
471: if (first.after(now))
472: return null;
473: Runnable task = (Runnable) runnables.firstElement();
474: runnables.removeElement(task);
475: times.removeElement(first);
476: return task;
477: }
478:
479: /** The main thread which kicks off the task execution **/
480: public void run() {
481: synchronized (schedulers) {
482: STOP_ALL = false;
483: STOP_THIS = false;
484: }
485: startWorkers(); // first start the workers
486: if (MAX_THREADS == 0)
487: return;
488: while ((!STOP_ALL) && (!STOP_THIS))
489: try {
490: Runnable task = getTheWork();
491: if (task == null) {
492: try {
493: waitSchedule();
494: } catch (InterruptedException iex) {
495: }
496: } else {
497: startTask(task);
498: }
499: } catch (Exception ex) {
500: System.err
501: .println("Exception scheduling task in scheduler:"
502: + getName() + " " + ex);
503: // ex.printStackTrace();
504: }
505: return;
506: }
507:
508: synchronized void waitSchedule() throws InterruptedException {
509: wait(10);
510: }
511:
512: /** start the task **/
513: synchronized void startTask(Runnable task) {
514: ready_tasks.addElement(task);
515: for (int i = 0; i < workers.size(); i++) { // first start the workers
516: WorkerThread worker = (WorkerThread) workers.elementAt(i);
517: worker.wakeUp();
518: }
519: }
520:
521: /** get the next task ready to run **/
522: synchronized Runnable getNextTask() {
523: if (ready_tasks.size() == 0)
524: return null;
525: Runnable task = (Runnable) ready_tasks.firstElement();
526: ready_tasks.removeElement(task);
527: return task;
528: }
529:
530: /** start the workers**/
531: synchronized void startWorkers() {
532: if ((STOP_ALL) || (STOP_THIS))
533: return;
534: workers = new Vector();
535: for (int i = 0; i < MAX_THREADS; i++) {
536: TOTAL_THREADS += 1;
537: WorkerThread worker = new WorkerThread(this , getName()
538: + "-" + (i + 1));
539: workers.addElement(worker);
540: worker.start();
541: }
542: }
543:
544: public void deregisterThisScheduler(String nam)// Devesh...because of reload problem in JavaUI
545: {
546: if (nam == null)
547: return;
548: else {
549: Scheduler s = (Scheduler) schedulers.remove(nam);
550: s.stopAll();
551: }
552:
553: }
554:
555: }
|