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
26package javax.management.timer;
27
28import static com.sun.jmx.defaults.JmxProperties.TIMER_LOGGER;
29import java.util.ArrayList;
30import java.util.Date;
31import java.util.Hashtable;
32import java.util.Iterator;
33import java.util.Map;
34import java.util.Set;
35import java.util.TreeSet;
36import java.util.Vector;
37import java.util.logging.Level;
38
39// jmx imports
40//
41import javax.management.InstanceNotFoundException;
42import javax.management.MBeanNotificationInfo;
43import javax.management.MBeanRegistration;
44import javax.management.MBeanServer;
45import javax.management.NotificationBroadcasterSupport;
46import 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 */
81public 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
1250class 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}