/* * @(#)StringMonitor.java 4.41 04/05/18 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.management.monitor; // java imports // import java.util.Date; import java.util.Timer; import java.util.TimerTask; // jmx imports // import javax.management.ObjectName; import javax.management.MBeanNotificationInfo; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.ReflectionException; /** * Defines a monitor MBean designed to observe the values of a string * attribute. *

* A string monitor sends notifications as follows: *

* * @version 4.41 05/18/04 * @author Sun Microsystems, Inc * * @since 1.5 */ public class StringMonitor extends Monitor implements StringMonitorMBean { // TRACES & DEBUG //--------------- String makeDebugTag() { return "StringMonitor"; } /* * ------------------------------------------ * PRIVATE VARIABLES * ------------------------------------------ */ private final static String[] types = { MonitorNotification.RUNTIME_ERROR, MonitorNotification.OBSERVED_OBJECT_ERROR, MonitorNotification.OBSERVED_ATTRIBUTE_ERROR, MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR, MonitorNotification.STRING_TO_COMPARE_VALUE_MATCHED, MonitorNotification.STRING_TO_COMPARE_VALUE_DIFFERED}; private final static MBeanNotificationInfo[] notifsInfo = { new MBeanNotificationInfo(types, "javax.management.monitor.MonitorNotification", "Notifications sent by the StringMonitor MBean")}; /** * String to compare with the observed attribute. *
The default value is an empty character sequence. */ private String stringToCompare = ""; /** * Flag indicating if the string monitor notifies when matching * the string to compare. *
The default value is set to false. */ private boolean notifyMatch = false; /** * Flag indicating if the string monitor notifies when differing * from the string to compare. *
The default value is set to false. */ private boolean notifyDiffer = false; /** * Derived gauges. *
Each element in this array corresponds to an observed object * in the list. */ private String derivedGauge[] = new String[capacityIncrement]; /** * Derived gauge timestamps. *
Each element in this array corresponds to an observed object * in the list. */ private long derivedGaugeTimestamp[] = new long[capacityIncrement]; /** * This attribute is used to handle the matching/differing mechanism. *
Each element in this array corresponds to an observed object * in the list. */ private int status[] = new int[capacityIncrement]; // Flags needed to implement the matching/differing mechanism. // private static final int MATCHING = 0; private static final int DIFFERING = 1; private static final int MATCHING_OR_DIFFERING = 2; /** * Timer. */ private transient Timer timer = null; /* * ------------------------------------------ * CONSTRUCTORS * ------------------------------------------ */ /** * Default constructor. */ public StringMonitor() { dbgTag = makeDebugTag(); } /* * ------------------------------------------ * PUBLIC METHODS * ------------------------------------------ */ /** * Starts the string monitor. */ public synchronized void start() { if (isTraceOn()) { trace("start", "start the string monitor"); } if (isActive) { if (isTraceOn()) { trace("start", "the string monitor is already activated"); } return; } isActive = true; // Reset values. // for (int i = 0; i < elementCount; i++) { status[i] = MATCHING_OR_DIFFERING; } // Start the AlarmClock. // timer = new Timer(); timer.schedule(new StringAlarmClock(this), getGranularityPeriod(), getGranularityPeriod()); } /** * Stops the string monitor. */ /* This method is not synchronized, because if it were there could be a deadlock with a thread that attempted to get the lock on the monitor before being interrupted or noticing that it had been interrupted. */ public void stop() { if (isTraceOn()) { trace("stop", "stop the string monitor"); } synchronized(this) { if (!isActive) { if (isTraceOn()) { trace("stop", "the string monitor is already deactivated"); } return; } isActive = false; // Stop the AlarmClock. // if (timer != null) { timer.cancel(); timer = null; } } } // GETTERS AND SETTERS //-------------------- /** * Sets the granularity period (in milliseconds). *
The default value of the granularity period is 10 seconds. * * @param period The granularity period value. * @exception java.lang.IllegalArgumentException The granularity * period is less than or equal to zero. * * @see Monitor#setGranularityPeriod(long) */ public synchronized void setGranularityPeriod(long period) throws IllegalArgumentException { super.setGranularityPeriod(period); // Reschedule timer task if timer is already running // if (isActive) { timer.cancel(); timer = new Timer(); timer.schedule(new StringAlarmClock(this), getGranularityPeriod(), getGranularityPeriod()); } } /** * Gets the derived gauge of the specified object, if this object is * contained in the set of observed MBeans, or null otherwise. * * @param object the name of the MBean whose derived gauge is required. * * @return The derived gauge of the specified object. * * @since.unbundled JMX 1.2 */ public synchronized String getDerivedGauge(ObjectName object) { int index = indexOf(object); if (index != -1) return derivedGauge[index]; else return null; } /** * Gets the derived gauge timestamp of the specified object, if * this object is contained in the set of observed MBeans, or * null otherwise. * * @param object the name of the MBean whose derived gauge * timestamp is required. * * @return The derived gauge timestamp of the specified object. * * @since.unbundled JMX 1.2 */ public synchronized long getDerivedGaugeTimeStamp(ObjectName object) { int index = indexOf(object); if (index != -1) return derivedGaugeTimestamp[index]; else return 0; } /** * Returns the derived gauge of the first object in the set of * observed MBeans. * * @return The derived gauge. * @deprecated As of JMX 1.2, replaced by {@link #getDerivedGauge(ObjectName)} */ public synchronized String getDerivedGauge() { return derivedGauge[0]; } /** * Gets the derived gauge timestamp of the first object in the set * of observed MBeans. * * @return The derived gauge timestamp. * @deprecated As of JMX 1.2, replaced by * {@link #getDerivedGaugeTimeStamp(ObjectName)} */ @Deprecated public synchronized long getDerivedGaugeTimeStamp() { return derivedGaugeTimestamp[0]; } /** * Gets the string to compare with the observed attribute common * to all observed MBeans. * * @return The string value. * * @see #setStringToCompare */ public synchronized String getStringToCompare() { return stringToCompare; } /** * Sets the string to compare with the observed attribute common * to all observed MBeans. * * @param value The string value. * @exception java.lang.IllegalArgumentException The specified * string to compare is null. * * @see #getStringToCompare */ public synchronized void setStringToCompare(String value) throws java.lang.IllegalArgumentException { if (value == null) { throw new IllegalArgumentException("Null string to compare"); } stringToCompare = value; // Reset values. // for (int i = 0; i < elementCount; i++) { status[i] = MATCHING_OR_DIFFERING; } } /** * Gets the matching notification's on/off switch value common to * all observed MBeans. * * @return true if the string monitor notifies when * matching the string to compare, false otherwise. * * @see #setNotifyMatch */ public synchronized boolean getNotifyMatch() { return notifyMatch; } /** * Sets the matching notification's on/off switch value common to * all observed MBeans. * * @param value The matching notification's on/off switch value. * * @see #getNotifyMatch */ public synchronized void setNotifyMatch(boolean value) { notifyMatch = value; } /** * Gets the differing notification's on/off switch value common to * all observed MBeans. * * @return true if the string monitor notifies when * differing from the string to compare, false otherwise. * * @see #setNotifyDiffer */ public synchronized boolean getNotifyDiffer() { return notifyDiffer; } /** * Sets the differing notification's on/off switch value common to * all observed MBeans. * * @param value The differing notification's on/off switch value. * * @see #getNotifyDiffer */ public synchronized void setNotifyDiffer(boolean value) { notifyDiffer = value; } /** * Returns a NotificationInfo object containing the * name of the Java class of the notification * and the notification types sent by the string monitor. */ public MBeanNotificationInfo[] getNotificationInfo() { return notifsInfo; } /* * ------------------------------------------ * PRIVATE METHODS * ------------------------------------------ */ /** * Updates the derived gauge and the derived gauge timestamp attributes * of the observed object at the specified index. * * @param scanString The value of the observed attribute. * @param index The index of the observed object. */ private synchronized void updateDerivedGauge(Object scanString, int index) { derivedGaugeTimestamp[index] = System.currentTimeMillis(); derivedGauge[index] = (String)scanString; } /** * Updates the notification attributes of the observed object at the * specified index and notifies the listeners only once if the * notifyMatch/notifyDiffer flag is set to true. * @param index The index of the observed object. */ private void updateNotifications(int index) { boolean sendNotify = false; String type = null; long timeStamp = 0; String msg = null; Object derGauge = null; Object trigger = null; synchronized(this) { // Send matching notification if notifyMatch is true. // Send differing notification if notifyDiffer is true. // if (status[index] == MATCHING_OR_DIFFERING) { if (derivedGauge[index].equals(stringToCompare)) { if (notifyMatch) { sendNotify = true; type = MonitorNotification.STRING_TO_COMPARE_VALUE_MATCHED; timeStamp = derivedGaugeTimestamp[index]; msg = ""; derGauge = derivedGauge[index]; trigger = stringToCompare; } status[index] = DIFFERING; } else { if (notifyDiffer) { sendNotify = true; type = MonitorNotification.STRING_TO_COMPARE_VALUE_DIFFERED; timeStamp = derivedGaugeTimestamp[index]; msg = ""; derGauge = derivedGauge[index]; trigger = stringToCompare; } status[index] = MATCHING; } } else { if (status[index] == MATCHING) { if (derivedGauge[index].equals(stringToCompare)) { if (notifyMatch) { sendNotify = true; type = MonitorNotification.STRING_TO_COMPARE_VALUE_MATCHED; timeStamp = derivedGaugeTimestamp[index]; msg = ""; derGauge = derivedGauge[index]; trigger = stringToCompare; } status[index] = DIFFERING; } } else if (status[index] == DIFFERING) { if (!derivedGauge[index].equals(stringToCompare)) { if (notifyDiffer) { sendNotify = true; type = MonitorNotification.STRING_TO_COMPARE_VALUE_DIFFERED; timeStamp = derivedGaugeTimestamp[index]; msg = ""; derGauge = derivedGauge[index]; trigger = stringToCompare; } status[index] = MATCHING; } } } } if (sendNotify) { sendNotification(type, timeStamp, msg, derGauge, trigger, index); } } /* * ------------------------------------------ * PACKAGE METHODS * ------------------------------------------ */ /** * This method is called by the string monitor each time * the granularity period has been exceeded. * @param index The index of the observed object. */ void notifyAlarmClock(int index) { boolean sendNotify = false; String type = null; long timeStamp = 0; String msg = null; Object derGauge = null; Object trigger = null; Object scan_string = null; String notif_type = null; synchronized(this) { if (!isActive) return; // Check if the observed object and observed attribute are valid. // // Check that neither the observed object nor the observed // attribute are null. If the observed object or observed // attribute is null, this means that the monitor started // before a complete initialization and nothing is done. // if ((getObservedObject(index) == null) || (getObservedAttribute() == null)) return; // Check that the observed object is registered in the // MBean server and that the observed attribute belongs to // the observed object. // try { scan_string = server.getAttribute(getObservedObject(index), getObservedAttribute()); if (scan_string == null) return; } catch (NullPointerException np_ex) { if (alreadyNotified(index, RUNTIME_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.RUNTIME_ERROR; setAlreadyNotified(index, RUNTIME_ERROR_NOTIFIED); msg = "The string monitor must be registered in " + "the MBean server."; } } catch (InstanceNotFoundException inf_ex) { if (alreadyNotified(index, OBSERVED_OBJECT_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.OBSERVED_OBJECT_ERROR; setAlreadyNotified(index, OBSERVED_OBJECT_ERROR_NOTIFIED); msg = "The observed object must be registered in " + "the MBean server."; } } catch (AttributeNotFoundException anf_ex) { if (alreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.OBSERVED_ATTRIBUTE_ERROR; setAlreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED); msg = "The observed attribute must be accessible in " + "the observed object."; } } catch (MBeanException mb_ex) { if (alreadyNotified(index, RUNTIME_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.RUNTIME_ERROR; setAlreadyNotified(index, RUNTIME_ERROR_NOTIFIED); msg = mb_ex.getMessage(); } } catch (ReflectionException ref_ex) { if (alreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.OBSERVED_ATTRIBUTE_ERROR; setAlreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED); msg = ref_ex.getMessage(); } } if (msg == null) { // Check that the observed attribute is of type "String". // if (!(scan_string instanceof String)) { if (alreadyNotified(index, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR; setAlreadyNotified(index, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED); msg = "The observed attribute type must be " + "a string type."; } } } if (msg == null) { // Clear all already notified flags. // resetAllAlreadyNotified(index); // Update the derived gauge attributes. // updateDerivedGauge(scan_string, index); // Notify the listeners. // updateNotifications(index); } else { // msg != null, will send the monitor error notification. timeStamp = derivedGaugeTimestamp[index]; derGauge = derivedGauge[index]; // Reset values. // status[index] = MATCHING_OR_DIFFERING; } } if (msg != null) { sendNotification(type, timeStamp, msg, derGauge, null, index); } } /** * This method is called when adding a new observed object in the vector. * It updates all the string specific arrays. * @param index The index of the observed object. */ synchronized void insertSpecificElementAt(int index) { // Update derivedGauge, derivedGaugeTimestamp, and status arrays. // if (index != elementCount) throw new Error("Internal error: index != elementCount"); if (elementCount >= derivedGauge.length) { derivedGauge = expandArray(derivedGauge); derivedGaugeTimestamp = expandArray(derivedGaugeTimestamp); status = expandArray(status); } derivedGauge[index] = ""; derivedGaugeTimestamp[index] = System.currentTimeMillis(); status[index] = MATCHING_OR_DIFFERING; } /** * This method is called when removing an observed object from the vector. * It updates all the string specific arrays. * @param index The index of the observed object. */ synchronized void removeSpecificElementAt(int index) { if (index < 0 || index >= elementCount) return; // Update derivedGauge, derivedGaugeTimestamp, and status arrays. // removeElementAt(derivedGauge, index); removeElementAt(derivedGaugeTimestamp, index); removeElementAt(status, index); } /** * StringAlarmClock inner class: * This class provides a simple implementation of an alarm clock MBean. * The aim of this MBean is to set up an alarm which wakes up the * string monitor every granularity period. */ private static class StringAlarmClock extends TimerTask { StringMonitor listener = null; /* * ------------------------------------------ * CONSTRUCTORS * ------------------------------------------ */ public StringAlarmClock(StringMonitor listener) { this.listener = listener; } /* * ------------------------------------------ * PUBLIC METHODS * ------------------------------------------ */ /** * This method is called by the StringAlarmClock thread when * it is started. */ public void run() { if (listener.isActive) { for (int i = 0; i < listener.elementCount; i++) { listener.notifyAlarmClock(i); } } } } }