diff -r 4ebc2e2fb97c -r 71c04702a3d5 src/java.management/share/classes/javax/management/relation/MBeanServerNotificationFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.management/share/classes/javax/management/relation/MBeanServerNotificationFilter.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2000, 2017, 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.relation; + +import static com.sun.jmx.mbeanserver.Util.cast; +import static com.sun.jmx.defaults.JmxProperties.RELATION_LOGGER; +import com.sun.jmx.mbeanserver.GetPropertyAction; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.security.AccessController; + +import java.util.List; +import java.util.Vector; + +import javax.management.MBeanServerNotification; + +import javax.management.Notification; +import javax.management.NotificationFilterSupport; +import javax.management.ObjectName; + +import java.util.List; +import java.lang.System.Logger.Level; +import java.util.Vector; + +/** + * 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). + * + *

The serialVersionUID of this class is 2605900539589789736L. + * + * @since 1.5 + */ +@SuppressWarnings("serial") // serialVersionUID must be constant +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 { + 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 + * + */ + 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(); + RELATION_LOGGER.log(Level.TRACE, "ENTRY"); + + enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION); + enableType(MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + + RELATION_LOGGER.log(Level.TRACE, "RETURN"); + return; + } + + // + // Accessors + // + + /** + * Disables any MBeanServerNotification (all ObjectNames are + * deselected). + */ + public synchronized void disableAllObjectNames() { + + RELATION_LOGGER.log(Level.TRACE, "ENTRY"); + + selectedNames = new Vector(); + deselectedNames = null; + + RELATION_LOGGER.log(Level.TRACE, "RETURN"); + 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); + } + + RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}" + objectName); + + // 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); + } + } + + RELATION_LOGGER.log(Level.TRACE, "RETURN"); + return; + } + + /** + * Enables all MBeanServerNotifications (all ObjectNames are selected). + */ + public synchronized void enableAllObjectNames() { + + RELATION_LOGGER.log(Level.TRACE, "ENTRY"); + + selectedNames = null; + deselectedNames = new Vector(); + + RELATION_LOGGER.log(Level.TRACE, "RETURN"); + 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); + } + + RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", objectName); + + // 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); + } + } + + RELATION_LOGGER.log(Level.TRACE, "RETURN"); + 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 new Vector(selectedNames); + } 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 new Vector(deselectedNames); + } 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 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); + } + + RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", notif); + + // Checks the type first + String ntfType = notif.getType(); + Vector enabledTypes = getEnabledTypes(); + if (!(enabledTypes.contains(ntfType))) { + RELATION_LOGGER.log(Level.TRACE, + "Type not selected, exiting"); + 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 + RELATION_LOGGER.log(Level.TRACE, + "No ObjectNames selected, exiting"); + return false; + } + + isSelectedFlg = selectedNames.contains(objName); + if (!isSelectedFlg) { + // Not in the explicit selected list + RELATION_LOGGER.log(Level.TRACE, + "ObjectName not in selected list, exiting"); + return false; + } + } + + if (!isSelectedFlg) { + // Not explicitly selected: is it deselected? + + if (deselectedNames == null) { + // All are implicitly deselected and it is not explicitly + // selected + RELATION_LOGGER.log(Level.TRACE, + "ObjectName not selected, and all " + + "names deselected, exiting"); + return false; + + } else if (deselectedNames.contains(objName)) { + // Explicitly deselected + RELATION_LOGGER.log(Level.TRACE, + "ObjectName explicitly not selected, exiting"); + return false; + } + } + + RELATION_LOGGER.log(Level.TRACE, + "ObjectName selected, exiting"); + return true; + } + + + /** + * 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 = cast(fields.get("mySelectObjNameList", null)); + if (fields.defaulted("mySelectObjNameList")) + { + throw new NullPointerException("mySelectObjNameList"); + } + deselectedNames = cast(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", selectedNames); + fields.put("myDeselectObjNameList", deselectedNames); + out.writeFields(); + } + else + { + // Serializes this instance in the new serial form + // + out.defaultWriteObject(); + } + } +}