/* * @(#)MBeanServerNotificationFilter.java 1.33 04/02/10 * * Copyright 2004 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). * * @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 * * @serialField deselectedNames List List of {@link ObjectName}s with no interest * */ private static final ObjectStreamField[] serialPersistentFields; private static boolean compat = false; static { try { PrivilegedAction act = new GetPropertyAction("jmx.serial.form"); String form = (String) 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 * */ private List selectedNames = new Vector(); /** * @serial List of {@link ObjectName}s with no interest * */ private List 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(); deselectedNames = null; if (isTraceOn()) trace("disableAllObjectNames: exiting", null); return; } /** * Disables MBeanServerNotifications concerning given ObjectName. * * @param theObjName ObjectName no longer of interest * * @exception IllegalArgumentException if the given ObjectName is null */ public synchronized void disableObjectName(ObjectName theObjName) throws IllegalArgumentException { if (theObjName == null) { // Revisit [cebro] Localize message String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } if (isTraceOn()) trace("disableObjectName: entering", theObjName.toString()); // Removes from selected ObjectNames, if present if (selectedNames != null) { if (selectedNames.size() != 0) { selectedNames.remove(theObjName); } } // Adds it in deselected ObjectNames if (deselectedNames != null) { // If all are deselected, no need to do anything :) if (!(deselectedNames.contains(theObjName))) { // ObjectName was not already deselected deselectedNames.add(theObjName); } } 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(); if (isTraceOn()) trace("enableAllObjectNames: exiting", null); return; } /** * Enables MBeanServerNotifications concerning given ObjectName. * * @param theObjName ObjectName of interest * * @exception IllegalArgumentException if the given ObjectName is null */ public synchronized void enableObjectName(ObjectName theObjName) throws IllegalArgumentException { if (theObjName == null) { // Revisit [cebro] Localize message String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } if (isTraceOn()) trace("enableObjectName: entering", theObjName.toString()); // Removes from deselected ObjectNames, if present if (deselectedNames != null) { if (deselectedNames.size() != 0) { deselectedNames.remove(theObjName); } } // Adds it in selected ObjectNames if (selectedNames != null) { // If all are selected, no need to do anything :) if (!(selectedNames.contains(theObjName))) { // ObjectName was not already selected selectedNames.add(theObjName); } } if (isTraceOn()) trace("enableObjectName: exiting", null); return; } /** * Gets all the ObjectNames enabled. * * @return Vector of ObjectNames: *

- null means all ObjectNames are implicitly selected, except the * ObjectNames explicitly deselected *

- empty means all ObjectNames are deselected, i.e. no ObjectName * selected. */ public synchronized Vector getEnabledObjectNames() { if (selectedNames != null) { return (Vector)((Vector)selectedNames).clone(); } else { return null; } } /** * Gets all the ObjectNames disabled. * * @return Vector of ObjectNames: *

- null means all ObjectNames are implicitly deselected, except the * ObjectNames explicitly selected *

- empty means all ObjectNames are selected, i.e. no ObjectName * deselected. */ public synchronized Vector getDisabledObjectNames() { if (deselectedNames != null) { return (Vector)((Vector)deselectedNames).clone(); } else { return null; } } // // NotificationFilter interface // /** * Invoked before sending the specified notification to the listener. *

If: *

- the ObjectName of the concerned MBean is selected (explicitly OR * (implicitly and not explicitly deselected)) *

AND *

- the type of the operation (registration or unregistration) is * selected *

then the notification is sent to the listener. * * @param theNtf 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 theNtf) throws IllegalArgumentException { if (theNtf == null) { // Revisit [cebro] Localize message String excMsg = "Invalid parameter."; throw new IllegalArgumentException(excMsg); } if (isTraceOn()) trace("isNotificationEnabled: entering", theNtf.toString()); // Checks the type first String ntfType = theNtf.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)theNtf; // 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) fields.get("mySelectObjNameList", null); if (fields.defaulted("mySelectObjNameList")) { throw new NullPointerException("mySelectObjNameList"); } deselectedNames = (List) 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(); } } }