0001 /*
0002 * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.management.timer;
0027
0028 import static com.sun.jmx.defaults.JmxProperties.TIMER_LOGGER;
0029 import java.util.Date;
0030 import java.util.Hashtable;
0031 import java.util.Iterator;
0032 import java.util.Map;
0033 import java.util.Set;
0034 import java.util.TreeSet;
0035 import java.util.Vector;
0036 import java.util.logging.Level;
0037
0038 // jmx imports
0039 //
0040 import javax.management.InstanceNotFoundException;
0041 import javax.management.MBeanNotificationInfo;
0042 import javax.management.MBeanRegistration;
0043 import javax.management.MBeanServer;
0044 import javax.management.NotificationBroadcasterSupport;
0045 import javax.management.ObjectName;
0046
0047 /**
0048 *
0049 * Provides the implementation of the timer MBean.
0050 * The timer MBean sends out an alarm at a specified time
0051 * that wakes up all the listeners registered to receive timer notifications.
0052 * <P>
0053 *
0054 * This class manages a list of dated timer notifications.
0055 * A method allows users to add/remove as many notifications as required.
0056 * When a timer notification is emitted by the timer and becomes obsolete,
0057 * it is automatically removed from the list of timer notifications.
0058 * <BR>Additional timer notifications can be added into regularly repeating notifications.
0059 * <P>
0060 *
0061 * Note:
0062 * <OL>
0063 * <LI>When sending timer notifications, the timer updates the notification sequence number
0064 * irrespective of the notification type.
0065 * <LI>The timer service relies on the system date of the host where the <CODE>Timer</CODE> class is loaded.
0066 * Listeners may receive untimely notifications
0067 * if their host has a different system date.
0068 * To avoid such problems, synchronize the system date of all host machines where timing is needed.
0069 * <LI>The default behavior for periodic notifications is <i>fixed-delay execution</i>, as
0070 * specified in {@link java.util.Timer}. In order to use <i>fixed-rate execution</i>, use the
0071 * overloaded {@link #addNotification(String, String, Object, Date, long, long, boolean)} method.
0072 * <LI>Notification listeners are potentially all executed in the same
0073 * thread. Therefore, they should execute rapidly to avoid holding up
0074 * other listeners or perturbing the regularity of fixed-delay
0075 * executions. See {@link NotificationBroadcasterSupport}.
0076 * </OL>
0077 *
0078 * @since 1.5
0079 */
0080 public class Timer extends NotificationBroadcasterSupport implements
0081 TimerMBean, MBeanRegistration {
0082
0083 /*
0084 * ------------------------------------------
0085 * PUBLIC VARIABLES
0086 * ------------------------------------------
0087 */
0088
0089 /**
0090 * Number of milliseconds in one second.
0091 * Useful constant for the <CODE>addNotification</CODE> method.
0092 */
0093 public static final long ONE_SECOND = 1000;
0094
0095 /**
0096 * Number of milliseconds in one minute.
0097 * Useful constant for the <CODE>addNotification</CODE> method.
0098 */
0099 public static final long ONE_MINUTE = 60 * ONE_SECOND;
0100
0101 /**
0102 * Number of milliseconds in one hour.
0103 * Useful constant for the <CODE>addNotification</CODE> method.
0104 */
0105 public static final long ONE_HOUR = 60 * ONE_MINUTE;
0106
0107 /**
0108 * Number of milliseconds in one day.
0109 * Useful constant for the <CODE>addNotification</CODE> method.
0110 */
0111 public static final long ONE_DAY = 24 * ONE_HOUR;
0112
0113 /**
0114 * Number of milliseconds in one week.
0115 * Useful constant for the <CODE>addNotification</CODE> method.
0116 */
0117 public static final long ONE_WEEK = 7 * ONE_DAY;
0118
0119 /*
0120 * ------------------------------------------
0121 * PRIVATE VARIABLES
0122 * ------------------------------------------
0123 */
0124
0125 /**
0126 * Table containing all the timer notifications of this timer,
0127 * with the associated date, period and number of occurrences.
0128 */
0129 private Map<Integer, Object[]> timerTable = new Hashtable<Integer, Object[]>();
0130
0131 /**
0132 * Past notifications sending on/off flag value.
0133 * This attribute is used to specify if the timer has to send past notifications after start.
0134 * <BR>The default value is set to <CODE>false</CODE>.
0135 */
0136 private boolean sendPastNotifications = false;
0137
0138 /**
0139 * Timer state.
0140 * The default value is set to <CODE>false</CODE>.
0141 */
0142 private transient boolean isActive = false;
0143
0144 /**
0145 * Timer sequence number.
0146 * The default value is set to 0.
0147 */
0148 private transient long sequenceNumber = 0;
0149
0150 // Flags needed to keep the indexes of the objects in the array.
0151 //
0152 private static final int TIMER_NOTIF_INDEX = 0;
0153 private static final int TIMER_DATE_INDEX = 1;
0154 private static final int TIMER_PERIOD_INDEX = 2;
0155 private static final int TIMER_NB_OCCUR_INDEX = 3;
0156 private static final int ALARM_CLOCK_INDEX = 4;
0157 private static final int FIXED_RATE_INDEX = 5;
0158
0159 /**
0160 * The notification counter ID.
0161 * Used to keep the max key value inserted into the timer table.
0162 */
0163 private int counterID = 0;
0164
0165 private java.util.Timer timer;
0166
0167 /*
0168 * ------------------------------------------
0169 * CONSTRUCTORS
0170 * ------------------------------------------
0171 */
0172
0173 /**
0174 * Default constructor.
0175 */
0176 public Timer() {
0177 }
0178
0179 /*
0180 * ------------------------------------------
0181 * PUBLIC METHODS
0182 * ------------------------------------------
0183 */
0184
0185 /**
0186 * Allows the timer MBean to perform any operations it needs before being registered
0187 * in the MBean server.
0188 * <P>
0189 * Not used in this context.
0190 *
0191 * @param server The MBean server in which the timer MBean will be registered.
0192 * @param name The object name of the timer MBean.
0193 *
0194 * @return The name of the timer MBean registered.
0195 *
0196 * @exception java.lang.Exception
0197 */
0198 public ObjectName preRegister(MBeanServer server, ObjectName name)
0199 throws java.lang.Exception {
0200 return name;
0201 }
0202
0203 /**
0204 * Allows the timer MBean to perform any operations needed after having been
0205 * registered in the MBean server or after the registration has failed.
0206 * <P>
0207 * Not used in this context.
0208 */
0209 public void postRegister(Boolean registrationDone) {
0210 }
0211
0212 /**
0213 * Allows the timer MBean to perform any operations it needs before being unregistered
0214 * by the MBean server.
0215 * <P>
0216 * Stops the timer.
0217 *
0218 * @exception java.lang.Exception
0219 */
0220 public void preDeregister() throws java.lang.Exception {
0221
0222 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0223 "preDeregister", "stop the timer");
0224
0225 // Stop the timer.
0226 //
0227 stop();
0228 }
0229
0230 /**
0231 * Allows the timer MBean to perform any operations needed after having been
0232 * unregistered by the MBean server.
0233 * <P>
0234 * Not used in this context.
0235 */
0236 public void postDeregister() {
0237 }
0238
0239 /*
0240 * This overrides the method in NotificationBroadcasterSupport.
0241 * Return the MBeanNotificationInfo[] array for this MBean.
0242 * The returned array has one element to indicate that the MBean
0243 * can emit TimerNotification. The array of type strings
0244 * associated with this entry is a snapshot of the current types
0245 * that were given to addNotification.
0246 */
0247 public synchronized MBeanNotificationInfo[] getNotificationInfo() {
0248 Set<String> notifTypes = new TreeSet<String>();
0249 for (Iterator it = timerTable.values().iterator(); it.hasNext();) {
0250 Object[] entry = (Object[]) it.next();
0251 TimerNotification notif = (TimerNotification) entry[TIMER_NOTIF_INDEX];
0252 notifTypes.add(notif.getType());
0253 }
0254 String[] notifTypesArray = notifTypes.toArray(new String[0]);
0255 return new MBeanNotificationInfo[] { new MBeanNotificationInfo(
0256 notifTypesArray, TimerNotification.class.getName(),
0257 "Notification sent by Timer MBean") };
0258 }
0259
0260 /**
0261 * Starts the timer.
0262 * <P>
0263 * If there is one or more timer notifications before the time in the list of notifications, the notification
0264 * is sent according to the <CODE>sendPastNotifications</CODE> flag and then, updated
0265 * according to its period and remaining number of occurrences.
0266 * If the timer notification date remains earlier than the current date, this notification is just removed
0267 * from the list of notifications.
0268 */
0269 public synchronized void start() {
0270
0271 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(), "start",
0272 "starting the timer");
0273
0274 // Start the TimerAlarmClock.
0275 //
0276 if (isActive == false) {
0277
0278 timer = new java.util.Timer();
0279
0280 TimerAlarmClock alarmClock;
0281 Date date;
0282
0283 Date currentDate = new Date();
0284
0285 // Send or not past notifications depending on the flag.
0286 // Update the date and the number of occurrences of past notifications
0287 // to make them later than the current date.
0288 //
0289 sendPastNotifications(currentDate, sendPastNotifications);
0290
0291 // Update and start all the TimerAlarmClocks.
0292 // Here, all the notifications in the timer table are later than the current date.
0293 //
0294 for (Object[] obj : timerTable.values()) {
0295
0296 // Retrieve the date notification and the TimerAlarmClock.
0297 //
0298 date = (Date) obj[TIMER_DATE_INDEX];
0299
0300 // Update all the TimerAlarmClock timeouts and start them.
0301 //
0302 boolean fixedRate = ((Boolean) obj[FIXED_RATE_INDEX])
0303 .booleanValue();
0304 if (fixedRate) {
0305 alarmClock = new TimerAlarmClock(this , date);
0306 obj[ALARM_CLOCK_INDEX] = (Object) alarmClock;
0307 timer.schedule(alarmClock, alarmClock.next);
0308 } else {
0309 alarmClock = new TimerAlarmClock(this , (date
0310 .getTime() - currentDate.getTime()));
0311 obj[ALARM_CLOCK_INDEX] = (Object) alarmClock;
0312 timer.schedule(alarmClock, alarmClock.timeout);
0313 }
0314 }
0315
0316 // Set the state to ON.
0317 //
0318 isActive = true;
0319
0320 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0321 "start", "timer started");
0322 } else {
0323 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0324 "start", "the timer is already activated");
0325 }
0326 }
0327
0328 /**
0329 * Stops the timer.
0330 */
0331 public synchronized void stop() {
0332
0333 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(), "stop",
0334 "stopping the timer");
0335
0336 // Stop the TimerAlarmClock.
0337 //
0338 if (isActive == true) {
0339
0340 TimerAlarmClock alarmClock;
0341
0342 for (Object[] obj : timerTable.values()) {
0343
0344 // Stop all the TimerAlarmClock.
0345 //
0346 alarmClock = (TimerAlarmClock) obj[ALARM_CLOCK_INDEX];
0347 if (alarmClock != null) {
0348 // alarmClock.interrupt();
0349 // try {
0350 // // Wait until the thread die.
0351 // //
0352 // alarmClock.join();
0353 // } catch (InterruptedException ex) {
0354 // // Ignore...
0355 // }
0356 // // Remove the reference on the TimerAlarmClock.
0357 // //
0358
0359 alarmClock.cancel();
0360 alarmClock = null;
0361 }
0362 }
0363
0364 timer.cancel();
0365
0366 // Set the state to OFF.
0367 //
0368 isActive = false;
0369
0370 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0371 "stop", "timer stopped");
0372 } else {
0373 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0374 "stop", "the timer is already deactivated");
0375 }
0376 }
0377
0378 /**
0379 * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>
0380 * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date,
0381 * period and number of occurrences.
0382 * <P>
0383 * If the timer notification to be inserted has a date that is before the current date,
0384 * the method behaves as if the specified date were the current date. <BR>
0385 * For once-off notifications, the notification is delivered immediately. <BR>
0386 * For periodic notifications, the first notification is delivered immediately and the
0387 * subsequent ones are spaced as specified by the period parameter.
0388 * <P>
0389 * Note that once the timer notification has been added into the list of notifications,
0390 * its associated date, period and number of occurrences cannot be updated.
0391 * <P>
0392 * In the case of a periodic notification, the value of parameter <i>fixedRate</i> is used to
0393 * specify the execution scheme, as specified in {@link java.util.Timer}.
0394 *
0395 * @param type The timer notification type.
0396 * @param message The timer notification detailed message.
0397 * @param userData The timer notification user data object.
0398 * @param date The date when the notification occurs.
0399 * @param period The period of the timer notification (in milliseconds).
0400 * @param nbOccurences The total number the timer notification will be emitted.
0401 * @param fixedRate If <code>true</code> and if the notification is periodic, the notification
0402 * is scheduled with a <i>fixed-rate</i> execution scheme. If
0403 * <code>false</code> and if the notification is periodic, the notification
0404 * is scheduled with a <i>fixed-delay</i> execution scheme. Ignored if the
0405 * notification is not periodic.
0406 *
0407 * @return The identifier of the new created timer notification.
0408 *
0409 * @exception java.lang.IllegalArgumentException The date is {@code null} or
0410 * the period or the number of occurrences is negative.
0411 *
0412 * @see #addNotification(String, String, Object, Date, long, long)
0413 */
0414 // NPCTE fix for bugId 4464388, esc 0, MR, to be added after modification of jmx spec
0415 // public synchronized Integer addNotification(String type, String message, Serializable userData,
0416 // Date date, long period, long nbOccurences)
0417 // end of NPCTE fix for bugId 4464388
0418 public synchronized Integer addNotification(String type,
0419 String message, Object userData, Date date, long period,
0420 long nbOccurences, boolean fixedRate)
0421 throws java.lang.IllegalArgumentException {
0422
0423 if (date == null) {
0424 throw new java.lang.IllegalArgumentException(
0425 "Timer notification date cannot be null.");
0426 }
0427
0428 // Check that all the timer notification attributes are valid.
0429 //
0430
0431 // Invalid timer period value exception:
0432 // Check that the period and the nbOccurences are POSITIVE VALUES.
0433 //
0434 if ((period < 0) || (nbOccurences < 0)) {
0435 throw new java.lang.IllegalArgumentException(
0436 "Negative values for the periodicity");
0437 }
0438
0439 Date currentDate = new Date();
0440
0441 // Update the date if it is before the current date.
0442 //
0443 if (currentDate.after(date)) {
0444
0445 date.setTime(currentDate.getTime());
0446 if (TIMER_LOGGER.isLoggable(Level.FINER)) {
0447 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0448 "addNotification",
0449 "update timer notification to add with:"
0450 + "\n\tNotification date = " + date);
0451 }
0452 }
0453
0454 // Create and add the timer notification into the timer table.
0455 //
0456 Integer notifID = null;
0457 notifID = new Integer(++counterID);
0458
0459 // The sequenceNumber and the timeStamp attributes are updated
0460 // when the notification is emitted by the timer.
0461 //
0462 TimerNotification notif = new TimerNotification(type, this , 0,
0463 0, message, notifID);
0464 notif.setUserData(userData);
0465
0466 Object[] obj = new Object[6];
0467
0468 TimerAlarmClock alarmClock;
0469 if (fixedRate) {
0470 alarmClock = new TimerAlarmClock(this , date);
0471 } else {
0472 alarmClock = new TimerAlarmClock(this ,
0473 (date.getTime() - currentDate.getTime()));
0474 }
0475
0476 // Fix bug 00417.B
0477 // The date registered into the timer is a clone from the date parameter.
0478 //
0479 Date d = new Date(date.getTime());
0480
0481 obj[TIMER_NOTIF_INDEX] = (Object) notif;
0482 obj[TIMER_DATE_INDEX] = (Object) d;
0483 obj[TIMER_PERIOD_INDEX] = (Object) new Long(period);
0484 obj[TIMER_NB_OCCUR_INDEX] = (Object) new Long(nbOccurences);
0485 obj[ALARM_CLOCK_INDEX] = (Object) alarmClock;
0486 obj[FIXED_RATE_INDEX] = Boolean.valueOf(fixedRate);
0487
0488 if (TIMER_LOGGER.isLoggable(Level.FINER)) {
0489 StringBuilder strb = new StringBuilder()
0490 .append("adding timer notification:\n\t")
0491 .append("Notification source = ")
0492 .append(notif.getSource())
0493 .append("\n\tNotification type = ")
0494 .append(notif.getType())
0495 .append("\n\tNotification ID = ")
0496 .append(notifID)
0497 .append("\n\tNotification date = ")
0498 .append(d)
0499 .append("\n\tNotification period = ")
0500 .append(period)
0501 .append("\n\tNotification nb of occurrences = ")
0502 .append(nbOccurences)
0503 .append(
0504 "\n\tNotification executes at fixed rate = ")
0505 .append(fixedRate);
0506 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0507 "addNotification", strb.toString());
0508 }
0509
0510 timerTable.put(notifID, obj);
0511
0512 // Update and start the TimerAlarmClock.
0513 //
0514 if (isActive == true) {
0515 if (fixedRate) {
0516 timer.schedule(alarmClock, alarmClock.next);
0517 } else {
0518 timer.schedule(alarmClock, alarmClock.timeout);
0519 }
0520 }
0521
0522 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0523 "addNotification", "timer notification added");
0524 return notifID;
0525 }
0526
0527 /**
0528 * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>
0529 * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date,
0530 * period and number of occurrences.
0531 * <P>
0532 * If the timer notification to be inserted has a date that is before the current date,
0533 * the method behaves as if the specified date were the current date. <BR>
0534 * For once-off notifications, the notification is delivered immediately. <BR>
0535 * For periodic notifications, the first notification is delivered immediately and the
0536 * subsequent ones are spaced as specified by the period parameter.
0537 * <P>
0538 * Note that once the timer notification has been added into the list of notifications,
0539 * its associated date, period and number of occurrences cannot be updated.
0540 * <P>
0541 * In the case of a periodic notification, uses a <i>fixed-delay</i> execution scheme, as specified in
0542 * {@link java.util.Timer}. In order to use a <i>fixed-rate</i> execution scheme, use
0543 * {@link #addNotification(String, String, Object, Date, long, long, boolean)} instead.
0544 *
0545 * @param type The timer notification type.
0546 * @param message The timer notification detailed message.
0547 * @param userData The timer notification user data object.
0548 * @param date The date when the notification occurs.
0549 * @param period The period of the timer notification (in milliseconds).
0550 * @param nbOccurences The total number the timer notification will be emitted.
0551 *
0552 * @return The identifier of the new created timer notification.
0553 *
0554 * @exception java.lang.IllegalArgumentException The date is {@code null} or
0555 * the period or the number of occurrences is negative.
0556 *
0557 * @see #addNotification(String, String, Object, Date, long, long, boolean)
0558 */
0559 // NPCTE fix for bugId 4464388, esc 0, MR , to be added after modification of jmx spec
0560 // public synchronized Integer addNotification(String type, String message, Serializable userData,
0561 // Date date, long period)
0562 // end of NPCTE fix for bugId 4464388 */
0563 public synchronized Integer addNotification(String type,
0564 String message, Object userData, Date date, long period,
0565 long nbOccurences)
0566 throws java.lang.IllegalArgumentException {
0567
0568 return addNotification(type, message, userData, date, period,
0569 nbOccurences, false);
0570 }
0571
0572 /**
0573 * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>
0574 * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date
0575 * and period and a null number of occurrences.
0576 * <P>
0577 * The timer notification will repeat continuously using the timer period using a <i>fixed-delay</i>
0578 * execution scheme, as specified in {@link java.util.Timer}. In order to use a <i>fixed-rate</i>
0579 * execution scheme, use {@link #addNotification(String, String, Object, Date, long, long,
0580 * boolean)} instead.
0581 * <P>
0582 * If the timer notification to be inserted has a date that is before the current date,
0583 * the method behaves as if the specified date were the current date. The
0584 * first notification is delivered immediately and the subsequent ones are
0585 * spaced as specified by the period parameter.
0586 *
0587 * @param type The timer notification type.
0588 * @param message The timer notification detailed message.
0589 * @param userData The timer notification user data object.
0590 * @param date The date when the notification occurs.
0591 * @param period The period of the timer notification (in milliseconds).
0592 *
0593 * @return The identifier of the new created timer notification.
0594 *
0595 * @exception java.lang.IllegalArgumentException The date is {@code null} or
0596 * the period is negative.
0597 */
0598 // NPCTE fix for bugId 4464388, esc 0, MR , to be added after modification of jmx spec
0599 // public synchronized Integer addNotification(String type, String message, Serializable userData,
0600 // Date date, long period)
0601 // end of NPCTE fix for bugId 4464388 */
0602 public synchronized Integer addNotification(String type,
0603 String message, Object userData, Date date, long period)
0604 throws java.lang.IllegalArgumentException {
0605
0606 return (addNotification(type, message, userData, date, period,
0607 0));
0608 }
0609
0610 /**
0611 * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>
0612 * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date
0613 * and a null period and number of occurrences.
0614 * <P>
0615 * The timer notification will be handled once at the specified date.
0616 * <P>
0617 * If the timer notification to be inserted has a date that is before the current date,
0618 * the method behaves as if the specified date were the current date and the
0619 * notification is delivered immediately.
0620 *
0621 * @param type The timer notification type.
0622 * @param message The timer notification detailed message.
0623 * @param userData The timer notification user data object.
0624 * @param date The date when the notification occurs.
0625 *
0626 * @return The identifier of the new created timer notification.
0627 *
0628 * @exception java.lang.IllegalArgumentException The date is {@code null}.
0629 */
0630 // NPCTE fix for bugId 4464388, esc 0, MR, to be added after modification of jmx spec
0631 // public synchronized Integer addNotification(String type, String message, Serializable userData, Date date)
0632 // throws java.lang.IllegalArgumentException {
0633 // end of NPCTE fix for bugId 4464388
0634 public synchronized Integer addNotification(String type,
0635 String message, Object userData, Date date)
0636 throws java.lang.IllegalArgumentException {
0637
0638 return (addNotification(type, message, userData, date, 0, 0));
0639 }
0640
0641 /**
0642 * Removes the timer notification corresponding to the specified identifier from the list of notifications.
0643 *
0644 * @param id The timer notification identifier.
0645 *
0646 * @exception InstanceNotFoundException The specified identifier does not correspond to any timer notification
0647 * in the list of notifications of this timer MBean.
0648 */
0649 public synchronized void removeNotification(Integer id)
0650 throws InstanceNotFoundException {
0651
0652 // Check that the notification to remove is effectively in the timer table.
0653 //
0654 if (timerTable.containsKey(id) == false) {
0655 throw new InstanceNotFoundException(
0656 "Timer notification to remove not in the list of notifications");
0657 }
0658
0659 // Stop the TimerAlarmClock.
0660 //
0661 Object[] obj = timerTable.get(id);
0662 TimerAlarmClock alarmClock = (TimerAlarmClock) obj[ALARM_CLOCK_INDEX];
0663 if (alarmClock != null) {
0664 // alarmClock.interrupt();
0665 // try {
0666 // // Wait until the thread die.
0667 // //
0668 // alarmClock.join();
0669 // } catch (InterruptedException e) {
0670 // // Ignore...
0671 // }
0672 // // Remove the reference on the TimerAlarmClock.
0673 // //
0674 alarmClock.cancel();
0675 alarmClock = null;
0676 }
0677
0678 // Remove the timer notification from the timer table.
0679 //
0680 if (TIMER_LOGGER.isLoggable(Level.FINER)) {
0681 StringBuilder strb = new StringBuilder()
0682 .append("removing timer notification:")
0683 .append("\n\tNotification source = ")
0684 .append(
0685 ((TimerNotification) obj[TIMER_NOTIF_INDEX])
0686 .getSource())
0687 .append("\n\tNotification type = ")
0688 .append(
0689 ((TimerNotification) obj[TIMER_NOTIF_INDEX])
0690 .getType())
0691 .append("\n\tNotification ID = ")
0692 .append(
0693 ((TimerNotification) obj[TIMER_NOTIF_INDEX])
0694 .getNotificationID())
0695 .append("\n\tNotification date = ")
0696 .append(obj[TIMER_DATE_INDEX])
0697 .append("\n\tNotification period = ")
0698 .append(obj[TIMER_PERIOD_INDEX])
0699 .append("\n\tNotification nb of occurrences = ")
0700 .append(obj[TIMER_NB_OCCUR_INDEX])
0701 .append(
0702 "\n\tNotification executes at fixed rate = ")
0703 .append(obj[FIXED_RATE_INDEX]);
0704 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0705 "removeNotification", strb.toString());
0706 }
0707
0708 timerTable.remove(id);
0709
0710 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0711 "removeNotification", "timer notification removed");
0712 }
0713
0714 /**
0715 * Removes all the timer notifications corresponding to the specified type from the list of notifications.
0716 *
0717 * @param type The timer notification type.
0718 *
0719 * @exception InstanceNotFoundException The specified type does not correspond to any timer notification
0720 * in the list of notifications of this timer MBean.
0721 */
0722 public synchronized void removeNotifications(String type)
0723 throws InstanceNotFoundException {
0724
0725 Vector<Integer> v = getNotificationIDs(type);
0726
0727 if (v.isEmpty())
0728 throw new InstanceNotFoundException(
0729 "Timer notifications to remove not in the list of notifications");
0730
0731 for (Integer i : v)
0732 removeNotification(i);
0733 }
0734
0735 /**
0736 * Removes all the timer notifications from the list of notifications
0737 * and resets the counter used to update the timer notification identifiers.
0738 */
0739 public synchronized void removeAllNotifications() {
0740
0741 TimerAlarmClock alarmClock;
0742
0743 for (Object[] obj : timerTable.values()) {
0744
0745 // Stop the TimerAlarmClock.
0746 //
0747 alarmClock = (TimerAlarmClock) obj[ALARM_CLOCK_INDEX];
0748 // if (alarmClock != null) {
0749 // alarmClock.interrupt();
0750 // try {
0751 // // Wait until the thread die.
0752 // //
0753 // alarmClock.join();
0754 // } catch (InterruptedException ex) {
0755 // // Ignore...
0756 // }
0757 // Remove the reference on the TimerAlarmClock.
0758 //
0759 // }
0760 alarmClock.cancel();
0761 alarmClock = null;
0762 }
0763
0764 // Remove all the timer notifications from the timer table.
0765 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0766 "removeAllNotifications",
0767 "removing all timer notifications");
0768
0769 timerTable.clear();
0770
0771 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0772 "removeAllNotifications",
0773 "all timer notifications removed");
0774 // Reset the counterID.
0775 //
0776 counterID = 0;
0777
0778 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
0779 "removeAllNotifications",
0780 "timer notification counter ID reset");
0781 }
0782
0783 // GETTERS AND SETTERS
0784 //--------------------
0785
0786 /**
0787 * Gets the number of timer notifications registered into the list of notifications.
0788 *
0789 * @return The number of timer notifications.
0790 */
0791 public int getNbNotifications() {
0792 return timerTable.size();
0793 }
0794
0795 /**
0796 * Gets all timer notification identifiers registered into the list of notifications.
0797 *
0798 * @return A vector of <CODE>Integer</CODE> objects containing all the timer notification identifiers.
0799 * <BR>The vector is empty if there is no timer notification registered for this timer MBean.
0800 */
0801 public synchronized Vector<Integer> getAllNotificationIDs() {
0802 return new Vector<Integer>(timerTable.keySet());
0803 }
0804
0805 /**
0806 * Gets all the identifiers of timer notifications corresponding to the specified type.
0807 *
0808 * @param type The timer notification type.
0809 *
0810 * @return A vector of <CODE>Integer</CODE> objects containing all the identifiers of
0811 * timer notifications with the specified <CODE>type</CODE>.
0812 * <BR>The vector is empty if there is no timer notifications registered for this timer MBean
0813 * with the specified <CODE>type</CODE>.
0814 */
0815 public synchronized Vector<Integer> getNotificationIDs(String type) {
0816
0817 String s;
0818
0819 Vector<Integer> v = new Vector<Integer>();
0820
0821 for (Map.Entry<Integer, Object[]> entry : timerTable.entrySet()) {
0822 Object[] obj = entry.getValue();
0823 s = ((TimerNotification) obj[TIMER_NOTIF_INDEX]).getType();
0824 if ((type == null) ? s == null : type.equals(s))
0825 v.addElement(entry.getKey());
0826 }
0827 return v;
0828 }
0829
0830 // 5089997: return is Vector<Integer> not Vector<TimerNotification>
0831
0832 /**
0833 * Gets the timer notification type corresponding to the specified identifier.
0834 *
0835 * @param id The timer notification identifier.
0836 *
0837 * @return The timer notification type or null if the identifier is not mapped to any
0838 * timer notification registered for this timer MBean.
0839 */
0840 public String getNotificationType(Integer id) {
0841
0842 Object[] obj = timerTable.get(id);
0843 if (obj != null) {
0844 return (((TimerNotification) obj[TIMER_NOTIF_INDEX])
0845 .getType());
0846 }
0847 return null;
0848 }
0849
0850 /**
0851 * Gets the timer notification detailed message corresponding to the specified identifier.
0852 *
0853 * @param id The timer notification identifier.
0854 *
0855 * @return The timer notification detailed message or null if the identifier is not mapped to any
0856 * timer notification registered for this timer MBean.
0857 */
0858 public String getNotificationMessage(Integer id) {
0859
0860 Object[] obj = timerTable.get(id);
0861 if (obj != null) {
0862 return (((TimerNotification) obj[TIMER_NOTIF_INDEX])
0863 .getMessage());
0864 }
0865 return null;
0866 }
0867
0868 /**
0869 * Gets the timer notification user data object corresponding to the specified identifier.
0870 *
0871 * @param id The timer notification identifier.
0872 *
0873 * @return The timer notification user data object or null if the identifier is not mapped to any
0874 * timer notification registered for this timer MBean.
0875 */
0876 // NPCTE fix for bugId 4464388, esc 0, MR, 03 sept 2001, to be added after modification of jmx spec
0877 //public Serializable getNotificationUserData(Integer id) {
0878 // end of NPCTE fix for bugId 4464388
0879 public Object getNotificationUserData(Integer id) {
0880 Object[] obj = timerTable.get(id);
0881 if (obj != null) {
0882 return (((TimerNotification) obj[TIMER_NOTIF_INDEX])
0883 .getUserData());
0884 }
0885 return null;
0886 }
0887
0888 /**
0889 * Gets a copy of the date associated to a timer notification.
0890 *
0891 * @param id The timer notification identifier.
0892 *
0893 * @return A copy of the date or null if the identifier is not mapped to any
0894 * timer notification registered for this timer MBean.
0895 */
0896 public Date getDate(Integer id) {
0897
0898 Object[] obj = timerTable.get(id);
0899 if (obj != null) {
0900 Date date = (Date) obj[TIMER_DATE_INDEX];
0901 return (new Date(date.getTime()));
0902 }
0903 return null;
0904 }
0905
0906 /**
0907 * Gets a copy of the period (in milliseconds) associated to a timer notification.
0908 *
0909 * @param id The timer notification identifier.
0910 *
0911 * @return A copy of the period or null if the identifier is not mapped to any
0912 * timer notification registered for this timer MBean.
0913 */
0914 public Long getPeriod(Integer id) {
0915
0916 Object[] obj = timerTable.get(id);
0917 if (obj != null) {
0918 Long period = (Long) obj[TIMER_PERIOD_INDEX];
0919 return (new Long(period.longValue()));
0920 }
0921 return null;
0922 }
0923
0924 /**
0925 * Gets a copy of the remaining number of occurrences associated to a timer notification.
0926 *
0927 * @param id The timer notification identifier.
0928 *
0929 * @return A copy of the remaining number of occurrences or null if the identifier is not mapped to any
0930 * timer notification registered for this timer MBean.
0931 */
0932 public Long getNbOccurences(Integer id) {
0933
0934 Object[] obj = timerTable.get(id);
0935 if (obj != null) {
0936 Long nbOccurences = (Long) obj[TIMER_NB_OCCUR_INDEX];
0937 return (new Long(nbOccurences.longValue()));
0938 }
0939 return null;
0940 }
0941
0942 /**
0943 * Gets a copy of the flag indicating whether a periodic notification is
0944 * executed at <i>fixed-delay</i> or at <i>fixed-rate</i>.
0945 *
0946 * @param id The timer notification identifier.
0947 *
0948 * @return A copy of the flag indicating whether a periodic notification is
0949 * executed at <i>fixed-delay</i> or at <i>fixed-rate</i>.
0950 */
0951 public Boolean getFixedRate(Integer id) {
0952
0953 Object[] obj = timerTable.get(id);
0954 if (obj != null) {
0955 Boolean fixedRate = (Boolean) obj[FIXED_RATE_INDEX];
0956 return (Boolean.valueOf(fixedRate.booleanValue()));
0957 }
0958 return null;
0959 }
0960
0961 /**
0962 * Gets the flag indicating whether or not the timer sends past notifications.
0963 * <BR>The default value of the past notifications sending on/off flag is <CODE>false</CODE>.
0964 *
0965 * @return The past notifications sending on/off flag value.
0966 *
0967 * @see #setSendPastNotifications
0968 */
0969 public boolean getSendPastNotifications() {
0970 return sendPastNotifications;
0971 }
0972
0973 /**
0974 * Sets the flag indicating whether the timer sends past notifications or not.
0975 * <BR>The default value of the past notifications sending on/off flag is <CODE>false</CODE>.
0976 *
0977 * @param value The past notifications sending on/off flag value.
0978 *
0979 * @see #getSendPastNotifications
0980 */
0981 public void setSendPastNotifications(boolean value) {
0982 sendPastNotifications = value;
0983 }
0984
0985 /**
0986 * Tests whether the timer MBean is active.
0987 * A timer MBean is marked active when the {@link #start start} method is called.
0988 * It becomes inactive when the {@link #stop stop} method is called.
0989 * <BR>The default value of the active on/off flag is <CODE>false</CODE>.
0990 *
0991 * @return <CODE>true</CODE> if the timer MBean is active, <CODE>false</CODE> otherwise.
0992 */
0993 public boolean isActive() {
0994 return isActive;
0995 }
0996
0997 /**
0998 * Tests whether the list of timer notifications is empty.
0999 *
1000 * @return <CODE>true</CODE> if the list of timer notifications is empty, <CODE>false</CODE> otherwise.
1001 */
1002 public boolean isEmpty() {
1003 return (timerTable.isEmpty());
1004 }
1005
1006 /*
1007 * ------------------------------------------
1008 * PRIVATE METHODS
1009 * ------------------------------------------
1010 */
1011
1012 /**
1013 * Sends or not past notifications depending on the specified flag.
1014 *
1015 * @param currentDate The current date.
1016 * @param currentFlag The flag indicating if past notifications must be sent or not.
1017 */
1018 private synchronized void sendPastNotifications(Date currentDate,
1019 boolean currentFlag) {
1020
1021 TimerNotification notif;
1022 Integer notifID;
1023 Date date;
1024
1025 for (Object[] obj : timerTable.values()) {
1026
1027 // Retrieve the timer notification and the date notification.
1028 //
1029 notif = (TimerNotification) obj[TIMER_NOTIF_INDEX];
1030 notifID = notif.getNotificationID();
1031 date = (Date) obj[TIMER_DATE_INDEX];
1032
1033 // Update the timer notification while:
1034 // - the timer notification date is earlier than the current date
1035 // - the timer notification has not been removed from the timer table.
1036 //
1037 while ((currentDate.after(date))
1038 && (timerTable.containsKey(notifID))) {
1039
1040 if (currentFlag == true) {
1041 if (TIMER_LOGGER.isLoggable(Level.FINER)) {
1042 StringBuilder strb = new StringBuilder()
1043 .append(
1044 "sending past timer notification:")
1045 .append("\n\tNotification source = ")
1046 .append(notif.getSource())
1047 .append("\n\tNotification type = ")
1048 .append(notif.getType())
1049 .append("\n\tNotification ID = ")
1050 .append(notif.getNotificationID())
1051 .append("\n\tNotification date = ")
1052 .append(date)
1053 .append("\n\tNotification period = ")
1054 .append(obj[TIMER_PERIOD_INDEX])
1055 .append(
1056 "\n\tNotification nb of occurrences = ")
1057 .append(obj[TIMER_NB_OCCUR_INDEX])
1058 .append(
1059 "\n\tNotification executes at fixed rate = ")
1060 .append(obj[FIXED_RATE_INDEX]);
1061 TIMER_LOGGER.logp(Level.FINER, Timer.class
1062 .getName(), "sendPastNotifications",
1063 strb.toString());
1064 }
1065 sendNotification(date, notif);
1066
1067 TIMER_LOGGER.logp(Level.FINER, Timer.class
1068 .getName(), "sendPastNotifications",
1069 "past timer notification sent");
1070 }
1071
1072 // Update the date and the number of occurrences of the timer notification.
1073 //
1074 updateTimerTable(notif.getNotificationID());
1075 }
1076 }
1077 }
1078
1079 /**
1080 * If the timer notification is not periodic, it is removed from the list of notifications.
1081 * <P>
1082 * If the timer period of the timer notification has a non null periodicity,
1083 * the date of the timer notification is updated by adding the periodicity.
1084 * The associated TimerAlarmClock is updated by setting its timeout to the period value.
1085 * <P>
1086 * If the timer period has a defined number of occurrences, the timer
1087 * notification is updated if the number of occurrences has not yet been reached.
1088 * Otherwise it is removed from the list of notifications.
1089 *
1090 * @param notifID The timer notification identifier to update.
1091 */
1092 private synchronized void updateTimerTable(Integer notifID) {
1093
1094 // Retrieve the timer notification and the TimerAlarmClock.
1095 //
1096 Object[] obj = timerTable.get(notifID);
1097 Date date = (Date) obj[TIMER_DATE_INDEX];
1098 Long period = (Long) obj[TIMER_PERIOD_INDEX];
1099 Long nbOccurences = (Long) obj[TIMER_NB_OCCUR_INDEX];
1100 Boolean fixedRate = (Boolean) obj[FIXED_RATE_INDEX];
1101 TimerAlarmClock alarmClock = (TimerAlarmClock) obj[ALARM_CLOCK_INDEX];
1102
1103 if (period.longValue() != 0) {
1104
1105 // Update the date and the number of occurrences of the timer notification
1106 // and the TimerAlarmClock time out.
1107 // NOTES :
1108 // nbOccurences = 0 notifies an infinite periodicity.
1109 // nbOccurences = 1 notifies a finite periodicity that has reached its end.
1110 // nbOccurences > 1 notifies a finite periodicity that has not yet reached its end.
1111 //
1112 if ((nbOccurences.longValue() == 0)
1113 || (nbOccurences.longValue() > 1)) {
1114
1115 date.setTime(date.getTime() + period.longValue());
1116 obj[TIMER_NB_OCCUR_INDEX] = new Long(java.lang.Math
1117 .max(0L, (nbOccurences.longValue() - 1)));
1118 nbOccurences = (Long) obj[TIMER_NB_OCCUR_INDEX];
1119
1120 if (isActive == true) {
1121 if (fixedRate.booleanValue()) {
1122 alarmClock = new TimerAlarmClock(this , date);
1123 obj[ALARM_CLOCK_INDEX] = (Object) alarmClock;
1124 timer.schedule(alarmClock, alarmClock.next);
1125 } else {
1126 alarmClock = new TimerAlarmClock(this , period
1127 .longValue());
1128 obj[ALARM_CLOCK_INDEX] = (Object) alarmClock;
1129 timer.schedule(alarmClock, alarmClock.timeout);
1130 }
1131 }
1132 if (TIMER_LOGGER.isLoggable(Level.FINER)) {
1133 TimerNotification notif = (TimerNotification) obj[TIMER_NOTIF_INDEX];
1134 StringBuilder strb = new StringBuilder()
1135 .append("update timer notification with:")
1136 .append("\n\tNotification source = ")
1137 .append(notif.getSource())
1138 .append("\n\tNotification type = ")
1139 .append(notif.getType())
1140 .append("\n\tNotification ID = ")
1141 .append(notifID)
1142 .append("\n\tNotification date = ")
1143 .append(date)
1144 .append("\n\tNotification period = ")
1145 .append(period)
1146 .append(
1147 "\n\tNotification nb of occurrences = ")
1148 .append(nbOccurences)
1149 .append(
1150 "\n\tNotification executes at fixed rate = ")
1151 .append(fixedRate);
1152 TIMER_LOGGER.logp(Level.FINER, Timer.class
1153 .getName(), "updateTimerTable", strb
1154 .toString());
1155 }
1156 } else {
1157 if (alarmClock != null) {
1158 // alarmClock.interrupt();
1159 // try {
1160 // // Wait until the thread die.
1161 // //
1162 // alarmClock.join();
1163 // } catch (InterruptedException e) {
1164 // // Ignore...
1165 // }
1166 alarmClock.cancel();
1167 // Remove the reference on the TimerAlarmClock.
1168 //
1169 alarmClock = null;
1170 }
1171 timerTable.remove(notifID);
1172 }
1173 } else {
1174 if (alarmClock != null) {
1175 // alarmClock.interrupt();
1176 // try {
1177 // // Wait until the thread die.
1178 // //
1179 // alarmClock.join();
1180 // } catch (InterruptedException e) {
1181 // // Ignore...
1182 // }
1183
1184 alarmClock.cancel();
1185
1186 // Remove the reference on the TimerAlarmClock.
1187 //
1188 alarmClock = null;
1189 }
1190 timerTable.remove(notifID);
1191 }
1192 }
1193
1194 /*
1195 * ------------------------------------------
1196 * PACKAGE METHODS
1197 * ------------------------------------------
1198 */
1199
1200 /**
1201 * This method is called by the timer each time
1202 * the TimerAlarmClock has exceeded its timeout.
1203 *
1204 * @param notification The TimerAlarmClock notification.
1205 */
1206 @SuppressWarnings("deprecation")
1207 void notifyAlarmClock(TimerAlarmClockNotification notification) {
1208
1209 TimerNotification timerNotification = null;
1210 Date timerDate = null;
1211
1212 // Retrieve the timer notification associated to the alarm-clock.
1213 //
1214 TimerAlarmClock alarmClock = (TimerAlarmClock) notification
1215 .getSource();
1216
1217 for (Object[] obj : timerTable.values()) {
1218 if (obj[ALARM_CLOCK_INDEX] == alarmClock) {
1219 timerNotification = (TimerNotification) obj[TIMER_NOTIF_INDEX];
1220 timerDate = (Date) obj[TIMER_DATE_INDEX];
1221 break;
1222 }
1223 }
1224
1225 // Notify the timer.
1226 //
1227 sendNotification(timerDate, timerNotification);
1228
1229 // Update the notification and the TimerAlarmClock timeout.
1230 //
1231 updateTimerTable(timerNotification.getNotificationID());
1232 }
1233
1234 /**
1235 * This method is used by the timer MBean to update and send a timer
1236 * notification to all the listeners registered for this kind of notification.
1237 *
1238 * @param timeStamp The notification emission date.
1239 * @param notification The timer notification to send.
1240 */
1241 void sendNotification(Date timeStamp, TimerNotification notification) {
1242
1243 if (TIMER_LOGGER.isLoggable(Level.FINER)) {
1244 StringBuilder strb = new StringBuilder().append(
1245 "sending timer notification:").append(
1246 "\n\tNotification source = ").append(
1247 notification.getSource()).append(
1248 "\n\tNotification type = ").append(
1249 notification.getType()).append(
1250 "\n\tNotification ID = ").append(
1251 notification.getNotificationID()).append(
1252 "\n\tNotification date = ").append(timeStamp);
1253 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
1254 "sendNotification", strb.toString());
1255 }
1256 long curSeqNumber;
1257 synchronized (this ) {
1258 sequenceNumber = sequenceNumber + 1;
1259 curSeqNumber = sequenceNumber;
1260 }
1261 synchronized (notification) {
1262 notification.setTimeStamp(timeStamp.getTime());
1263 notification.setSequenceNumber(curSeqNumber);
1264 this .sendNotification((TimerNotification) notification
1265 .cloneTimerNotification());
1266 }
1267
1268 TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),
1269 "sendNotification", "timer notification sent");
1270 }
1271 }
1272
1273 /**
1274 * TimerAlarmClock inner class:
1275 * This class provides a simple implementation of an alarm clock MBean.
1276 * The aim of this MBean is to set up an alarm which wakes up the timer every timeout (fixed-delay)
1277 * or at the specified date (fixed-rate).
1278 */
1279
1280 class TimerAlarmClock extends java.util.TimerTask {
1281
1282 Timer listener = null;
1283 long timeout = 10000;
1284 Date next = null;
1285
1286 /*
1287 * ------------------------------------------
1288 * CONSTRUCTORS
1289 * ------------------------------------------
1290 */
1291
1292 public TimerAlarmClock(Timer listener, long timeout) {
1293 this .listener = listener;
1294 this .timeout = Math.max(0L, timeout);
1295 }
1296
1297 public TimerAlarmClock(Timer listener, Date next) {
1298 this .listener = listener;
1299 this .next = next;
1300 }
1301
1302 /*
1303 * ------------------------------------------
1304 * PUBLIC METHODS
1305 * ------------------------------------------
1306 */
1307
1308 /**
1309 * This method is called by the timer when it is started.
1310 */
1311 public void run() {
1312
1313 try {
1314 //this.sleep(timeout);
1315 TimerAlarmClockNotification notif = new TimerAlarmClockNotification(
1316 this );
1317 listener.notifyAlarmClock(notif);
1318 } catch (Exception e) {
1319 TIMER_LOGGER
1320 .logp(
1321 Level.FINEST,
1322 Timer.class.getName(),
1323 "run",
1324 "Got unexpected exception when sending a notification",
1325 e);
1326 }
1327 }
1328 }
|