1. /*
  2. * @(#)Timer.java 4.58 04/04/13
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.management.timer;
  8. // java imports
  9. //
  10. import java.util.Date;
  11. import java.util.Enumeration;
  12. import java.util.Hashtable;
  13. import java.util.Iterator;
  14. import java.util.Set;
  15. import java.util.TreeSet;
  16. import java.util.Vector;
  17. // jmx imports
  18. //
  19. import javax.management.MBeanNotificationInfo;
  20. import javax.management.MBeanRegistration;
  21. import javax.management.MBeanServer;
  22. import javax.management.NotificationBroadcasterSupport;
  23. import javax.management.ObjectName;
  24. import javax.management.InstanceNotFoundException;
  25. import com.sun.jmx.trace.Trace;
  26. /**
  27. *
  28. * Provides the implementation of the timer MBean.
  29. * The timer MBean sends out an alarm at a specified time
  30. * that wakes up all the listeners registered to receive timer notifications.
  31. * <P>
  32. *
  33. * This class manages a list of dated timer notifications.
  34. * A method allows users to add/remove as many notifications as required.
  35. * When a timer notification is emitted by the timer and becomes obsolete,
  36. * it is automatically removed from the list of timer notifications.
  37. * <BR>Additional timer notifications can be added into regularly repeating notifications.
  38. * <P>
  39. *
  40. * Note:
  41. * <OL>
  42. * <LI>All notifications before the time when the <CODE>addNotification</CODE> method is called
  43. * are ignored, irrespective of the <CODE>sendPastNotifications</CODE> flag.
  44. * <LI>When sending timer notifications, the timer updates the notification sequence number
  45. * irrespective of the notification type.
  46. * <LI>The timer service relies on the system date of the host where the <CODE>Timer</CODE> class is loaded.
  47. * Listeners may receive untimely notifications
  48. * if their host has a different system date.
  49. * To avoid such problems, synchronize the system date of all host machines where timing is needed.
  50. * <LI>The default behavior for periodic notifications is <i>fixed-delay execution</i>, as
  51. * specified in {@link java.util.Timer}. In order to use <i>fixed-rate execution</i>, use the
  52. * overloaded {@link #addNotification(String, String, Object, Date, long, long, boolean)} method.
  53. * <LI>Notification listeners are potentially all executed in the same
  54. * thread. Therefore, they should execute rapidly to avoid holding up
  55. * other listeners or perturbing the regularity of fixed-delay
  56. * executions. See {@link NotificationBroadcasterSupport}.
  57. * </OL>
  58. *
  59. * @version 4.58 04/13/04
  60. * @author Sun Microsystems, Inc
  61. *
  62. * @since 1.5
  63. */
  64. public class Timer extends NotificationBroadcasterSupport
  65. implements TimerMBean, MBeanRegistration {
  66. /*
  67. * ------------------------------------------
  68. * PUBLIC VARIABLES
  69. * ------------------------------------------
  70. */
  71. /**
  72. * Number of milliseconds in one second.
  73. * Useful constant for the <CODE>addNotification</CODE> method.
  74. */
  75. public static final long ONE_SECOND = 1000;
  76. /**
  77. * Number of milliseconds in one minute.
  78. * Useful constant for the <CODE>addNotification</CODE> method.
  79. */
  80. public static final long ONE_MINUTE = 60*ONE_SECOND;
  81. /**
  82. * Number of milliseconds in one hour.
  83. * Useful constant for the <CODE>addNotification</CODE> method.
  84. */
  85. public static final long ONE_HOUR = 60*ONE_MINUTE;
  86. /**
  87. * Number of milliseconds in one day.
  88. * Useful constant for the <CODE>addNotification</CODE> method.
  89. */
  90. public static final long ONE_DAY = 24*ONE_HOUR;
  91. /**
  92. * Number of milliseconds in one week.
  93. * Useful constant for the <CODE>addNotification</CODE> method.
  94. */
  95. public static final long ONE_WEEK = 7*ONE_DAY;
  96. // TRACES & DEBUG
  97. //---------------
  98. boolean isTraceOn() {
  99. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_TIMER);
  100. }
  101. void trace(String clz, String func, String info) {
  102. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_TIMER, clz, func, info);
  103. }
  104. void trace(String func, String info) {
  105. trace(dbgTag, func, info);
  106. }
  107. boolean isDebugOn() {
  108. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_TIMER);
  109. }
  110. void debug(String clz, String func, String info) {
  111. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_TIMER, clz, func, info);
  112. }
  113. void debug(String func, String info) {
  114. debug(dbgTag, func, info);
  115. }
  116. /*
  117. * ------------------------------------------
  118. * PRIVATE VARIABLES
  119. * ------------------------------------------
  120. */
  121. private static final String dbgTag = "Timer";
  122. /**
  123. * Table containing all the timer notifications of this timer,
  124. * with the associated date, period and number of occurrences.
  125. */
  126. private Hashtable timerTable = new Hashtable();
  127. /**
  128. * Past notifications sending on/off flag value.
  129. * This attribute is used to specify if the timer has to send past notifications after start.
  130. * <BR>The default value is set to <CODE>false</CODE>.
  131. */
  132. private boolean sendPastNotifications = false;
  133. /**
  134. * Timer state.
  135. * The default value is set to <CODE>false</CODE>.
  136. */
  137. private transient boolean isActive = false;
  138. /**
  139. * Timer sequence number.
  140. * The default value is set to 0.
  141. */
  142. private transient long sequenceNumber = 0;
  143. // Flags needed to keep the indexes of the objects in the array.
  144. //
  145. private static final int TIMER_NOTIF_INDEX = 0;
  146. private static final int TIMER_DATE_INDEX = 1;
  147. private static final int TIMER_PERIOD_INDEX = 2;
  148. private static final int TIMER_NB_OCCUR_INDEX = 3;
  149. private static final int ALARM_CLOCK_INDEX = 4;
  150. private static final int FIXED_RATE_INDEX = 5;
  151. /**
  152. * The notification counter ID.
  153. * Used to keep the max key value inserted into the timer table.
  154. */
  155. private int counterID = 0;
  156. private java.util.Timer timer;
  157. /*
  158. * ------------------------------------------
  159. * CONSTRUCTORS
  160. * ------------------------------------------
  161. */
  162. /**
  163. * Default constructor.
  164. */
  165. public Timer() {
  166. }
  167. /*
  168. * ------------------------------------------
  169. * PUBLIC METHODS
  170. * ------------------------------------------
  171. */
  172. /**
  173. * Allows the timer MBean to perform any operations it needs before being registered
  174. * in the MBean server.
  175. * <P>
  176. * Not used in this context.
  177. *
  178. * @param server The MBean server in which the timer MBean will be registered.
  179. * @param name The object name of the timer MBean.
  180. *
  181. * @return The name of the timer MBean registered.
  182. *
  183. * @exception java.lang.Exception
  184. */
  185. public ObjectName preRegister(MBeanServer server, ObjectName name)
  186. throws java.lang.Exception {
  187. return name;
  188. }
  189. /**
  190. * Allows the timer MBean to perform any operations needed after having been
  191. * registered in the MBean server or after the registration has failed.
  192. * <P>
  193. * Not used in this context.
  194. */
  195. public void postRegister (Boolean registrationDone) {
  196. }
  197. /**
  198. * Allows the timer MBean to perform any operations it needs before being unregistered
  199. * by the MBean server.
  200. * <P>
  201. * Stops the timer.
  202. *
  203. * @exception java.lang.Exception
  204. */
  205. public void preDeregister() throws java.lang.Exception {
  206. if (isTraceOn()) {
  207. trace("preDeregister", "stop the timer");
  208. }
  209. // Stop the timer.
  210. //
  211. stop();
  212. }
  213. /**
  214. * Allows the timer MBean to perform any operations needed after having been
  215. * unregistered by the MBean server.
  216. * <P>
  217. * Not used in this context.
  218. */
  219. public void postDeregister() {
  220. }
  221. /*
  222. * This overrides the method in NotificationBroadcasterSupport.
  223. * Return the MBeanNotificationInfo[] array for this MBean.
  224. * The returned array has one element to indicate that the MBean
  225. * can emit TimerNotification. The array of type strings
  226. * associated with this entry is a snapshot of the current types
  227. * that were given to addNotification.
  228. */
  229. public synchronized MBeanNotificationInfo[] getNotificationInfo() {
  230. Set/*<String>*/ notifTypes = new TreeSet();
  231. for (Iterator it = timerTable.values().iterator(); it.hasNext(); ) {
  232. Object[] entry = (Object[]) it.next();
  233. TimerNotification notif = (TimerNotification)
  234. entry[TIMER_NOTIF_INDEX];
  235. notifTypes.add(notif.getType());
  236. }
  237. String[] notifTypesArray = (String[])
  238. notifTypes.toArray(new String[0]);
  239. return new MBeanNotificationInfo[] {
  240. new MBeanNotificationInfo(notifTypesArray,
  241. TimerNotification.class.getName(),
  242. "Notification sent by Timer MBean")
  243. };
  244. }
  245. /**
  246. * Starts the timer.
  247. * <P>
  248. * If there is one or more timer notifications before the time in the list of notifications, the notification
  249. * is sent according to the <CODE>sendPastNotifications</CODE> flag and then, updated
  250. * according to its period and remaining number of occurrences.
  251. * If the timer notification date remains earlier than the current date, this notification is just removed
  252. * from the list of notifications.
  253. */
  254. public synchronized void start() {
  255. if (isTraceOn()) {
  256. trace("start", "starting the timer");
  257. }
  258. // Start the TimerAlarmClock.
  259. //
  260. if (isActive == false) {
  261. timer = new java.util.Timer();
  262. TimerAlarmClock alarmClock;
  263. Object[] obj;
  264. Date date;
  265. Date currentDate = new Date();
  266. // Send or not past notifications depending on the flag.
  267. // Update the date and the number of occurrences of past notifications
  268. // to make them later than the current date.
  269. //
  270. sendPastNotifications(currentDate, sendPastNotifications);
  271. // Update and start all the TimerAlarmClocks.
  272. // Here, all the notifications in the timer table are later than the current date.
  273. //
  274. Enumeration e = timerTable.elements();
  275. while (e.hasMoreElements()) {
  276. obj = (Object[])e.nextElement();
  277. // Retrieve the date notification and the TimerAlarmClock.
  278. //
  279. date = (Date)obj[TIMER_DATE_INDEX];
  280. // Update all the TimerAlarmClock timeouts and start them.
  281. //
  282. boolean fixedRate = ((Boolean)obj[FIXED_RATE_INDEX]).booleanValue();
  283. if (fixedRate)
  284. {
  285. alarmClock = new TimerAlarmClock(this, date);
  286. obj[ALARM_CLOCK_INDEX] = (Object)alarmClock;
  287. timer.schedule(alarmClock, alarmClock.next);
  288. }
  289. else
  290. {
  291. alarmClock = new TimerAlarmClock(this, (date.getTime() - currentDate.getTime()));
  292. obj[ALARM_CLOCK_INDEX] = (Object)alarmClock;
  293. timer.schedule(alarmClock, alarmClock.timeout);
  294. }
  295. }
  296. // Set the state to ON.
  297. //
  298. isActive = true;
  299. if (isTraceOn()) {
  300. trace("start", "timer started");
  301. }
  302. } else {
  303. if (isTraceOn()) {
  304. trace("start", "the timer is already activated");
  305. }
  306. }
  307. }
  308. /**
  309. * Stops the timer.
  310. */
  311. public synchronized void stop() {
  312. if (isTraceOn()) {
  313. trace("stop", "stoping the timer");
  314. }
  315. // Stop the TimerAlarmClock.
  316. //
  317. if (isActive == true) {
  318. TimerAlarmClock alarmClock;
  319. Object[] obj;
  320. Enumeration e = timerTable.elements();
  321. while (e.hasMoreElements()) {
  322. obj = (Object[])e.nextElement();
  323. // Stop all the TimerAlarmClock.
  324. //
  325. alarmClock = (TimerAlarmClock)obj[ALARM_CLOCK_INDEX];
  326. if (alarmClock != null) {
  327. // alarmClock.interrupt();
  328. // try {
  329. // // Wait until the thread die.
  330. // //
  331. // alarmClock.join();
  332. // } catch (InterruptedException ex) {
  333. // // Ignore...
  334. // }
  335. // // Remove the reference on the TimerAlarmClock.
  336. // //
  337. alarmClock.cancel();
  338. alarmClock = null;
  339. }
  340. }
  341. timer.cancel();
  342. // Set the state to OFF.
  343. //
  344. isActive = false;
  345. if (isTraceOn()) {
  346. trace("stop", "timer stopped");
  347. }
  348. } else {
  349. if (isTraceOn()) {
  350. trace("stop", "the timer is already deactivated");
  351. }
  352. }
  353. }
  354. /**
  355. * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>
  356. * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date,
  357. * period and number of occurrences.
  358. * <P>
  359. * If the timer notification to be inserted has a date that is before the current date,
  360. * the method behaves as if the specified date were the current date. <BR>
  361. * For once-off notifications, the notification is delivered immediately. <BR>
  362. * For periodic notifications, the first notification is delivered immediately and the
  363. * subsequent ones are spaced as specified by the period parameter.
  364. * <P>
  365. * Note that once the timer notification has been added into the list of notifications,
  366. * its associated date, period and number of occurrences cannot be updated.
  367. * <P>
  368. * In the case of a periodic notification, the value of parameter <i>fixedRate</i> is used to
  369. * specify the execution scheme, as specified in {@link java.util.Timer}.
  370. *
  371. * @param type The timer notification type.
  372. * @param message The timer notification detailed message.
  373. * @param userData The timer notification user data object.
  374. * @param date The date when the notification occurs.
  375. * @param period The period of the timer notification (in milliseconds).
  376. * @param nbOccurences The total number the timer notification will be emitted.
  377. * @param fixedRate If <code>true</code> and if the notification is periodic, the notification
  378. * is scheduled with a <i>fixed-rate</i> execution scheme. If
  379. * <code>false</code> and if the notification is periodic, the notification
  380. * is scheduled with a <i>fixed-delay</i> execution scheme. Ignored if the
  381. * notification is not periodic.
  382. *
  383. * @return The identifier of the new created timer notification.
  384. *
  385. * @exception java.lang.IllegalArgumentException The period or the number of occurrences is negative
  386. *
  387. * @see #addNotification(String, String, Object, Date, long, long)
  388. */
  389. // NPCTE fix for bugId 4464388, esc 0, MR, to be added after modification of jmx spec
  390. // public synchronized Integer addNotification(String type, String message, Serializable userData,
  391. // Date date, long period, long nbOccurences)
  392. // end of NPCTE fix for bugId 4464388
  393. public synchronized Integer addNotification(String type, String message, Object userData,
  394. Date date, long period, long nbOccurences, boolean fixedRate)
  395. throws java.lang.IllegalArgumentException {
  396. if (date == null) {
  397. throw new java.lang.IllegalArgumentException("Timer notification date cannot be null.");
  398. }
  399. // Check that all the timer notification attributes are valid.
  400. //
  401. // Invalid timer period value exception:
  402. // Check that the period and the nbOccurences are POSITIVE VALUES.
  403. //
  404. if ((period < 0) || (nbOccurences < 0)) {
  405. throw new java.lang.IllegalArgumentException("Negative values for the periodicity");
  406. }
  407. Date currentDate = new Date();
  408. // Update the date if it is before the current date.
  409. //
  410. if (currentDate.after(date)) {
  411. date.setTime(currentDate.getTime());
  412. if (isTraceOn()) {
  413. trace("addNotification", "update timer notification to add with:" +
  414. "\n\tNotification date = " + date);
  415. }
  416. }
  417. // Create and add the timer notification into the timer table.
  418. //
  419. Integer notifID = null;
  420. notifID = new Integer(++counterID);
  421. // The sequenceNumber and the timeStamp attributes are updated
  422. // when the notification is emitted by the timer.
  423. //
  424. TimerNotification notif = new TimerNotification(type, this, 0, 0, message, notifID);
  425. notif.setUserData(userData);
  426. Object[] obj = new Object[6];
  427. TimerAlarmClock alarmClock;
  428. if (fixedRate)
  429. {
  430. alarmClock = new TimerAlarmClock(this, date);
  431. }
  432. else
  433. {
  434. alarmClock = new TimerAlarmClock(this, (date.getTime() - currentDate.getTime()));
  435. }
  436. // Fix bug 00417.B
  437. // The date registered into the timer is a clone from the date parameter.
  438. //
  439. Date d = new Date(date.getTime());
  440. obj[TIMER_NOTIF_INDEX] = (Object)notif;
  441. obj[TIMER_DATE_INDEX] = (Object)d;
  442. obj[TIMER_PERIOD_INDEX] = (Object) new Long(period);
  443. obj[TIMER_NB_OCCUR_INDEX] = (Object) new Long(nbOccurences);
  444. obj[ALARM_CLOCK_INDEX] = (Object)alarmClock;
  445. obj[FIXED_RATE_INDEX] = new Boolean(fixedRate);
  446. if (isTraceOn()) {
  447. trace("addNotification", "adding timer notification:" +
  448. "\n\tNotification source = " + notif.getSource() +
  449. "\n\tNotification type = " + notif.getType() +
  450. "\n\tNotification ID = " + notifID +
  451. "\n\tNotification date = " + d +
  452. "\n\tNotification period = " + period +
  453. "\n\tNotification nb of occurrences = " + nbOccurences +
  454. "\n\tNotification executes at fixed rate = " + fixedRate);
  455. }
  456. timerTable.put(notifID, obj);
  457. // Update and start the TimerAlarmClock.
  458. //
  459. if (isActive == true) {
  460. if (fixedRate)
  461. {
  462. timer.schedule(alarmClock, alarmClock.next);
  463. }
  464. else
  465. {
  466. timer.schedule(alarmClock, alarmClock.timeout);
  467. }
  468. }
  469. if (isTraceOn()) {
  470. trace("addNotification", "timer notification added");
  471. }
  472. return notifID;
  473. }
  474. /**
  475. * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>
  476. * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date,
  477. * period and number of occurrences.
  478. * <P>
  479. * If the timer notification to be inserted has a date that is before the current date,
  480. * the method behaves as if the specified date were the current date. <BR>
  481. * For once-off notifications, the notification is delivered immediately. <BR>
  482. * For periodic notifications, the first notification is delivered immediately and the
  483. * subsequent ones are spaced as specified by the period parameter.
  484. * <P>
  485. * Note that once the timer notification has been added into the list of notifications,
  486. * its associated date, period and number of occurrences cannot be updated.
  487. * <P>
  488. * In the case of a periodic notification, uses a <i>fixed-delay</i> execution scheme, as specified in
  489. * {@link java.util.Timer}. In order to use a <i>fixed-rate</i> execution scheme, use
  490. * {@link #addNotification(String, String, Object, Date, long, long, boolean)} instead.
  491. *
  492. * @param type The timer notification type.
  493. * @param message The timer notification detailed message.
  494. * @param userData The timer notification user data object.
  495. * @param date The date when the notification occurs.
  496. * @param period The period of the timer notification (in milliseconds).
  497. * @param nbOccurences The total number the timer notification will be emitted.
  498. *
  499. * @return The identifier of the new created timer notification.
  500. *
  501. * @exception java.lang.IllegalArgumentException The period or the number of occurrences is negative
  502. *
  503. * @see #addNotification(String, String, Object, Date, long, long, boolean)
  504. */
  505. // NPCTE fix for bugId 4464388, esc 0, MR , to be added after modification of jmx spec
  506. // public synchronized Integer addNotification(String type, String message, Serializable userData,
  507. // Date date, long period)
  508. // end of NPCTE fix for bugId 4464388 */
  509. public synchronized Integer addNotification(String type, String message, Object userData,
  510. Date date, long period, long nbOccurences)
  511. throws java.lang.IllegalArgumentException {
  512. return addNotification(type, message, userData, date, period, nbOccurences, false);
  513. }
  514. /**
  515. * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>
  516. * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date
  517. * and period and a null number of occurrences.
  518. * <P>
  519. * The timer notification will repeat continuously using the timer period using a <i>fixed-delay</i>
  520. * execution scheme, as specified in {@link java.util.Timer}. In order to use a <i>fixed-rate</i>
  521. * execution scheme, use {@link #addNotification(String, String, Object, Date, long, long,
  522. * boolean)} instead.
  523. * <P>
  524. * If the timer notification to be inserted has a date that is before the current date,
  525. * the method behaves as if the specified date were the current date. The
  526. * first notification is delivered immediately and the subsequent ones are
  527. * spaced as specified by the period parameter.
  528. *
  529. * @param type The timer notification type.
  530. * @param message The timer notification detailed message.
  531. * @param userData The timer notification user data object.
  532. * @param date The date when the notification occurs.
  533. * @param period The period of the timer notification (in milliseconds).
  534. *
  535. * @return The identifier of the new created timer notification.
  536. *
  537. * @exception java.lang.IllegalArgumentException The period is negative or
  538. * the date notification is before the current date.
  539. */
  540. // NPCTE fix for bugId 4464388, esc 0, MR , to be added after modification of jmx spec
  541. // public synchronized Integer addNotification(String type, String message, Serializable userData,
  542. // Date date, long period)
  543. // end of NPCTE fix for bugId 4464388 */
  544. public synchronized Integer addNotification(String type, String message, Object userData,
  545. Date date, long period)
  546. throws java.lang.IllegalArgumentException {
  547. return (addNotification(type, message, userData, date, period, 0));
  548. }
  549. /**
  550. * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>
  551. * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date
  552. * and a null period and number of occurrences.
  553. * <P>
  554. * The timer notification will be handled once at the specified date.
  555. * <P>
  556. * If the timer notification to be inserted has a date that is before the current date,
  557. * the method behaves as if the specified date were the current date and the
  558. * notification is delivered immediately.
  559. *
  560. * @param type The timer notification type.
  561. * @param message The timer notification detailed message.
  562. * @param userData The timer notification user data object.
  563. * @param date The date when the notification occurs.
  564. *
  565. * @return The identifier of the new created timer notification.
  566. *
  567. * @exception java.lang.IllegalArgumentException The date notification is before the current date.
  568. */
  569. // NPCTE fix for bugId 4464388, esc 0, MR, to be added after modification of jmx spec
  570. // public synchronized Integer addNotification(String type, String message, Serializable userData, Date date)
  571. // throws java.lang.IllegalArgumentException {
  572. // end of NPCTE fix for bugId 4464388
  573. public synchronized Integer addNotification(String type, String message, Object userData, Date date)
  574. throws java.lang.IllegalArgumentException {
  575. return (addNotification(type, message, userData, date, 0, 0));
  576. }
  577. /**
  578. * Removes the timer notification corresponding to the specified identifier from the list of notifications.
  579. *
  580. * @param id The timer notification identifier.
  581. *
  582. * @exception InstanceNotFoundException The specified identifier does not correspond to any timer notification
  583. * in the list of notifications of this timer MBean.
  584. */
  585. public synchronized void removeNotification(Integer id) throws InstanceNotFoundException {
  586. // Check that the notification to remove is effectively in the timer table.
  587. //
  588. if (timerTable.containsKey(id) == false) {
  589. throw new InstanceNotFoundException("Timer notification to remove not in the list of notifications");
  590. }
  591. // Stop the TimerAlarmClock.
  592. //
  593. Object[] obj = (Object[])timerTable.get(id);
  594. TimerAlarmClock alarmClock = (TimerAlarmClock)obj[ALARM_CLOCK_INDEX];
  595. if (alarmClock != null) {
  596. // alarmClock.interrupt();
  597. // try {
  598. // // Wait until the thread die.
  599. // //
  600. // alarmClock.join();
  601. // } catch (InterruptedException e) {
  602. // // Ignore...
  603. // }
  604. // // Remove the reference on the TimerAlarmClock.
  605. // //
  606. alarmClock.cancel();
  607. alarmClock = null;
  608. }
  609. // Remove the timer notification from the timer table.
  610. //
  611. if (isTraceOn()) {
  612. trace("removeNotification", "removing timer notification:" +
  613. "\n\tNotification source = " + ((TimerNotification)obj[TIMER_NOTIF_INDEX]).getSource() +
  614. "\n\tNotification type = " + ((TimerNotification)obj[TIMER_NOTIF_INDEX]).getType() +
  615. "\n\tNotification ID = " + ((TimerNotification)obj[TIMER_NOTIF_INDEX]).getNotificationID() +
  616. "\n\tNotification date = " + obj[TIMER_DATE_INDEX] +
  617. "\n\tNotification period = " + obj[TIMER_PERIOD_INDEX] +
  618. "\n\tNotification nb of occurrences = " + obj[TIMER_NB_OCCUR_INDEX] +
  619. "\n\tNotification executes at fixed rate = " + obj[FIXED_RATE_INDEX]);
  620. }
  621. timerTable.remove(id);
  622. if (isTraceOn()) {
  623. trace("removeNotification", "timer notification removed");
  624. }
  625. }
  626. /**
  627. * Removes all the timer notifications corresponding to the specified type from the list of notifications.
  628. *
  629. * @param type The timer notification type.
  630. *
  631. * @exception InstanceNotFoundException The specified type does not correspond to any timer notification
  632. * in the list of notifications of this timer MBean.
  633. */
  634. public synchronized void removeNotifications(String type) throws InstanceNotFoundException {
  635. TimerNotification notif;
  636. Integer id;
  637. TimerAlarmClock alarmClock;
  638. Object[] obj;
  639. Vector v = getNotificationIDs(type);
  640. // Check that the notification to remove is effectively in the timer table.
  641. //
  642. if (v.isEmpty()) {
  643. throw new InstanceNotFoundException("Timer notifications to remove not in the list of notifications");
  644. }
  645. Enumeration e = v.elements();
  646. while (e.hasMoreElements()) {
  647. notif = (TimerNotification)e.nextElement();
  648. id = notif.getNotificationID();
  649. obj = (Object[])timerTable.get(id);
  650. timerTable.remove(id);
  651. alarmClock = (TimerAlarmClock)obj[ALARM_CLOCK_INDEX];
  652. if (alarmClock != null) {
  653. alarmClock.cancel();
  654. }
  655. }
  656. }
  657. /**
  658. * Removes all the timer notifications from the list of notifications
  659. * and resets the counter used to update the timer notification identifiers.
  660. */
  661. public synchronized void removeAllNotifications() {
  662. Object[] obj;
  663. TimerAlarmClock alarmClock;
  664. Enumeration e = timerTable.elements();
  665. while (e.hasMoreElements()) {
  666. obj = (Object[])e.nextElement();
  667. // Stop the TimerAlarmClock.
  668. //
  669. alarmClock = (TimerAlarmClock)obj[ALARM_CLOCK_INDEX];
  670. // if (alarmClock != null) {
  671. // alarmClock.interrupt();
  672. // try {
  673. // // Wait until the thread die.
  674. // //
  675. // alarmClock.join();
  676. // } catch (InterruptedException ex) {
  677. // // Ignore...
  678. // }
  679. // Remove the reference on the TimerAlarmClock.
  680. //
  681. // }
  682. alarmClock.cancel();
  683. alarmClock = null;
  684. }
  685. // Remove all the timer notifications from the timer table.
  686. //
  687. if (isTraceOn()) {
  688. trace("removeAllNotifications", "removing all timer notifications");
  689. }
  690. timerTable.clear();
  691. if (isTraceOn()) {
  692. trace("removeAllNotifications", "all timer notifications removed");
  693. }
  694. // Reset the counterID.
  695. //
  696. counterID = 0;
  697. if (isTraceOn()) {
  698. trace("removeAllNotifications", "timer notification counter ID resetted");
  699. }
  700. }
  701. // GETTERS AND SETTERS
  702. //--------------------
  703. /**
  704. * Gets the number of timer notifications registered into the list of notifications.
  705. *
  706. * @return The number of timer notifications.
  707. */
  708. public int getNbNotifications() {
  709. return timerTable.size();
  710. }
  711. /**
  712. * Gets all timer notification identifiers registered into the list of notifications.
  713. *
  714. * @return A vector of <CODE>Integer</CODE> objects containing all the timer notification identifiers.
  715. * <BR>The vector is empty if there is no timer notification registered for this timer MBean.
  716. */
  717. public synchronized Vector getAllNotificationIDs() {
  718. Vector v = new Vector();
  719. Enumeration e = timerTable.keys();
  720. while (e.hasMoreElements()) {
  721. v.addElement((Integer)e.nextElement());
  722. }
  723. return v;
  724. }
  725. /**
  726. * Gets all the identifiers of timer notifications corresponding to the specified type.
  727. *
  728. * @param type The timer notification type.
  729. *
  730. * @return A vector of <CODE>Integer</CODE> objects containing all the identifiers of
  731. * timer notifications with the specified <CODE>type</CODE>.
  732. * <BR>The vector is empty if there is no timer notifications registered for this timer MBean
  733. * with the specified <CODE>type</CODE>.
  734. */
  735. public synchronized Vector getNotificationIDs(String type) {
  736. Object[] obj;
  737. String s;
  738. Vector v = new Vector();
  739. Enumeration e = timerTable.elements();
  740. // If the specified type is null, retreive all the timer notificatiosn which type is null.
  741. //
  742. if (type == null) {
  743. while (e.hasMoreElements()) {
  744. obj = (Object[])e.nextElement();
  745. s = ((TimerNotification)obj[TIMER_NOTIF_INDEX]).getType();
  746. if (s == null) {
  747. v.addElement((TimerNotification)obj[TIMER_NOTIF_INDEX]);
  748. }
  749. }
  750. }
  751. else {
  752. while (e.hasMoreElements()) {
  753. obj = (Object[])e.nextElement();
  754. s = ((TimerNotification)obj[TIMER_NOTIF_INDEX]).getType();
  755. if (type.equals(s)) {
  756. v.addElement((TimerNotification)obj[TIMER_NOTIF_INDEX]);
  757. }
  758. }
  759. }
  760. return v;
  761. }
  762. /**
  763. * Gets the timer notification type corresponding to the specified identifier.
  764. *
  765. * @param id The timer notification identifier.
  766. *
  767. * @return The timer notification type or null if the identifier is not mapped to any
  768. * timer notification registered for this timer MBean.
  769. */
  770. public String getNotificationType(Integer id) {
  771. Object[] obj = (Object[])timerTable.get(id);
  772. if (obj != null) {
  773. return ( (String)((TimerNotification)obj[TIMER_NOTIF_INDEX]).getType() );
  774. }
  775. return null;
  776. }
  777. /**
  778. * Gets the timer notification detailed message corresponding to the specified identifier.
  779. *
  780. * @param id The timer notification identifier.
  781. *
  782. * @return The timer notification detailed message or null if the identifier is not mapped to any
  783. * timer notification registered for this timer MBean.
  784. */
  785. public String getNotificationMessage(Integer id) {
  786. Object[] obj = (Object[])timerTable.get(id);
  787. if (obj != null) {
  788. return ( (String)((TimerNotification)obj[TIMER_NOTIF_INDEX]).getMessage() );
  789. }
  790. return null;
  791. }
  792. /**
  793. * Gets the timer notification user data object corresponding to the specified identifier.
  794. *
  795. * @param id The timer notification identifier.
  796. *
  797. * @return The timer notification user data object or null if the identifier is not mapped to any
  798. * timer notification registered for this timer MBean.
  799. */
  800. // NPCTE fix for bugId 4464388, esc 0, MR, 03 sept 2001, to be added after modification of jmx spec
  801. //public Serializable getNotificationUserData(Integer id) {
  802. // end of NPCTE fix for bugId 4464388
  803. public Object getNotificationUserData(Integer id) {
  804. Object[] obj = (Object[])timerTable.get(id);
  805. if (obj != null) {
  806. return ( ((TimerNotification)obj[TIMER_NOTIF_INDEX]).getUserData() );
  807. }
  808. return null;
  809. }
  810. /**
  811. * Gets a copy of the date associated to a timer notification.
  812. *
  813. * @param id The timer notification identifier.
  814. *
  815. * @return A copy of the date or null if the identifier is not mapped to any
  816. * timer notification registered for this timer MBean.
  817. */
  818. public Date getDate(Integer id) {
  819. Object[] obj = (Object[])timerTable.get(id);
  820. if (obj != null) {
  821. Date date = (Date)obj[TIMER_DATE_INDEX];
  822. return (new Date(date.getTime()));
  823. }
  824. return null;
  825. }
  826. /**
  827. * Gets a copy of the period (in milliseconds) associated to a timer notification.
  828. *
  829. * @param id The timer notification identifier.
  830. *
  831. * @return A copy of the period or null if the identifier is not mapped to any
  832. * timer notification registered for this timer MBean.
  833. */
  834. public Long getPeriod(Integer id) {
  835. Object[] obj = (Object[])timerTable.get(id);
  836. if (obj != null) {
  837. Long period = (Long)obj[TIMER_PERIOD_INDEX];
  838. return (new Long(period.longValue()));
  839. }
  840. return null;
  841. }
  842. /**
  843. * Gets a copy of the remaining number of occurrences associated to a timer notification.
  844. *
  845. * @param id The timer notification identifier.
  846. *
  847. * @return A copy of the remaining number of occurrences or null if the identifier is not mapped to any
  848. * timer notification registered for this timer MBean.
  849. */
  850. public Long getNbOccurences(Integer id) {
  851. Object[] obj = (Object[])timerTable.get(id);
  852. if (obj != null) {
  853. Long nbOccurences = (Long)obj[TIMER_NB_OCCUR_INDEX];
  854. return (new Long(nbOccurences.longValue()));
  855. }
  856. return null;
  857. }
  858. /**
  859. * Gets a copy of the flag indicating whether a periodic notification is
  860. * executed at <i>fixed-delay</i> or at <i>fixed-rate</i>.
  861. *
  862. * @param id The timer notification identifier.
  863. *
  864. * @return A copy of the flag indicating whether a periodic notification is
  865. * executed at <i>fixed-delay</i> or at <i>fixed-rate</i>.
  866. */
  867. public Boolean getFixedRate(Integer id) {
  868. Object[] obj = (Object[])timerTable.get(id);
  869. if (obj != null) {
  870. Boolean fixedRate = (Boolean)obj[FIXED_RATE_INDEX];
  871. return (new Boolean(fixedRate.booleanValue()));
  872. }
  873. return null;
  874. }
  875. /**
  876. * Gets the flag indicating whether or not the timer sends past notifications.
  877. * <BR>The default value of the past notifications sending on/off flag is <CODE>false</CODE>.
  878. *
  879. * @return The past notifications sending on/off flag value.
  880. *
  881. * @see #setSendPastNotifications
  882. */
  883. public boolean getSendPastNotifications() {
  884. return sendPastNotifications;
  885. }
  886. /**
  887. * Sets the flag indicating whether the timer sends past notifications or not.
  888. * <BR>The default value of the past notifications sending on/off flag is <CODE>false</CODE>.
  889. *
  890. * @param value The past notifications sending on/off flag value.
  891. *
  892. * @see #getSendPastNotifications
  893. */
  894. public void setSendPastNotifications(boolean value) {
  895. sendPastNotifications = value;
  896. }
  897. /**
  898. * Tests whether the timer MBean is active.
  899. * A timer MBean is marked active when the {@link #start start} method is called.
  900. * It becomes inactive when the {@link #stop stop} method is called.
  901. * <BR>The default value of the active on/off flag is <CODE>false</CODE>.
  902. *
  903. * @return <CODE>true</CODE> if the timer MBean is active, <CODE>false</CODE> otherwise.
  904. */
  905. public boolean isActive() {
  906. return isActive;
  907. }
  908. /**
  909. * Tests whether the list of timer notifications is empty.
  910. *
  911. * @return <CODE>true</CODE> if the list of timer notifications is empty, <CODE>false</CODE> otherwise.
  912. */
  913. public boolean isEmpty() {
  914. return (timerTable.isEmpty());
  915. }
  916. /*
  917. * ------------------------------------------
  918. * PRIVATE METHODS
  919. * ------------------------------------------
  920. */
  921. /**
  922. * Sends or not past notifications depending on the specified flag.
  923. *
  924. * @param currentDate The current date.
  925. * @param currentFlag The flag indicating if past notifications must be sent or not.
  926. */
  927. private synchronized void sendPastNotifications(Date currentDate, boolean currentFlag) {
  928. TimerNotification notif;
  929. Integer notifID;
  930. Date date;
  931. Object[] obj;
  932. Enumeration e = timerTable.elements();
  933. while (e.hasMoreElements()) {
  934. obj = (Object[])e.nextElement();
  935. // Retrieve the timer notification and the date notification.
  936. //
  937. notif = (TimerNotification)obj[TIMER_NOTIF_INDEX];
  938. notifID = notif.getNotificationID();
  939. date = (Date)obj[TIMER_DATE_INDEX];
  940. // Update the timer notification while:
  941. // - the timer notification date is earlier than the current date
  942. // - the timer notification has not been removed from the timer table.
  943. //
  944. while ( (currentDate.after(date)) && (timerTable.containsKey(notifID)) ) {
  945. if (currentFlag == true) {
  946. if (isTraceOn()) {
  947. trace("sendPastNotifications", "sending past timer notification:" +
  948. "\n\tNotification source = " + notif.getSource() +
  949. "\n\tNotification type = " + notif.getType() +
  950. "\n\tNotification ID = " + notif.getNotificationID() +
  951. "\n\tNotification date = " + date +
  952. "\n\tNotification period = " + obj[TIMER_PERIOD_INDEX] +
  953. "\n\tNotification nb of occurrences = " + obj[TIMER_NB_OCCUR_INDEX] +
  954. "\n\tNotification executes at fixed rate = " + obj[FIXED_RATE_INDEX]);
  955. }
  956. sendNotification(date, notif);
  957. if (isTraceOn()) {
  958. trace("sendPastNotifications", "past timer notification sent");
  959. }
  960. }
  961. // Update the date and the number of occurrences of the timer notification.
  962. //
  963. updateTimerTable(notif.getNotificationID());
  964. }
  965. }
  966. }
  967. /**
  968. * If the timer notification is not periodic, it is removed from the list of notifications.
  969. * <P>
  970. * If the timer period of the timer notification has a non null periodicity,
  971. * the date of the timer notification is updated by adding the periodicity.
  972. * The associated TimerAlarmClock is updated by setting its timeout to the period value.
  973. * <P>
  974. * If the timer period has a defined number of occurrences, the timer
  975. * notification is updated if the number of occurrences has not yet been reached.
  976. * Otherwise it is removed from the list of notifications.
  977. *
  978. * @param notifID The timer notification identifier to update.
  979. */
  980. private synchronized void updateTimerTable(Integer notifID) {
  981. // Retrieve the timer notification and the TimerAlarmClock.
  982. //
  983. Object[] obj = (Object[])timerTable.get(notifID);
  984. Date date = (Date)obj[TIMER_DATE_INDEX];
  985. Long period = (Long)obj[TIMER_PERIOD_INDEX];
  986. Long nbOccurences = (Long)obj[TIMER_NB_OCCUR_INDEX];
  987. Boolean fixedRate = (Boolean)obj[FIXED_RATE_INDEX];
  988. TimerAlarmClock alarmClock = (TimerAlarmClock)obj[ALARM_CLOCK_INDEX];
  989. if (period.longValue() != 0) {
  990. // Update the date and the number of occurrences of the timer notification
  991. // and the TimerAlarmClock time out.
  992. // NOTES :
  993. // nbOccurences = 0 notifies an infinite periodicity.
  994. // nbOccurences = 1 notifies a finite periodicity that has reached its end.
  995. // nbOccurences > 1 notifies a finite periodicity that has not yet reached its end.
  996. //
  997. if ((nbOccurences.longValue() == 0) || (nbOccurences.longValue() > 1)) {
  998. date.setTime(date.getTime() + period.longValue());
  999. obj[TIMER_NB_OCCUR_INDEX] = new Long(java.lang.Math.max(0L, (nbOccurences.longValue() - 1)));
  1000. nbOccurences = (Long)obj[TIMER_NB_OCCUR_INDEX];
  1001. if (isActive == true) {
  1002. if (fixedRate.booleanValue())
  1003. {
  1004. alarmClock = new TimerAlarmClock(this, date);
  1005. obj[ALARM_CLOCK_INDEX] = (Object)alarmClock;
  1006. timer.schedule(alarmClock, alarmClock.next);
  1007. }
  1008. else
  1009. {
  1010. alarmClock = new TimerAlarmClock(this, period.longValue());
  1011. obj[ALARM_CLOCK_INDEX] = (Object)alarmClock;
  1012. timer.schedule(alarmClock, alarmClock.timeout);
  1013. }
  1014. }
  1015. if (isTraceOn()) {
  1016. TimerNotification notif = (TimerNotification)obj[TIMER_NOTIF_INDEX];
  1017. trace("updateTimerTable", "update timer notification with:" +
  1018. "\n\tNotification source = " + notif.getSource() +
  1019. "\n\tNotification type = " + notif.getType() +
  1020. "\n\tNotification ID = " + notifID +
  1021. "\n\tNotification date = " + date +
  1022. "\n\tNotification period = " + period +
  1023. "\n\tNotification nb of occurrences = " + nbOccurences +
  1024. "\n\tNotification executes at fixed rate = " + fixedRate);
  1025. }
  1026. }
  1027. else {
  1028. if (alarmClock != null) {
  1029. // alarmClock.interrupt();
  1030. // try {
  1031. // // Wait until the thread die.
  1032. // //
  1033. // alarmClock.join();
  1034. // } catch (InterruptedException e) {
  1035. // // Ignore...
  1036. // }
  1037. alarmClock.cancel();
  1038. // Remove the reference on the TimerAlarmClock.
  1039. //
  1040. alarmClock = null;
  1041. }
  1042. timerTable.remove(notifID);
  1043. }
  1044. }
  1045. else {
  1046. if (alarmClock != null) {
  1047. // alarmClock.interrupt();
  1048. // try {
  1049. // // Wait until the thread die.
  1050. // //
  1051. // alarmClock.join();
  1052. // } catch (InterruptedException e) {
  1053. // // Ignore...
  1054. // }
  1055. alarmClock.cancel();
  1056. // Remove the reference on the TimerAlarmClock.
  1057. //
  1058. alarmClock = null;
  1059. }
  1060. timerTable.remove(notifID);
  1061. }
  1062. }
  1063. /*
  1064. * ------------------------------------------
  1065. * PACKAGE METHODS
  1066. * ------------------------------------------
  1067. */
  1068. /**
  1069. * This method is called by the timer each time
  1070. * the TimerAlarmClock has exceeded its timeout.
  1071. *
  1072. * @param notification The TimerAlarmClock notification.
  1073. */
  1074. void notifyAlarmClock(TimerAlarmClockNotification notification) {
  1075. Object[] obj;
  1076. TimerNotification timerNotification = null;
  1077. Date timerDate = null;
  1078. // Retrieve the timer notification associated to the alarm-clock.
  1079. //
  1080. TimerAlarmClock alarmClock = (TimerAlarmClock)notification.getSource();
  1081. Enumeration e = timerTable.elements();
  1082. while (e.hasMoreElements()) {
  1083. obj = (Object[])e.nextElement();
  1084. if (obj[ALARM_CLOCK_INDEX] == alarmClock) {
  1085. timerNotification = (TimerNotification)obj[TIMER_NOTIF_INDEX];
  1086. timerDate = (Date)obj[TIMER_DATE_INDEX];
  1087. break;
  1088. }
  1089. }
  1090. // Notify the timer.
  1091. //
  1092. sendNotification(timerDate, timerNotification);
  1093. // Update the notification and the TimerAlarmClock timeout.
  1094. //
  1095. updateTimerTable(timerNotification.getNotificationID());
  1096. }
  1097. /**
  1098. * This method is used by the timer MBean to update and send a timer
  1099. * notification to all the listeners registered for this kind of notification.
  1100. *
  1101. * @param timeStamp The notification emission date.
  1102. * @param notification The timer notification to send.
  1103. */
  1104. void sendNotification(Date timeStamp, TimerNotification notification) {
  1105. if (isTraceOn()) {
  1106. trace("sendNotification", "sending timer notification:" +
  1107. "\n\tNotification source = " + notification.getSource() +
  1108. "\n\tNotification type = " + notification.getType() +
  1109. "\n\tNotification ID = " + notification.getNotificationID() +
  1110. "\n\tNotification date = " + timeStamp);
  1111. }
  1112. long curSeqNumber;
  1113. synchronized(this) {
  1114. sequenceNumber = sequenceNumber + 1;
  1115. curSeqNumber = sequenceNumber;
  1116. }
  1117. synchronized (notification) {
  1118. notification.setTimeStamp(timeStamp.getTime());
  1119. notification.setSequenceNumber(curSeqNumber);
  1120. this.sendNotification((TimerNotification)notification.cloneTimerNotification());
  1121. }
  1122. if (isTraceOn()) {
  1123. trace("sendNotification", "timer notification sent");
  1124. }
  1125. }
  1126. }
  1127. /**
  1128. * TimerAlarmClock inner class:
  1129. * This class provides a simple implementation of an alarm clock MBean.
  1130. * The aim of this MBean is to set up an alarm which wakes up the timer every timeout (fixed-delay)
  1131. * or at the specified date (fixed-rate).
  1132. */
  1133. class TimerAlarmClock extends java.util.TimerTask {
  1134. Timer listener = null;
  1135. long timeout = 10000;
  1136. Date next = null;
  1137. /*
  1138. * ------------------------------------------
  1139. * CONSTRUCTORS
  1140. * ------------------------------------------
  1141. */
  1142. public TimerAlarmClock(Timer listener, long timeout) {
  1143. this.listener = listener;
  1144. this.timeout = Math.max(0L, timeout);
  1145. }
  1146. public TimerAlarmClock(Timer listener, Date next) {
  1147. this.listener = listener;
  1148. this.next = next;
  1149. }
  1150. /*
  1151. * ------------------------------------------
  1152. * PUBLIC METHODS
  1153. * ------------------------------------------
  1154. */
  1155. /**
  1156. * This method is called by the timer when it is started.
  1157. */
  1158. public void run() {
  1159. try {
  1160. //this.sleep(timeout);
  1161. TimerAlarmClockNotification notif = new TimerAlarmClockNotification(this);
  1162. listener.notifyAlarmClock(notif);
  1163. } catch (Exception e) {
  1164. if (Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_TIMER)) {
  1165. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_TIMER, "TimerAlarmClock", "run", "Got an exception when sending a notifiacation: "+e);
  1166. }
  1167. }
  1168. }
  1169. }