001: /*
002: * @(#) TimerManager.java
003: *
004: * JOTM: Java Open Transaction Manager
005: *
006: *
007: * This module was originally developed by
008: *
009: * - Bull S.A. as part of the JOnAS application server code released in
010: * July 1999 (www.bull.com)
011: *
012: * --------------------------------------------------------------------------
013: * The original code and portions created by Bull SA are
014: * Copyright (c) 1999 BULL SA
015: * All rights reserved.
016: *
017: * Redistribution and use in source and binary forms, with or without
018: * modification, are permitted provided that the following conditions are met:
019: *
020: * -Redistributions of source code must retain the above copyright notice, this
021: * list of conditions and the following disclaimer.
022: *
023: * -Redistributions in binary form must reproduce the above copyright notice,
024: * this list of conditions and the following disclaimer in the documentation
025: * and/or other materials provided with the distribution.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
028: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
029: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
030: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
031: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
032: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
033: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
034: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
035: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
036: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
037: * POSSIBILITY OF SUCH DAMAGE.
038: *
039: * --------------------------------------------------------------------------
040: * $Id: TimerManager.java,v 1.4 2005/03/15 00:06:05 tonyortiz Exp $
041: * --------------------------------------------------------------------------
042: */
043: package org.objectweb.jotm;
044:
045: import java.util.Vector;
046:
047: /**
048: * Clock thread for a TimerManager
049: * Every second, decrement timers and launch action if expired
050: */
051: class Clock extends Thread {
052:
053: private TimerManager tmgr;
054:
055: public Clock(TimerManager tmgr) {
056: super ("JotmClock");
057: if (TraceTm.jta.isDebugEnabled()) {
058: TraceTm.jta.debug("Clock constructor");
059: }
060:
061: this .tmgr = tmgr;
062: }
063:
064: public void run() {
065: tmgr.clock();
066: }
067: }
068:
069: /**
070: * Batch thread for a TimerManager
071: * pocess all expired timers
072: */
073: class Batch extends Thread {
074:
075: private TimerManager tmgr;
076:
077: public Batch(TimerManager tmgr) {
078: super ("JotmBatch");
079: if (TraceTm.jta.isDebugEnabled()) {
080: TraceTm.jta.debug("Batch constructor");
081: }
082:
083: this .tmgr = tmgr;
084: }
085:
086: public void run() {
087: tmgr.batch();
088: }
089: }
090:
091: /**
092: * A timer manager manages 2 lists of timers with 2 threads
093: * One thread is a clock which decrements timers every second
094: * and passes them when expired in a list of expired timers.
095: * The other thread looks in the list of expired timers to process
096: * them.
097: */
098: public class TimerManager {
099:
100: // threads managing the service.
101: private static Batch batchThread;
102: private static Clock clockThread;
103:
104: // lists
105: private Vector timerList = new Vector();
106: private Vector expiredList = new Vector();
107:
108: private static TimerManager unique = null;
109: private static boolean shuttingdown = false;
110:
111: /**
112: * Constructor
113: */
114: private TimerManager() {
115: // launch threads for timers
116: batchThread = new Batch(this );
117: batchThread.setDaemon(true);
118: batchThread.start();
119: clockThread = new Clock(this );
120: clockThread.setDaemon(true);
121: clockThread.start();
122: }
123:
124: /**
125: * Get an instance of the TimerManager
126: */
127: public static TimerManager getInstance() {
128: if (unique == null)
129: unique = new TimerManager();
130: return unique;
131: }
132:
133: /**
134: * stop the service
135: * @param force tell the manager NOT to wait for the timers to be completed
136: */
137: public static void stop(boolean force) {
138: if (TraceTm.jta.isDebugEnabled()) {
139: TraceTm.jta.debug("Stop TimerManager");
140: }
141:
142: TimerManager tmgr = getInstance();
143: shuttingdown = true;
144: while (clockThread.isAlive() || batchThread.isAlive()) {
145: try {
146: Thread.sleep(100);
147: } catch (InterruptedException e) {
148: break;
149: }
150: }
151: if (TraceTm.jta.isDebugEnabled()) {
152: TraceTm.jta.debug("TimerManager has stopped");
153: }
154: }
155:
156: public static void stop() {
157: stop(true);
158: }
159:
160: /**
161: * cney speed up the clock x1000 when shutting down
162: * update all timers in the list
163: * each timer expired is put in a special list of expired timers
164: * they will be processed then by the Batch Thread.
165: */
166: public void clock() {
167: while (true) {
168: try {
169: Thread.sleep(shuttingdown ? 1 : 1000); // 1 second or 1ms shen shuttingdown
170: // Thread.currentThread().sleep(shuttingdown?1:1000); // 1 second or 1ms shen shuttingdown
171: synchronized (timerList) {
172: int found = 0;
173: boolean empty = true;
174: for (int i = 0; i < timerList.size(); i++) {
175: TimerEvent t = (TimerEvent) timerList
176: .elementAt(i);
177: if (!t.isStopped()) {
178: empty = false;
179: }
180: if (t.update() <= 0) {
181: timerList.removeElementAt(i--);
182: if (t.valid()) {
183: expiredList.addElement(t);
184: found++;
185: if (t.ispermanent() && !shuttingdown) {
186: t.restart();
187: timerList.addElement(t);
188: }
189: }
190: }
191: // Be sure there is no more ref on bean in this local variable.
192: t = null;
193: }
194: if (found > 0) {
195: timerList.notify();
196: } else {
197: if (empty && shuttingdown) {
198: break;
199: }
200: }
201: }
202: } catch (InterruptedException e) {
203: TraceTm.jta.error("Timer interrupted");
204: }
205: }
206: synchronized (timerList) { // notify batch so that function can return.
207: timerList.notify();
208: }
209: }
210:
211: /**
212: * process all expired timers
213: */
214: public void batch() {
215:
216: while (!(shuttingdown && timerList.isEmpty() && expiredList
217: .isEmpty())) {
218: TimerEvent t;
219: synchronized (timerList) {
220: while (expiredList.isEmpty()) {
221: if (shuttingdown)
222: return;
223: try {
224: timerList.wait();
225: } catch (Exception e) {
226: TraceTm.jta.error("Exception in Batch: ", e);
227: }
228: }
229: t = (TimerEvent) expiredList.elementAt(0);
230: expiredList.removeElementAt(0);
231: }
232: // Do not keep the lock during the processing of the timer
233: t.process();
234: }
235: }
236:
237: /**
238: * add a new timer in the list
239: * @param tel Object that will be notified when the timer expire.
240: * @param timeout nb of seconds before the timer expires.
241: * @param arg info passed with the timer
242: * @param permanent true if the timer is permanent.
243: */
244: public TimerEvent addTimer(TimerEventListener tel, long timeout,
245: Object arg, boolean permanent) {
246: TimerEvent te = new TimerEvent(tel, timeout, arg, permanent);
247: synchronized (timerList) {
248: timerList.addElement(te);
249: }
250: return te;
251: }
252:
253: /**
254: * remove a timer from the list. this is not very efficient.
255: * A better way to do this is TimerEvent.unset()
256: * @deprecated
257: */
258: public void removeTimer(TimerEvent te) {
259: synchronized (timerList) {
260: timerList.removeElement(te);
261: }
262: }
263: }
|