1292 lines · 48.7 KB · Java
RawDownload
/* * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.management.timer; import static com.sun.jmx.defaults.JmxProperties.TIMER_LOGGER;import java.util.ArrayList;import java.util.Date;import java.util.Hashtable;import java.util.Iterator;import java.util.Map;import java.util.Set;import java.util.TreeSet;import java.util.Vector;import java.util.logging.Level; // jmx imports//import javax.management.InstanceNotFoundException;import javax.management.MBeanNotificationInfo;import javax.management.MBeanRegistration;import javax.management.MBeanServer;import javax.management.NotificationBroadcasterSupport;import javax.management.ObjectName; /** * * Provides the implementation of the timer MBean. * The timer MBean sends out an alarm at a specified time * that wakes up all the listeners registered to receive timer notifications. * <P> * * This class manages a list of dated timer notifications. * A method allows users to add/remove as many notifications as required. * When a timer notification is emitted by the timer and becomes obsolete, * it is automatically removed from the list of timer notifications. * <BR>Additional timer notifications can be added into regularly repeating notifications. * <P> * * Note: * <OL> * <LI>When sending timer notifications, the timer updates the notification sequence number * irrespective of the notification type. * <LI>The timer service relies on the system date of the host where the <CODE>Timer</CODE> class is loaded. * Listeners may receive untimely notifications * if their host has a different system date. * To avoid such problems, synchronize the system date of all host machines where timing is needed. * <LI>The default behavior for periodic notifications is <i>fixed-delay execution</i>, as *     specified in {@link java.util.Timer}. In order to use <i>fixed-rate execution</i>, use the *     overloaded {@link #addNotification(String, String, Object, Date, long, long, boolean)} method. * <LI>Notification listeners are potentially all executed in the same * thread.  Therefore, they should execute rapidly to avoid holding up * other listeners or perturbing the regularity of fixed-delay * executions.  See {@link NotificationBroadcasterSupport}. * </OL> * * @since 1.5 */public class Timer extends NotificationBroadcasterSupport        implements TimerMBean, MBeanRegistration {      /*     * ------------------------------------------     *  PUBLIC VARIABLES     * ------------------------------------------     */     /**     * Number of milliseconds in one second.     * Useful constant for the <CODE>addNotification</CODE> method.     */    public static final long ONE_SECOND = 1000;     /**     * Number of milliseconds in one minute.     * Useful constant for the <CODE>addNotification</CODE> method.     */    public static final long ONE_MINUTE = 60*ONE_SECOND;     /**     * Number of milliseconds in one hour.     * Useful constant for the <CODE>addNotification</CODE> method.     */    public static final long ONE_HOUR   = 60*ONE_MINUTE;     /**     * Number of milliseconds in one day.     * Useful constant for the <CODE>addNotification</CODE> method.     */    public static final long ONE_DAY    = 24*ONE_HOUR;     /**     * Number of milliseconds in one week.     * Useful constant for the <CODE>addNotification</CODE> method.     */    public static final long ONE_WEEK   = 7*ONE_DAY;     /*     * ------------------------------------------     *  PRIVATE VARIABLES     * ------------------------------------------     */     /**     * Table containing all the timer notifications of this timer,     * with the associated date, period and number of occurrences.     */    private Map<Integer,Object[]> timerTable =        new Hashtable<Integer,Object[]>();     /**     * Past notifications sending on/off flag value.     * This attribute is used to specify if the timer has to send past notifications after start.     * <BR>The default value is set to <CODE>false</CODE>.     */    private boolean sendPastNotifications = false;     /**     * Timer state.     * The default value is set to <CODE>false</CODE>.     */    private transient boolean isActive = false;     /**     * Timer sequence number.     * The default value is set to 0.     */    private transient long sequenceNumber = 0;     // Flags needed to keep the indexes of the objects in the array.    //    private static final int TIMER_NOTIF_INDEX     = 0;    private static final int TIMER_DATE_INDEX      = 1;    private static final int TIMER_PERIOD_INDEX    = 2;    private static final int TIMER_NB_OCCUR_INDEX  = 3;    private static final int ALARM_CLOCK_INDEX     = 4;    private static final int FIXED_RATE_INDEX      = 5;     /**     * The notification counter ID.     * Used to keep the max key value inserted into the timer table.     */    private int counterID = 0;     private java.util.Timer timer;     /*     * ------------------------------------------     *  CONSTRUCTORS     * ------------------------------------------     */     /**     * Default constructor.     */    public Timer() {    }     /*     * ------------------------------------------     *  PUBLIC METHODS     * ------------------------------------------     */     /**     * Allows the timer MBean to perform any operations it needs before being registered     * in the MBean server.     * <P>     * Not used in this context.     *     * @param server The MBean server in which the timer MBean will be registered.     * @param name The object name of the timer MBean.     *     * @return The name of the timer MBean registered.     *     * @exception java.lang.Exception     */    public ObjectName preRegister(MBeanServer server, ObjectName name)        throws java.lang.Exception {        return name;    }     /**     * Allows the timer MBean to perform any operations needed after having been     * registered in the MBean server or after the registration has failed.     * <P>     * Not used in this context.     */    public void postRegister (Boolean registrationDone) {    }     /**     * Allows the timer MBean to perform any operations it needs before being unregistered     * by the MBean server.     * <P>     * Stops the timer.     *     * @exception java.lang.Exception     */    public void preDeregister() throws java.lang.Exception {         TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),                "preDeregister", "stop the timer");         // Stop the timer.        //        stop();    }     /**     * Allows the timer MBean to perform any operations needed after having been     * unregistered by the MBean server.     * <P>     * Not used in this context.     */    public void postDeregister() {    }     /*     * This overrides the method in NotificationBroadcasterSupport.     * Return the MBeanNotificationInfo[] array for this MBean.     * The returned array has one element to indicate that the MBean     * can emit TimerNotification.  The array of type strings     * associated with this entry is a snapshot of the current types     * that were given to addNotification.     */    public synchronized MBeanNotificationInfo[] getNotificationInfo() {        Set<String> notifTypes = new TreeSet<String>();        for (Object[] entry : timerTable.values()) {            TimerNotification notif = (TimerNotification)                entry[TIMER_NOTIF_INDEX];            notifTypes.add(notif.getType());        }        String[] notifTypesArray =            notifTypes.toArray(new String[0]);        return new MBeanNotificationInfo[] {            new MBeanNotificationInfo(notifTypesArray,                                      TimerNotification.class.getName(),                                      "Notification sent by Timer MBean")        };    }     /**     * Starts the timer.     * <P>     * If there is one or more timer notifications before the time in the list of notifications, the notification     * is sent according to the <CODE>sendPastNotifications</CODE> flag and then, updated     * according to its period and remaining number of occurrences.     * If the timer notification date remains earlier than the current date, this notification is just removed     * from the list of notifications.     */    public synchronized void start() {         TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),                "start", "starting the timer");         // Start the TimerAlarmClock.        //        if (isActive == false) {             timer = new java.util.Timer();             TimerAlarmClock alarmClock;            Date date;             Date currentDate = new Date();             // Send or not past notifications depending on the flag.            // Update the date and the number of occurrences of past notifications            // to make them later than the current date.            //            sendPastNotifications(currentDate, sendPastNotifications);             // Update and start all the TimerAlarmClocks.            // Here, all the notifications in the timer table are later than the current date.            //            for (Object[] obj : timerTable.values()) {                 // Retrieve the date notification and the TimerAlarmClock.                //                date = (Date)obj[TIMER_DATE_INDEX];                 // Update all the TimerAlarmClock timeouts and start them.                //                boolean fixedRate = ((Boolean)obj[FIXED_RATE_INDEX]).booleanValue();                if (fixedRate)                {                  alarmClock = new TimerAlarmClock(this, date);                  obj[ALARM_CLOCK_INDEX] = (Object)alarmClock;                  timer.schedule(alarmClock, alarmClock.next);                }                else                {                  alarmClock = new TimerAlarmClock(this, (date.getTime() - currentDate.getTime()));                  obj[ALARM_CLOCK_INDEX] = (Object)alarmClock;                  timer.schedule(alarmClock, alarmClock.timeout);                }            }             // Set the state to ON.            //            isActive = true;             TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),                    "start", "timer started");        } else {            TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),                    "start", "the timer is already activated");        }    }     /**     * Stops the timer.     */    public synchronized void stop() {         TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),                "stop", "stopping the timer");         // Stop the TimerAlarmClock.        //        if (isActive == true) {             for (Object[] obj : timerTable.values()) {                 // Stop all the TimerAlarmClock.                //                TimerAlarmClock alarmClock = (TimerAlarmClock)obj[ALARM_CLOCK_INDEX];                if (alarmClock != null) {//                     alarmClock.interrupt();//                     try {//                         // Wait until the thread die.//                         ////                         alarmClock.join();//                     } catch (InterruptedException ex) {//                         // Ignore...//                     }//                     // Remove the reference on the TimerAlarmClock.//                     //                     alarmClock.cancel();                }            }             timer.cancel();             // Set the state to OFF.            //            isActive = false;             TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),                    "stop", "timer stopped");        } else {            TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),                    "stop", "the timer is already deactivated");        }    }     /**     * Creates a new timer notification with the specified <CODE>type</CODE>, <CODE>message</CODE>     * and <CODE>userData</CODE> and inserts it into the list of notifications with a given date,     * period and number of occurrences.     * <P>     * If the timer notification to be inserted has a date that is before the current date,     * the method behaves as if the specified date were the current date. <BR>     * For once-off notifications, the notification is delivered immediately. <BR>     * For periodic notifications, the first notification is delivered immediately and the     * subsequent ones are spaced as specified by the period parameter.     * <P>     * Note that once the timer notification has been added into the list of notifications,     * its associated date, period and number of occurrences cannot be updated.     * <P>     * In the case of a periodic notification, the value of parameter <i>fixedRate</i> is used to     * specify the execution scheme, as specified in {@link java.util.Timer}.     *     * @param type The timer notification type.     * @param message The timer notification detailed message.     * @param userData The timer notification user data object.     * @param date The date when the notification occurs.     * @param period The period of the timer notification (in milliseconds).     * @param nbOccurences The total number the timer notification will be emitted.     * @param fixedRate If <code>true</code> and if the notification is periodic, the notification     *                  is scheduled with a <i>fixed-rate</i> execution scheme. If     *                  <code>false</code> and if the notification is periodic, the notification     *                  is scheduled with a <i>fixed-delay</i> execution scheme. Ignored if the     *                  notification is not periodic.     *     * @return The identifier of the new created timer notification.     *     * @exception java.lang.IllegalArgumentException The date is {@code null} or     * the period or the number of occurrences is negative.     *     * @see #addNotification(String, String, Object, Date, long, long)     */// NPCTE fix for bugId 4464388, esc 0,  MR, to be added after modification of jmx spec//  public synchronized Integer addNotification(String type, String message, Serializable userData,//                                                Date date, long period, long nbOccurences)// end of NPCTE fix for bugId 4464388     public synchronized Integer addNotification(String type, String message, Object userData,                                                Date date, long period, long nbOccurences, boolean fixedRate)        throws java.lang.IllegalArgumentException {         if (date == null) {            throw new java.lang.IllegalArgumentException("Timer notification date cannot be null.");        }         // Check that all the timer notification attributes are valid.        //         // Invalid timer period value exception:        // Check that the period and the nbOccurences are POSITIVE VALUES.        //        if ((period < 0) || (nbOccurences < 0)) {            throw new java.lang.IllegalArgumentException("Negative values for the periodicity");        }         Date currentDate = new Date();         // Update the date if it is before the current date.        //        if (currentDate.after(date)) {             date.setTime(currentDate.getTime());            if (TIMER_LOGGER.isLoggable(Level.FINER)) {                TIMER_LOGGER.logp(Level.FINER, Timer.class.getName(),                        "addNotification",                        "update timer notification to add with:" +                        "\n\tNotification date = " + date);            }        }         // Create and add the timer notification into the timer table.        //        Integer notifID = Integer.valueOf(++counterID);         // The sequenceNumber and the timeStamp attributes are updated        // when the notification is emitted by the timer.        //        TimerNotification notif = new TimerNotification(type, this, 0, 0, message, notifID);        notif.setUserData(userData);         Object[] obj = new Object[6];         TimerAlarmClock alarmClock;        if (fixedRate)        {          alarmClock = new TimerAlarmClock(this, date);        }        else        {          alarmClock = new TimerAlarmClock(this, (date.getTime() - currentDate.getTime()));        }         // Fix bug 00417.B        // The date registered into the timer is a clone from the date parameter.        //        Date d = new Date(date.getTime());         obj[TIMER_NOTIF_INDEX] = (Object)notif;        obj[TIMER_DATE_INDEX] = (Object)d;        obj[TIMER_PERIOD_INDEX] = (Object) period;        obj[TIMER_NB_OCCUR_INDEX] = (Object) nbOccurences;        obj[ALARM_CLOCK_INDEX] = (Object)alarmClock;        obj[FIXED_RATE_INDEX] = Boolean.valueOf(fixedRate);         if (TIMER_LOGGER.isLoggable(Level.FINER)) {            StringBuilder strb = new StringBuilder()            .append("adding timer notification:\n\t")            .append("Notification source = ")            .append(notif.getSource())            .append("\n\tNotification type = ")            .append(notif.getType())            .append("\n\tNotification ID = ")            .append(notifID)            .append("\n\tNotification date = ")            .append(d)

Lines 1–500 of 1292.