001: // EventManager.java
002: // $Id: EventManager.java,v 1.4 1998/12/08 10:42:11 bmahe Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1996.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: /**
007: * A timer handling package.
008: * This package was written by J Payne.
009: */package org.w3c.tools.timers;
010:
011: import java.util.Vector;
012:
013: class Event {
014: /** Absolute time, in ms, to deliver this event. */
015: long time;
016:
017: /** Piece of data to pass to the event handler. */
018: Object data;
019:
020: /** handler for this event */
021: EventHandler handler;
022:
023: Event(long time, EventHandler handler, Object data) {
024: this .time = time;
025: this .handler = handler;
026: this .data = data;
027: }
028: }
029:
030: /** This implements an event manager for timer events. Timer events
031: are a way to have events occur some time in the future. They are an
032: alternative to using separate threads which issue sleep requests
033: themselves. */
034:
035: public class EventManager extends Thread implements EventHandler {
036: static final boolean debug = false;
037:
038: /** Vector of events, sorted by time. */
039: Vector queue = new Vector();
040:
041: public EventManager() {
042: setName("Event Manager");
043: }
044:
045: /** registerTimer inserts a new timer event into the queue. The
046: queue is always sorted by time, in increasing order. That is,
047: things farther into the future are further down in the queue.
048:
049: ms is milliseconds in the future, handler is the object that
050: will handle the event, and data is a "rock" that is passed to
051: the handler to do with what it will.
052:
053: This returns an opaque object which can be used to recall the
054: timer before it is delivered. */
055:
056: public Object registerTimer(long ms, EventHandler handler,
057: Object data) {
058: long time = ms + System.currentTimeMillis();
059: Event event = new Event(time, handler, data);
060:
061: return registerTimer(event);
062: }
063:
064: boolean done = false;
065:
066: public synchronized void stopEventManager() {
067: done = true;
068: notify();
069: }
070:
071: /** This is like the above registerTimer, except it takes an event
072: object with the deliver time filled in. If deliver time is
073: before the current time, the event is "immediately" delivered.
074: Do a binary search to figure out where the event goes. */
075:
076: public synchronized Object registerTimer(Event newEvent) {
077: int lo = 0;
078: int hi = queue.size();
079: long newTime = newEvent.time;
080: Event e;
081: long midTime;
082:
083: if (done) {
084: return null;
085: }
086:
087: if (hi == 0) {
088: queue.addElement(newEvent);
089: } else {
090: while (hi - lo > 0) {
091: int mid = (hi + lo) >> 1;
092: e = (Event) queue.elementAt(mid);
093: midTime = e.time;
094:
095: if (midTime < newTime) {
096: lo = mid + 1;
097: } else if (midTime > newTime) {
098: hi = mid;
099: } else {
100: lo = mid;
101: break;
102: }
103: }
104: if (lo < hi && ((Event) queue.elementAt(lo)).time > newTime) {
105: lo += 1;
106: }
107: queue.insertElementAt(newEvent, lo);
108: }
109: if (debug) {
110: checkQueue();
111: }
112: notify();
113:
114: return newEvent;
115: }
116:
117: /** This recalls a previously registered timer event. */
118: public synchronized Object recallTimer(Object timer) {
119: int lo = 0;
120: int hi = queue.size();
121: int limit = hi;
122: long destTime = ((Event) timer).time;
123: Event e;
124: long midTime;
125:
126: if (hi == 0) {
127: return null; /* already delivered or recalled */
128: }
129: while (hi - lo > 0) {
130: int mid = (hi + lo) >> 1;
131: e = (Event) queue.elementAt(mid);
132: midTime = e.time;
133:
134: if (midTime < destTime) {
135: lo = mid + 1;
136: } else if (midTime > destTime) {
137: hi = mid;
138: } else {
139: lo = mid;
140: for (int i = mid - 1; i >= 0; i--) {
141: e = (Event) queue.elementAt(i);
142: if (e.time == midTime) {
143: lo = i;
144: } else {
145: break;
146: }
147: }
148: break;
149: }
150: }
151: while (lo < limit) {
152: e = (Event) queue.elementAt(lo);
153: if (e.time == destTime) {
154: if (e == timer) {
155: queue.removeElementAt(lo);
156: break;
157: } else {
158: lo += 1;
159: }
160: } else {
161: return null;
162: }
163: }
164: if (debug) {
165: checkQueue();
166: }
167: if (lo == 0)
168: notify();
169: return timer;
170: }
171:
172: /** This is a separate method so that it can be
173: synchronized while the actual execution of the event
174: does not lock the EventManager. In other words, while
175: one event is being processed by its handler, others can
176: register or recall other events. */
177:
178: synchronized Event getNextEvent() {
179: while (true) {
180: while (queue.size() == 0) {
181: if (debug) {
182: System.out.println("Queue waiting for event.");
183: }
184: if (done) {
185: return null;
186: }
187: try {
188: wait();
189: } catch (InterruptedException e) {
190: }
191: }
192: Event e = (Event) queue.elementAt(0);
193: long now = System.currentTimeMillis();
194: long dt;
195:
196: dt = e.time - now;
197:
198: if (dt <= 0) {
199: queue.removeElementAt(0);
200: return e;
201: }
202: /* If we get here, we have no events scheduled for a while, so
203: we sleep until the next event needs delivering. When we
204: wake up, it could be because the queue has been changed.
205: So we have to check again. */
206: if (debug) {
207: System.out.println("Queue sleeping for " + dt + "ms");
208: }
209: try {
210: wait(dt);
211: } catch (InterruptedException ex) {
212: }
213: }
214: }
215:
216: public void run() {
217: Thread.currentThread().setPriority(Thread.MAX_PRIORITY - 1);
218: while (true) {
219: Event e = getNextEvent();
220:
221: if (done) {
222: break;
223: }
224:
225: try {
226: e.handler.handleTimerEvent(e.data, e.time);
227: } catch (Exception ex) {
228: System.out.println("Exception " + ex
229: + " in EventManager");
230: ex.printStackTrace();
231: } catch (Error er) {
232: System.out.println("Error " + er + " in EventManager");
233: er.printStackTrace();
234: }
235: }
236: }
237:
238: /* This is here for testing purposes only. */
239: public void handleTimerEvent(Object rock, long time) {
240: long dt = (System.currentTimeMillis() - time);
241:
242: System.out.println("Handling event with dt=" + dt);
243: }
244:
245: public static void main(String args[]) {
246: EventManager mgr = new EventManager();
247: int i;
248:
249: for (i = 0; i < 30; i++) {
250: mgr.registerTimer(1000 + (int) (1000 * Math.random()), mgr,
251: null);
252: }
253: mgr.checkQueue();
254: }
255:
256: synchronized void checkQueue() {
257: Vector q = queue;
258:
259: if (q.size() == 0)
260: return;
261: Event e = (Event) q.elementAt(0);
262: int i, size = q.size();
263: for (i = 1; i < size; i++) {
264: Event next = (Event) q.elementAt(i);
265:
266: if (next.time < e.time) {
267: System.out.println("Events out of order!\n");
268: System.out.println(q);
269: }
270: e = next;
271: }
272: }
273: }
|