TimerManager.java

00001 
00030 package org.objectweb.jonas_timer;
00031 
00032 import java.util.ArrayList;
00033 import java.util.Collection;
00034 import java.util.Iterator;
00035 
00036 import org.objectweb.util.monolog.api.BasicLevel;
00037 
00042 class Clock extends Thread {
00043 
00044     private TimerManager tmgr;
00045 
00046     public Clock(TimerManager tmgr) {
00047         super("JonasClock");
00048         TraceTimer.logger.log(BasicLevel.DEBUG, "Clock constructor");
00049         this.tmgr = tmgr;
00050     }
00051 
00052     public void run() {
00053         tmgr.clock();
00054     }
00055 }
00056 
00061 class Batch extends Thread {
00062 
00063     private TimerManager tmgr;
00064 
00065     public Batch(TimerManager tmgr) {
00066         super("JonasBatch");
00067         TraceTimer.logger.log(BasicLevel.DEBUG, "Batch constructor");
00068         this.tmgr = tmgr;
00069     }
00070 
00071     public void run() {
00072         tmgr.batch();
00073     }
00074 }
00075 
00083 public class TimerManager {
00084 
00085     // threads managing the service.
00086     private static Batch batchThread;
00087     private static Clock clockThread;
00088 
00089     private final static long PERIOD_MAX = 30000; // 30 sec
00090     private final static long PERIOD_MIN = 100; // 1/10 sec
00091     private long period;
00092     private long minremtime = PERIOD_MAX;
00093 
00094     // lists
00095     private ArrayList timerList = new ArrayList();
00096     private ArrayList expiredList = new ArrayList();
00097 
00098     private static TimerManager unique = null;
00099     private static boolean shuttingdown = false;
00100 
00104     private TimerManager() {
00105         // launch threads for timers
00106         batchThread = new Batch(this);
00107         batchThread.start();
00108         clockThread = new Clock(this);
00109         clockThread.start();
00110     }
00111 
00115     public static TimerManager getInstance() {
00116         if (unique == null)
00117             unique = new TimerManager();
00118         return unique;
00119     }
00120 
00125     public static void stop(boolean force) {
00126         TraceTimer.logger.log(BasicLevel.DEBUG,"Stop TimerManager");
00127         TimerManager tmgr = getInstance();
00128         shuttingdown = true;
00129         while (clockThread.isAlive() || batchThread.isAlive()) {
00130             try {
00131                 Thread.sleep(100);
00132             } catch (InterruptedException e) {
00133                 break;
00134             }
00135         }
00136         TraceTimer.logger.log(BasicLevel.DEBUG,"TimerManager has stopped");
00137     }
00138 
00139     public static void stop() {
00140         stop(true);
00141     }
00142 
00143 
00149     public void clock() {
00150         synchronized(timerList) {
00151             while (true) {
00152                 // compute time to sleep
00153                 if (shuttingdown) {
00154                     period = 1;
00155                 } else {
00156                     period = PERIOD_MAX;
00157                     if (minremtime < period) {
00158                         period = minremtime < PERIOD_MIN ? PERIOD_MIN : minremtime;
00159                     }
00160                 }
00161                 // must sleep a little less than period
00162                 try {
00163                     timerList.wait(period);
00164                 } catch (InterruptedException e) {
00165                     TraceTimer.logger.log(BasicLevel.ERROR, "Timer interrupted");
00166                 }
00167                 int found = 0;
00168                 boolean empty = true;
00169                 minremtime = PERIOD_MAX;
00170                 for (Iterator i = timerList.iterator(); i.hasNext(); ) {
00171                     TimerEvent t = (TimerEvent) i.next();
00172                     if (!t.isStopped()) {
00173                         empty = false;
00174                     }
00175                     long remtime = t.update();
00176                     if (remtime <= 0) {
00177                         if (t.valid()) {
00178                             expiredList.add(t);
00179                             found++;
00180                             if (t.ispermanent() && !shuttingdown) {
00181                                 remtime = t.restart();
00182                                 if (remtime < minremtime) {
00183                                     minremtime = remtime;
00184                                 }
00185                             } else {
00186                                 i.remove();
00187                             }
00188                         } else {
00189                             i.remove();
00190                         }
00191                     } else {
00192                         if (remtime < minremtime) {
00193                             minremtime = remtime;
00194                         }
00195                     }
00196                     // Be sure there is no more ref on bean in this local variable.
00197                     t = null;
00198                 }
00199                 if (found > 0) {
00200                     timerList.notifyAll();
00201                 } else {
00202                     if (empty) {
00203                         if (shuttingdown) {
00204                             break;
00205                         }
00206                     }
00207                 }
00208             }
00209             timerList.notifyAll();
00210         }
00211     }
00212 
00216     public void batch() {
00217 
00218         while (!(shuttingdown && timerList.isEmpty() && expiredList.isEmpty())) {
00219             TimerEvent t;
00220             synchronized(timerList) {
00221                 while (expiredList.isEmpty()) {
00222                     if (shuttingdown) {
00223                         TraceTimer.logger.log(BasicLevel.WARN, "TimerManager shutting down");
00224                         return;
00225                     }
00226                     try {
00227                         timerList.wait();
00228                     } catch (Exception e) {
00229                         TraceTimer.logger.log(BasicLevel.ERROR, "Exception in Batch: ",e);
00230                     }
00231                 }
00232                 t = (TimerEvent) expiredList.remove(0);
00233             }
00234             // Do not keep the lock during the processing of the timer
00235             try {
00236                 t.process();
00237             } catch (Exception e) {
00238                 // An exception in a timer process should not stop this thread.
00239                 TraceTimer.logger.log(BasicLevel.WARN, "Ignoring exception: " + e);
00240                 e.printStackTrace();
00241             }
00242         }
00243         TraceTimer.logger.log(BasicLevel.WARN, "TimerManager stopped");
00244     }
00245 
00254     public TimerEvent addTimer(TimerEventListener tel, long timeout, Object arg, boolean permanent) {
00255         return addTimerMs(tel, timeout * 1000, arg, permanent);
00256     }
00257 
00265     public TimerEvent addTimerMs(TimerEventListener tel, long timeout, Object arg, boolean permanent) {
00266         TimerEvent te = new TimerEvent(tel, timeout, arg, permanent);
00267         synchronized(timerList) {
00268             timerList.add(te);
00269             if (timeout < minremtime) {
00270                 minremtime = timeout;
00271             }
00272             timerList.notifyAll();
00273         }
00274         return te;
00275     }
00276 
00282     public void removeTimer(TimerEvent te) {
00283         synchronized(timerList) {
00284             timerList.remove(timerList.indexOf(te));
00285         }
00286     }
00287 }

Generated on Tue Feb 15 15:05:57 2005 for JOnAS by  doxygen 1.3.9.1