001: /*
002: * Copyright (C) The MX4J Contributors.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the MX4J License version 1.0.
006: * See the terms of the MX4J License in the documentation provided with this software.
007: */
008:
009: package javax.management.timer;
010:
011: import java.util.ArrayList;
012: import java.util.Date;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.Map;
016: import java.util.Vector;
017: import javax.management.InstanceNotFoundException;
018: import javax.management.MBeanRegistration;
019: import javax.management.MBeanServer;
020: import javax.management.Notification;
021: import javax.management.NotificationBroadcasterSupport;
022: import javax.management.ObjectName;
023:
024: import mx4j.log.Log;
025: import mx4j.log.Logger;
026: import mx4j.timer.TimeQueue;
027: import mx4j.timer.TimerTask;
028:
029: /**
030: * @version $Revision: 1.19 $
031: */
032: public class Timer extends NotificationBroadcasterSupport implements
033: TimerMBean, MBeanRegistration {
034: public static final long ONE_SECOND = 1000;
035: public static final long ONE_MINUTE = 60 * ONE_SECOND;
036: public static final long ONE_HOUR = 60 * ONE_MINUTE;
037: public static final long ONE_DAY = 24 * ONE_HOUR;
038: public static final long ONE_WEEK = 7 * ONE_DAY;
039:
040: private TimeQueue queue = new TimeQueue();
041: private boolean isActive;
042: private int notificationID;
043: private HashMap tasks = new HashMap();
044: private boolean sendPastNotification;
045: private ObjectName objectName;
046:
047: private Logger getLogger() {
048: return Log.getLogger(getClass().getName());
049: }
050:
051: public ObjectName preRegister(MBeanServer server, ObjectName name)
052: throws Exception {
053: Logger logger = getLogger();
054: objectName = name;
055: if (logger.isEnabledFor(Logger.TRACE))
056: logger.trace("Timer service " + objectName
057: + " preRegistered successfully");
058: return name;
059: }
060:
061: public void postRegister(Boolean registrationDone) {
062: Logger logger = getLogger();
063: boolean done = registrationDone.booleanValue();
064: if (!done) {
065: logger.warn("Timer service " + objectName
066: + " was not registered");
067: } else {
068: if (logger.isEnabledFor(Logger.TRACE))
069: logger.trace("Timer service " + objectName
070: + " postRegistered successfully.");
071: }
072: }
073:
074: public void preDeregister() throws Exception {
075: Logger logger = getLogger();
076: stop();
077: if (logger.isEnabledFor(Logger.TRACE))
078: logger.trace("Timer service " + objectName
079: + " preDeregistered successfully");
080: }
081:
082: public void postDeregister() {
083: Logger logger = getLogger();
084: if (logger.isEnabledFor(Logger.TRACE))
085: logger.trace("Timer service " + objectName
086: + " postDeregistered successfully");
087: }
088:
089: public void start() {
090: if (!isActive()) {
091: Logger logger = getLogger();
092: if (logger.isEnabledFor(Logger.TRACE))
093: logger.trace("Starting Timer service " + objectName);
094:
095: queue.clear();
096: queue.start();
097:
098: ArrayList tasks = updateTasks();
099: scheduleTasks(tasks);
100:
101: isActive = true;
102:
103: if (logger.isEnabledFor(Logger.TRACE))
104: logger.trace("Timer service " + objectName
105: + " started successfully");
106: }
107: }
108:
109: public void stop() {
110: if (isActive()) {
111: Logger logger = getLogger();
112: if (logger.isEnabledFor(Logger.TRACE))
113: logger.trace("Stopping Timer service " + objectName);
114:
115: queue.stop();
116: queue.clear();
117:
118: isActive = false;
119:
120: if (logger.isEnabledFor(Logger.TRACE))
121: logger.trace("Timer service " + objectName
122: + " stopped successfully");
123: }
124: }
125:
126: public boolean isActive() {
127: return isActive;
128: }
129:
130: public Integer addNotification(String type, String message,
131: Object userData, Date date) throws IllegalArgumentException {
132: return addNotification(type, message, userData, date, 0, 0,
133: false);
134: }
135:
136: public Integer addNotification(String type, String message,
137: Object userData, Date date, long period)
138: throws IllegalArgumentException {
139: return addNotification(type, message, userData, date, period,
140: 0, false);
141: }
142:
143: public Integer addNotification(String type, String message,
144: Object userData, Date date, long period, long occurrences)
145: throws IllegalArgumentException {
146: return addNotification(type, message, userData, date, period,
147: occurrences, false);
148: }
149:
150: public Integer addNotification(String type, String message,
151: Object userData, Date date, long period, long occurrences,
152: boolean fixedRate) throws IllegalArgumentException {
153: if (date == null)
154: throw new IllegalArgumentException(
155: "Notification date cannot be null");
156: if (period < 0)
157: throw new IllegalArgumentException(
158: "Period cannot be negative");
159: if (occurrences < 0)
160: throw new IllegalArgumentException(
161: "Occurrences cannot be negative");
162:
163: long now = System.currentTimeMillis();
164:
165: if (isActive()) {
166: // Check for the validity of the notification times, as the Timer is active
167:
168: // Notification in the past, assume it's now
169: if (date.getTime() < now)
170: date = new Date(now);
171:
172: // Periodic limited, the last notification is in the past
173: if (period > 0 && occurrences > 0) {
174: long lastTime = date.getTime() + (occurrences - 1)
175: * period;
176: if (lastTime < now)
177: throw new IllegalArgumentException(
178: "Last date for periodic notification is before current date");
179: }
180: }
181:
182: // Anyway, register the notification, no matter if the Timer is active
183: Integer id = addNotificationImpl(type, message, userData, date,
184: period, occurrences, fixedRate);
185:
186: // If the Timer is active, schedule the notification
187: if (isActive()) {
188: TimerTask task = getTask(id);
189: updateTask(task, now);
190: if (!task.isFinished()) {
191: queue.schedule(task);
192: }
193: }
194: return id;
195: }
196:
197: private Integer addNotificationImpl(String type, String message,
198: Object userData, Date date, long period, long occurrences,
199: boolean fixedRate) {
200: Logger logger = getLogger();
201:
202: Integer id = createNotificationID();
203:
204: TimerNotification notification = new TimerNotification(type,
205: this , 0, System.currentTimeMillis(), message, id);
206: notification.setUserData(userData);
207: if (logger.isEnabledFor(Logger.DEBUG))
208: logger.debug("Adding timer notification: " + notification
209: + " on Timer service " + objectName);
210:
211: TimerTask task = createTimerTask(notification, date, period,
212: occurrences, fixedRate);
213:
214: synchronized (this ) {
215: tasks.put(id, task);
216: }
217:
218: return id;
219: }
220:
221: private TimerTask createTimerTask(TimerNotification notification,
222: Date date, long period, long occurrences, boolean fixedRate) {
223: return new TimerTask(notification, date, period, occurrences,
224: fixedRate) {
225: public void run() {
226: // Send the notification
227: TimerNotification notification = getNotification();
228: TimerNotification toSend;
229: synchronized (notification) {
230: toSend = new TimerNotification(notification
231: .getType(), notification.getSource(),
232: notification.getSequenceNumber(),
233: notification.getTimeStamp(), notification
234: .getMessage(), notification
235: .getNotificationID());
236: toSend.setUserData(notification.getUserData());
237: notification.setSequenceNumber(notification
238: .getSequenceNumber() + 1);
239: }
240: sendNotification(toSend);
241: }
242: };
243: }
244:
245: private ArrayList updateTasks() {
246: ArrayList list = new ArrayList();
247: boolean sendPast = getSendPastNotifications();
248: long now = System.currentTimeMillis();
249: synchronized (this ) {
250: for (Iterator i = tasks.entrySet().iterator(); i.hasNext();) {
251: Map.Entry entry = getNextNonFinishedTaskEntry(i);
252: if (entry == null)
253: break;
254:
255: TimerTask task = (TimerTask) entry.getValue();
256:
257: if (!sendPast) {
258: updateTask(task, now);
259: if (task.isFinished())
260: continue;
261: }
262: list.add(task);
263: }
264: return list;
265: }
266: }
267:
268: private void updateTask(TimerTask task, long now) {
269: long time = task.getNextExecutionTime();
270:
271: while (time < now && !task.isFinished()) {
272: if (task.isPeriodic()) {
273: task.setNextExecutionTime(time + task.getPeriod());
274: time = task.getNextExecutionTime();
275: } else {
276: task.setFinished(true);
277: }
278: }
279: }
280:
281: private void scheduleTasks(ArrayList tasks) {
282: synchronized (this ) {
283: for (int i = 0; i < tasks.size(); ++i) {
284: TimerTask task = (TimerTask) tasks.get(i);
285: queue.schedule(task);
286: }
287: }
288: }
289:
290: public void removeNotification(Integer id)
291: throws InstanceNotFoundException {
292: Logger logger = getLogger();
293:
294: synchronized (this ) {
295: TimerTask t = getTask(id);
296: if (t == null)
297: throw new InstanceNotFoundException(
298: "Cannot find notification to remove with id: "
299: + id);
300: queue.unschedule(t);
301: tasks.remove(id);
302: if (logger.isEnabledFor(Logger.DEBUG))
303: logger.debug("Notification " + t.getNotification()
304: + " removed successfully from Timer service "
305: + objectName);
306: }
307: }
308:
309: public void removeNotifications(String type)
310: throws InstanceNotFoundException {
311: Logger logger = getLogger();
312:
313: boolean found = false;
314: synchronized (this ) {
315: for (Iterator i = tasks.entrySet().iterator(); i.hasNext();) {
316: Map.Entry entry = getNextNonFinishedTaskEntry(i);
317: if (entry == null)
318: break;
319:
320: TimerTask t = (TimerTask) entry.getValue();
321: TimerNotification n = t.getNotification();
322: if (n.getType().equals(type)) {
323: queue.unschedule(t);
324: i.remove();
325: if (logger.isEnabledFor(Logger.DEBUG))
326: logger
327: .debug("Notification "
328: + n
329: + " removed successfully from Timer service "
330: + objectName);
331: found = true;
332: }
333: }
334: }
335:
336: if (!found)
337: throw new InstanceNotFoundException(
338: "Cannot find timer notification to remove with type: "
339: + type + " from Timer service "
340: + objectName);
341: }
342:
343: public void removeAllNotifications() {
344: synchronized (this ) {
345: queue.clear();
346: tasks.clear();
347: notificationID = 0;
348: }
349: }
350:
351: public Vector getAllNotificationIDs() {
352: Vector vector = new Vector();
353: synchronized (this ) {
354: for (Iterator i = tasks.entrySet().iterator(); i.hasNext();) {
355: Map.Entry entry = getNextNonFinishedTaskEntry(i);
356: if (entry == null)
357: break;
358: vector.add(entry.getKey());
359: }
360: }
361: return vector;
362: }
363:
364: public Vector getNotificationIDs(String type) {
365: Vector vector = new Vector();
366: synchronized (this ) {
367: for (Iterator i = tasks.entrySet().iterator(); i.hasNext();) {
368: Map.Entry entry = getNextNonFinishedTaskEntry(i);
369: if (entry == null)
370: break;
371: TimerTask t = (TimerTask) entry.getValue();
372: TimerNotification n = t.getNotification();
373: if (n.getType().equals(type)) {
374: vector.add(entry.getKey());
375: }
376: }
377: }
378: return vector;
379: }
380:
381: public boolean getSendPastNotifications() {
382: return sendPastNotification;
383: }
384:
385: public void setSendPastNotifications(boolean value) {
386: sendPastNotification = value;
387: }
388:
389: public int getNbNotifications() {
390: int count = 0;
391: synchronized (this ) {
392: for (Iterator i = tasks.entrySet().iterator(); i.hasNext();) {
393: Map.Entry entry = getNextNonFinishedTaskEntry(i);
394: if (entry == null)
395: break;
396: ++count;
397: }
398: return count;
399: }
400: }
401:
402: public boolean isEmpty() {
403: synchronized (this ) {
404: return getNbNotifications() == 0;
405: }
406: }
407:
408: public String getNotificationType(Integer id) {
409: synchronized (this ) {
410: TimerTask t = getTask(id);
411: return t == null ? null : t.getNotification().getType();
412: }
413: }
414:
415: public String getNotificationMessage(Integer id) {
416: synchronized (this ) {
417: TimerTask t = getTask(id);
418: return t == null ? null : t.getNotification().getMessage();
419: }
420: }
421:
422: public Object getNotificationUserData(Integer id) {
423: synchronized (this ) {
424: TimerTask t = getTask(id);
425: return t == null ? null : t.getNotification().getUserData();
426: }
427: }
428:
429: public Date getDate(Integer id) {
430: synchronized (this ) {
431: TimerTask t = getTask(id);
432: return t == null ? null : new Date(t.getDate());
433: }
434: }
435:
436: public Long getPeriod(Integer id) {
437: synchronized (this ) {
438: TimerTask t = getTask(id);
439: return t == null ? null : new Long(t.getPeriod());
440: }
441: }
442:
443: public Long getNbOccurences(Integer id) {
444: synchronized (this ) {
445: TimerTask t = getTask(id);
446: return t == null ? null : new Long(t.getOccurrences());
447: }
448: }
449:
450: private Integer createNotificationID() {
451: synchronized (this ) {
452: return new Integer(++notificationID);
453: }
454: }
455:
456: private TimerTask getTask(Integer id) {
457: Logger logger = getLogger();
458:
459: synchronized (this ) {
460: TimerTask t = (TimerTask) tasks.get(id);
461:
462: if (logger.isEnabledFor(Logger.DEBUG))
463: logger
464: .debug("Retrieving task with id " + id + ": "
465: + t);
466:
467: if (t != null && t.isFinished()) {
468: if (logger.isEnabledFor(Logger.DEBUG))
469: logger.debug("Task with id " + id
470: + " is expired, removing it");
471:
472: tasks.remove(id);
473: t = null;
474: }
475: return t;
476: }
477: }
478:
479: private Map.Entry getNextNonFinishedTaskEntry(Iterator i) {
480: Logger logger = getLogger();
481:
482: synchronized (this ) {
483: if (i.hasNext()) {
484: Map.Entry entry = (Map.Entry) i.next();
485: TimerTask t = (TimerTask) entry.getValue();
486: if (t.isFinished()) {
487: if (logger.isEnabledFor(Logger.DEBUG))
488: logger
489: .debug("Found an expired notification, removing it: "
490: + t);
491: i.remove();
492: return getNextNonFinishedTaskEntry(i);
493: }
494: return entry;
495: }
496: return null;
497: }
498: }
499:
500: public void sendNotification(Notification n) {
501: Logger logger = getLogger();
502: if (logger.isEnabledFor(Logger.TRACE))
503: logger
504: .trace("Start sending notifications from Timer service "
505: + objectName);
506: super .sendNotification(n);
507: if (logger.isEnabledFor(Logger.TRACE))
508: logger
509: .trace("Finished sending notifications from Timer service "
510: + objectName);
511: }
512:
513: public Boolean getFixedRate(Integer id) {
514: return new Boolean(getTask(id).getFixedRate());
515: }
516: }
|