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
00086 private static Batch batchThread;
00087 private static Clock clockThread;
00088
00089 private final static long PERIOD_MAX = 30000;
00090 private final static long PERIOD_MIN = 100;
00091 private long period;
00092 private long minremtime = PERIOD_MAX;
00093
00094
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
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
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
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
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
00235 try {
00236 t.process();
00237 } catch (Exception e) {
00238
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 }