History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/management/timer/Timer.java (1 of 18352 files). Show all

Unified · Split

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