/*
* @(#)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.
* <P>
* A string monitor sends notifications as follows:
* <UL>
* <LI> if the attribute value matches the string to compare value,
* a {@link MonitorNotification#STRING_TO_COMPARE_VALUE_MATCHED
* match notification} is sent.
* The notify match flag must be set to <CODE>true</CODE>.
* <BR>Subsequent matchings of the string to compare values do not
* cause further notifications unless
* the attribute value differs from the string to compare value.
* <LI> if the attribute value differs from the string to compare value,
* a {@link MonitorNotification#STRING_TO_COMPARE_VALUE_DIFFERED
* differ notification} is sent.
* The notify differ flag must be set to <CODE>true</CODE>.
* <BR>Subsequent differences from the string to compare value do
* not cause further notifications unless
* the attribute value matches the string to compare value.
* </UL>
*
* @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.
* <BR>The default value is an empty character sequence.
*/
private String stringToCompare = "";
/**
* Flag indicating if the string monitor notifies when matching
* the string to compare.
* <BR>The default value is set to <CODE>false</CODE>.
*/
private boolean notifyMatch = false;
/**
* Flag indicating if the string monitor notifies when differing
* from the string to compare.
* <BR>The default value is set to <CODE>false</CODE>.
*/
private boolean notifyDiffer = false;
/**
* Derived gauges.
* <BR>Each element in this array corresponds to an observed object
* in the list.
*/
private String derivedGauge[] = new String[capacityIncrement];
/**
* Derived gauge timestamps.
* <BR>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.
* <BR>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).
* <BR>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 <code>null</code> 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
* <code>null</code> 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 <CODE>true</CODE> if the string monitor notifies when
* matching the string to compare, <CODE>false</CODE> 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 <CODE>true</CODE> if the string monitor notifies when
* differing from the string to compare, <CODE>false</CODE> 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 <CODE>NotificationInfo</CODE> 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 <CODE>true</CODE>.
* @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);
}
}
}
}
}
|