/*
* @(#)MBeanServerNotificationFilter.java 1.37 05/12/01
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package javax.management.relation;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.management.Notification;
import javax.management.NotificationFilterSupport;
import javax.management.MBeanServerNotification;
import javax.management.ObjectName;
import java.util.List;
import java.util.Vector;
import com.sun.jmx.mbeanserver.GetPropertyAction;
import com.sun.jmx.trace.Trace;
/**
* Filter for {@link MBeanServerNotification}.
* This filter filters MBeanServerNotification notifications by
* selecting the ObjectNames of interest and the operations (registration,
* unregistration, both) of interest (corresponding to notification
* types).
*
* <p>The <b>serialVersionUID</b> of this class is <code>2605900539589789736L</code>.
*
* @since 1.5
*/
public class MBeanServerNotificationFilter extends NotificationFilterSupport {
// Serialization compatibility stuff:
// Two serial forms are supported in this class. The selected form depends
// on system property "jmx.serial.form":
// - "1.0" for JMX 1.0
// - any other value for JMX 1.1 and higher
//
// Serial version for old serial form
private static final long oldSerialVersionUID = 6001782699077323605L;
//
// Serial version for new serial form
private static final long newSerialVersionUID = 2605900539589789736L;
//
// Serializable fields in old serial form
private static final ObjectStreamField[] oldSerialPersistentFields =
{
new ObjectStreamField("mySelectObjNameList", Vector.class),
new ObjectStreamField("myDeselectObjNameList", Vector.class)
};
//
// Serializable fields in new serial form
private static final ObjectStreamField[] newSerialPersistentFields =
{
new ObjectStreamField("selectedNames", List.class),
new ObjectStreamField("deselectedNames", List.class)
};
//
// Actual serial version and serial form
private static final long serialVersionUID;
/**
* @serialField selectedNames List List of {@link ObjectName}s of interest
* <ul>
* <li><code>null</code> means that all {@link ObjectName}s are implicitly selected
* (check for explicit deselections)</li>
* <li>Empty vector means that no {@link ObjectName} is explicitly selected</li>
* </ul>
* @serialField deselectedNames List List of {@link ObjectName}s with no interest
* <ul>
* <li><code>null</code> means that all {@link ObjectName}s are implicitly deselected
* (check for explicit selections))</li>
* <li>Empty vector means that no {@link ObjectName} is explicitly deselected</li>
* </ul>
*/
private static final ObjectStreamField[] serialPersistentFields;
private static boolean compat = false;
static {
try {
GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
String form = AccessController.doPrivileged(act);
compat = (form != null && form.equals("1.0"));
} catch (Exception e) {
// OK : Too bad, no compat with 1.0
}
if (compat) {
serialPersistentFields = oldSerialPersistentFields;
serialVersionUID = oldSerialVersionUID;
} else {
serialPersistentFields = newSerialPersistentFields;
serialVersionUID = newSerialVersionUID;
}
}
//
// END Serialization compatibility stuff
//
// Private members
//
/**
* @serial List of {@link ObjectName}s of interest
* <ul>
* <li><code>null</code> means that all {@link ObjectName}s are implicitly selected
* (check for explicit deselections)</li>
* <li>Empty vector means that no {@link ObjectName} is explicitly selected</li>
* </ul>
*/
private List<ObjectName> selectedNames = new Vector<ObjectName>();
/**
* @serial List of {@link ObjectName}s with no interest
* <ul>
* <li><code>null</code> means that all {@link ObjectName}s are implicitly deselected
* (check for explicit selections))</li>
* <li>Empty vector means that no {@link ObjectName} is explicitly deselected</li>
* </ul>
*/
private List<ObjectName> deselectedNames = null;
//
// Constructor
//
/**
* Creates a filter selecting all MBeanServerNotification notifications for
* all ObjectNames.
*/
public MBeanServerNotificationFilter() {
super();
if (isTraceOn())
trace("Constructor: entering", null);
enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION);
enableType(MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
if (isTraceOn())
trace("Constructor: exiting", null);
return;
}
//
// Accessors
//
/**
* Disables any MBeanServerNotification (all ObjectNames are
* deselected).
*/
public synchronized void disableAllObjectNames() {
if (isTraceOn())
trace("disableAllObjectNames: entering", null);
selectedNames = new Vector<ObjectName>();
deselectedNames = null;
if (isTraceOn())
trace("disableAllObjectNames: exiting", null);
return;
}
/**
* Disables MBeanServerNotifications concerning given ObjectName.
*
* @param objectName ObjectName no longer of interest
*
* @exception IllegalArgumentException if the given ObjectName is null
*/
public synchronized void disableObjectName(ObjectName objectName)
throws IllegalArgumentException {
if (objectName == null) {
String excMsg = "Invalid parameter.";
throw new IllegalArgumentException(excMsg);
}
if (isTraceOn())
trace("disableObjectName: entering", objectName.toString());
// Removes from selected ObjectNames, if present
if (selectedNames != null) {
if (selectedNames.size() != 0) {
selectedNames.remove(objectName);
}
}
// Adds it in deselected ObjectNames
if (deselectedNames != null) {
// If all are deselected, no need to do anything :)
if (!(deselectedNames.contains(objectName))) {
// ObjectName was not already deselected
deselectedNames.add(objectName);
}
}
if (isTraceOn())
trace("disableObjectName: exiting", null);
return;
}
/**
* Enables all MBeanServerNotifications (all ObjectNames are selected).
*/
public synchronized void enableAllObjectNames() {
if (isTraceOn())
trace("enableAllObjectNames: entering", null);
selectedNames = null;
deselectedNames = new Vector<ObjectName>();
if (isTraceOn())
trace("enableAllObjectNames: exiting", null);
return;
}
/**
* Enables MBeanServerNotifications concerning given ObjectName.
*
* @param objectName ObjectName of interest
*
* @exception IllegalArgumentException if the given ObjectName is null
*/
public synchronized void enableObjectName(ObjectName objectName)
throws IllegalArgumentException {
if (objectName == null) {
String excMsg = "Invalid parameter.";
throw new IllegalArgumentException(excMsg);
}
if (isTraceOn())
trace("enableObjectName: entering", objectName.toString());
// Removes from deselected ObjectNames, if present
if (deselectedNames != null) {
if (deselectedNames.size() != 0) {
deselectedNames.remove(objectName);
}
}
// Adds it in selected ObjectNames
if (selectedNames != null) {
// If all are selected, no need to do anything :)
if (!(selectedNames.contains(objectName))) {
// ObjectName was not already selected
selectedNames.add(objectName);
}
}
if (isTraceOn())
trace("enableObjectName: exiting", null);
return;
}
/**
* Gets all the ObjectNames enabled.
*
* @return Vector of ObjectNames:
* <P>- null means all ObjectNames are implicitly selected, except the
* ObjectNames explicitly deselected
* <P>- empty means all ObjectNames are deselected, i.e. no ObjectName
* selected.
*/
public synchronized Vector<ObjectName> getEnabledObjectNames() {
if (selectedNames != null) {
return new Vector<ObjectName>(selectedNames);
} else {
return null;
}
}
/**
* Gets all the ObjectNames disabled.
*
* @return Vector of ObjectNames:
* <P>- null means all ObjectNames are implicitly deselected, except the
* ObjectNames explicitly selected
* <P>- empty means all ObjectNames are selected, i.e. no ObjectName
* deselected.
*/
public synchronized Vector<ObjectName> getDisabledObjectNames() {
if (deselectedNames != null) {
return new Vector<ObjectName>(deselectedNames);
} else {
return null;
}
}
//
// NotificationFilter interface
//
/**
* Invoked before sending the specified notification to the listener.
* <P>If:
* <P>- the ObjectName of the concerned MBean is selected (explicitly OR
* (implicitly and not explicitly deselected))
* <P>AND
* <P>- the type of the operation (registration or unregistration) is
* selected
* <P>then the notification is sent to the listener.
*
* @param notif The notification to be sent.
*
* @return true if the notification has to be sent to the listener, false
* otherwise.
*
* @exception IllegalArgumentException if null parameter
*/
public synchronized boolean isNotificationEnabled(Notification notif)
throws IllegalArgumentException {
if (notif == null) {
String excMsg = "Invalid parameter.";
throw new IllegalArgumentException(excMsg);
}
if (isTraceOn())
trace("isNotificationEnabled: entering", notif.toString());
// Checks the type first
String ntfType = notif.getType();
Vector enabledTypes = getEnabledTypes();
if (!(enabledTypes.contains(ntfType))) {
if (isTraceOn())
trace("isNotificationEnabled: type not selected, exiting", null);
return false;
}
// We have a MBeanServerNotification: downcasts it
MBeanServerNotification mbsNtf = (MBeanServerNotification)notif;
// Checks the ObjectName
ObjectName objName = mbsNtf.getMBeanName();
// Is it selected?
boolean isSelectedFlg = false;
if (selectedNames != null) {
// Not all are implicitly selected:
// checks for explicit selection
if (selectedNames.size() == 0) {
// All are explicitly not selected
if (isTraceOn())
trace("isNotificationEnabled: no ObjectNames selected, exiting", null);
return false;
}
isSelectedFlg = selectedNames.contains(objName);
if (!isSelectedFlg) {
// Not in the explicit selected list
if (isTraceOn())
trace("isNotificationEnabled: ObjectName not in selected list, exiting", null);
return false;
}
}
if (!isSelectedFlg) {
// Not explicitly selected: is it deselected?
if (deselectedNames == null) {
// All are implicitly deselected and it is not explicitly
// selected
if (isTraceOn())
trace("isNotificationEnabled: ObjectName not selected and all deselectedm, exiting", null);
return false;
} else if (deselectedNames.contains(objName)) {
// Explicitly deselected
if (isTraceOn())
trace("isNotificationEnabled: ObjectName explicitly not selected, exiting", null);
return false;
}
}
if (isTraceOn())
trace("isNotificationEnabled: ObjectName selected, exiting", null);
return true;
}
// stuff for Tracing
private static String localClassName = "MBeanServerNotificationFilter";
// trace level
private boolean isTraceOn() {
return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_RELATION);
}
// private void trace(String className, String methodName, String info) {
// Trace.send(Trace.LEVEL_TRACE, Trace.INFO_RELATION, className, methodName, info);
// }
private void trace(String methodName, String info) {
Trace.send(Trace.LEVEL_TRACE, Trace.INFO_RELATION, localClassName, methodName, info);
Trace.send(Trace.LEVEL_TRACE, Trace.INFO_RELATION, "", "", "\n");
}
// private void trace(String className, String methodName, Exception e) {
// Trace.send(Trace.LEVEL_TRACE, Trace.INFO_RELATION, className, methodName, e);
// }
// private void trace(String methodName, Exception e) {
// Trace.send(Trace.LEVEL_TRACE, Trace.INFO_RELATION, localClassName, methodName, e);
// }
// debug level
private boolean isDebugOn() {
return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_RELATION);
}
// private void debug(String className, String methodName, String info) {
// Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_RELATION, className, methodName, info);
// }
private void debug(String methodName, String info) {
Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_RELATION, localClassName, methodName, info);
Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_RELATION, "", "", "\n");
}
// private void debug(String className, String methodName, Exception e) {
// Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_RELATION, className, methodName, e);
// }
// private void debug(String methodName, Exception e) {
// Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_RELATION, localClassName, methodName, e);
// }
/**
* Deserializes an {@link MBeanServerNotificationFilter} from an {@link ObjectInputStream}.
*/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
if (compat)
{
// Read an object serialized in the old serial form
//
ObjectInputStream.GetField fields = in.readFields();
selectedNames =
(List<ObjectName>) fields.get("mySelectObjNameList", null);
if (fields.defaulted("mySelectObjNameList"))
{
throw new NullPointerException("mySelectObjNameList");
}
deselectedNames =
(List<ObjectName>) fields.get("myDeselectObjNameList", null);
if (fields.defaulted("myDeselectObjNameList"))
{
throw new NullPointerException("myDeselectObjNameList");
}
}
else
{
// Read an object serialized in the new serial form
//
in.defaultReadObject();
}
}
/**
* Serializes an {@link MBeanServerNotificationFilter} to an {@link ObjectOutputStream}.
*/
private void writeObject(ObjectOutputStream out)
throws IOException {
if (compat)
{
// Serializes this instance in the old serial form
//
ObjectOutputStream.PutField fields = out.putFields();
fields.put("mySelectObjNameList", (Vector)selectedNames);
fields.put("myDeselectObjNameList", (Vector)deselectedNames);
out.writeFields();
}
else
{
// Serializes this instance in the new serial form
//
out.defaultWriteObject();
}
}
}