Showing the changes to java/pkg/javax/management/timer/Timer.java (1 of 18352 files). Show all
Unified · Split
| @@ -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 | } | ||