# HG changeset patch
# User dfuchs
# Date 1220532396 -7200
# Node ID bbc2d15aaf7a52ca177bf9b4ad22aabdb273e5e0
# Parent a9a142fcf1b517ab27fe07ff4a7da7937650bde8
5072476: RFE: support cascaded (federated) MBean Servers
6299231: Add support for named MBean Servers
Summary: New javax.management.namespace package.
Reviewed-by: emcmanus
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/make/docs/CORE_PKGS.gmk
--- a/jdk/make/docs/CORE_PKGS.gmk Wed Sep 03 14:31:17 2008 +0200
+++ b/jdk/make/docs/CORE_PKGS.gmk Thu Sep 04 14:46:36 2008 +0200
@@ -158,6 +158,7 @@
javax.management.event \
javax.management.loading \
javax.management.monitor \
+ javax.management.namespace \
javax.management.relation \
javax.management.openmbean \
javax.management.timer \
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java
--- a/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java Wed Sep 03 14:31:17 2008 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java Thu Sep 04 14:46:36 2008 +0200
@@ -177,6 +177,18 @@
"javax.management.relation";
/**
+ * Logger name for Namespaces.
+ */
+ public static final String NAMESPACE_LOGGER_NAME =
+ "javax.management.namespace";
+
+ /**
+ * Logger name for Namespaces.
+ */
+ public static final Logger NAMESPACE_LOGGER =
+ Logger.getLogger(NAMESPACE_LOGGER_NAME);
+
+ /**
* Logger for Relation Service.
*/
public static final Logger RELATION_LOGGER =
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Wed Sep 03 14:31:17 2008 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Thu Sep 04 14:46:36 2008 +0200
@@ -25,33 +25,49 @@
package com.sun.jmx.interceptor;
-// java import
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.WeakHashMap;
+
+// JMX RI
+import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
+import com.sun.jmx.mbeanserver.DynamicMBean2;
+import com.sun.jmx.mbeanserver.Introspector;
+import com.sun.jmx.mbeanserver.MBeanInjector;
+import com.sun.jmx.mbeanserver.MBeanInstantiator;
+import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
+import com.sun.jmx.mbeanserver.NamedObject;
+import com.sun.jmx.mbeanserver.NotifySupport;
+import com.sun.jmx.mbeanserver.Repository;
+import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
+import com.sun.jmx.mbeanserver.Util;
+import com.sun.jmx.remote.util.EnvHelp;
+
import java.lang.ref.WeakReference;
import java.security.AccessControlContext;
+import java.security.AccessController;
import java.security.Permission;
+import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
// JMX import
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
+import javax.management.DynamicWrapperMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMRuntimeException;
import javax.management.ListenerNotFoundException;
-import javax.management.MalformedObjectNameException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanPermission;
@@ -64,6 +80,7 @@
import javax.management.NotCompliantMBeanException;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
+import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
@@ -75,22 +92,7 @@
import javax.management.RuntimeErrorException;
import javax.management.RuntimeMBeanException;
import javax.management.RuntimeOperationsException;
-
-// JMX RI
-import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
-import com.sun.jmx.mbeanserver.DynamicMBean2;
-import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
-import com.sun.jmx.mbeanserver.MBeanInstantiator;
-import com.sun.jmx.mbeanserver.Repository;
-import com.sun.jmx.mbeanserver.NamedObject;
-import com.sun.jmx.mbeanserver.Introspector;
-import com.sun.jmx.mbeanserver.MBeanInjector;
-import com.sun.jmx.mbeanserver.NotifySupport;
-import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
-import com.sun.jmx.mbeanserver.Util;
-import com.sun.jmx.remote.util.EnvHelp;
-import javax.management.DynamicWrapperMBean;
-import javax.management.NotificationBroadcasterSupport;
+import javax.management.namespace.JMXNamespace;
/**
* This is the default class for MBean manipulation on the agent side. It
@@ -113,7 +115,8 @@
*
* @since 1.5
*/
-public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
+public class DefaultMBeanServerInterceptor
+ extends MBeanServerInterceptorSupport {
/** The MBeanInstantiator object used by the
* DefaultMBeanServerInterceptor */
@@ -123,7 +126,7 @@
* DefaultMBeanServerInterceptor */
private transient MBeanServer server = null;
- /** The MBean server object taht associated to the
+ /** The MBean server delegate object that is associated to the
* DefaultMBeanServerInterceptor */
private final transient MBeanServerDelegate delegate;
@@ -138,13 +141,15 @@
new WeakHashMap
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ * Adds a listener to a registered MBean. A notification emitted by an MBean will be forwarded by the
- * MBeanServer to the listener. If the source of the notification
- * is a reference to an MBean object, the MBean server will replace it
- * by that MBean's ObjectName. Otherwise the source is unchanged.
- *
- * @param name The name of the MBean on which the listener should
- * be added.
- * @param listener The listener object which will handle the
- * notifications emitted by the registered MBean.
- * @param filter The filter object. If filter is null, no
- * filtering will be performed before handling notifications.
- * @param handback The context to be sent to the listener when a
- * notification is emitted.
- *
- * @exception InstanceNotFoundException The MBean name provided
- * does not match any of the registered MBeans.
- */
- public void addNotificationListener(ObjectName name,
- NotificationListener listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException;
-
-
- /**
- * Adds a listener to a registered MBean. A notification emitted by an MBean will be forwarded by the
- * MBeanServer to the listener. If the source of the notification
- * is a reference to an MBean object, the MBean server will
- * replace it by that MBean's ObjectName. Otherwise the source is
- * unchanged. The listener object that receives notifications is the one
- * that is registered with the given name at the time this method
- * is called. Even if it is subsequently unregistered, it will
- * continue to receive notifications. If the listener is registered more than once, perhaps with
- * different filters or callbacks, this method will remove all
- * those registrations.
- *
- * @param name The name of the MBean on which the listener should
- * be removed.
- * @param listener The object name of the listener to be removed.
- *
- * @exception InstanceNotFoundException The MBean name provided
- * does not match any of the registered MBeans.
- * @exception ListenerNotFoundException The listener is not
- * registered in the MBean.
+ * This method should never be called.
+ * Usually hrows UnsupportedOperationException.
*/
- public void removeNotificationListener(ObjectName name,
- ObjectName listener)
- throws InstanceNotFoundException, ListenerNotFoundException;
-
- /**
- * Removes a listener from a registered MBean. The MBean must have a listener that exactly matches the
- * given The Removes a listener from a registered MBean. If the listener is registered more than once, perhaps with
- * different filters or callbacks, this method will remove all
- * those registrations.
- *
- * @param name The name of the MBean on which the listener should
- * be removed.
- * @param listener The listener object which will handle the
- * notifications emitted by the registered MBean.
- *
- * @exception InstanceNotFoundException The MBean name provided
- * does not match any of the registered MBeans.
- * @exception ListenerNotFoundException The listener is not
- * registered in the MBean.
- */
- public void removeNotificationListener(ObjectName name,
- NotificationListener listener)
- throws InstanceNotFoundException, ListenerNotFoundException;
+ @Deprecated
+ public ObjectInputStream deserialize(String className,
+ ObjectName loaderName, byte[] data)
+ throws InstanceNotFoundException, OperationsException,
+ ReflectionException;
/**
- * Removes a listener from a registered MBean. The MBean must have a listener that exactly matches the
- * given The Return the {@link java.lang.ClassLoader} that was used for
- * loading the class of the named MBean.
- * @param mbeanName The ObjectName of the MBean.
- * @return The ClassLoader used for that MBean.
- * @exception InstanceNotFoundException if the named MBean is not found.
- */
- public ClassLoader getClassLoaderFor(ObjectName mbeanName)
- throws InstanceNotFoundException;
-
- /**
- * Return the named {@link java.lang.ClassLoader}.
- * @param loaderName The ObjectName of the ClassLoader.
- * @return The named ClassLoader.
- * @exception InstanceNotFoundException if the named ClassLoader is
- * not found.
- */
- public ClassLoader getClassLoader(ObjectName loaderName)
- throws InstanceNotFoundException;
+ public ClassLoaderRepository getClassLoaderRepository();
}
+
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.interceptor;
+
+import java.io.ObjectInputStream;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.ReflectionException;
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * An abstract class for MBeanServerInterceptorSupport.
+ * Some methods in MBeanServerInterceptor should never be called.
+ * This base class provides an implementation of these methods that simply
+ * throw an {@link UnsupportedOperationException}.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ * Base class for custom implementations of the {@link MBeanServer}
- * interface. The commonest use of this class is as the {@linkplain
- * JMXNamespace#getSourceServer() source server} for a {@link
- * JMXNamespace}, although this class can be used anywhere an {@code
- * MBeanServer} instance is required. Note that the usual ways to
- * obtain an {@code MBeanServer} instance are either to use {@link
- * java.lang.management.ManagementFactory#getPlatformMBeanServer()
- * ManagementFactory.getPlatformMBeanServer()} or to use the {@code
- * newMBeanServer} or {@code createMBeanServer} methods from {@link
- * javax.management.MBeanServerFactory MBeanServerFactory}. {@code
- * MBeanServerSupport} is for certain cases where those are not
- * appropriate. There are two main use cases for this class: special-purpose MBeanServer implementations,
- * and namespaces containing Virtual MBeans. The next
- * sections explain these use cases. In the simplest case, a subclass needs to implement only two methods: Subclasses can create such {@link DynamicMBean} MBeans on the fly - for
- * instance, using the class {@link javax.management.StandardMBean}, just for
- * the duration of an MBeanServer method call. In some cases
- * the general-purpose {@code MBeanServer} that you get from
- * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not
- * appropriate. You might need different security checks, or you might
- * want a mock {@code MBeanServer} suitable for use in tests, or you might
- * want a simplified and optimized {@code MBeanServer} for a special purpose. As an example of a special-purpose {@code MBeanServer}, the class {@link
- * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs
- * an {@code MBeanServer} instance every time it filters a notification,
- * with just one MBean that represents the notification. Although it could
- * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code
- * MBeanServer} will be quicker to create, use less memory, and have simpler
- * methods that execute faster. Here is an example of a special-purpose {@code MBeanServer}
- * implementation that contains exactly one MBean, which is specified at the
- * time of creation. Using this class, you could make an {@code MBeanServer} that contains
- * a {@link javax.management.timer.Timer Timer} MBean like this: When {@code getDynamicMBeanFor} always returns the same object for the
- * same name, as here, notifications work in the expected way: if the object
- * is a {@link NotificationEmitter} then listeners can be added using
- * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener,
- * NotificationFilter, Object) MBeanServer.addNotificationListener}. If
- * {@code getDynamicMBeanFor} does not always return the same object for the
- * same name, more work is needed to make notifications work, as described
- * below. Virtual MBeans are MBeans that do not exist as Java objects,
- * except transiently while they are being accessed. This is useful when
- * there might be very many of them, or when keeping track of their creation
- * and deletion might be expensive or hard. For example, you might have one
- * MBean per system process. With an ordinary {@code MBeanServer}, you would
- * have to list the system processes in order to create an MBean object for
- * each one, and you would have to track the arrival and departure of system
- * processes in order to create or delete the corresponding MBeans. With
- * Virtual MBeans, you only need the MBean for a given process at the exact
- * point where it is referenced with a call such as
- * {@link MBeanServer#getAttribute MBeanServer.getAttribute}. Here is an example of an {@code MBeanServer} implementation that has
- * one MBean for every system property. The system property {@code "java.home"}
- * is represented by the MBean called {@code
- * com.example:type=Property,name="java.home"}, with an attribute called
- * {@code Value} that is the value of the property. Because the {@code getDynamicMBeanFor} method
- * returns a different object every time it is called, the default handling
- * of notifications will not work, as explained below.
- * In this case it does not matter, because the object returned by {@code
- * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link
- * MBeanServer#addNotificationListener(ObjectName, NotificationListener,
- * NotificationFilter, Object) MBeanServer.addNotificationListener} will
- * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean
- * for property {@code "foo"} emitted a notification every time that property
- * changed, we would need to do it as shown below. (Because there is no API to
- * be informed when a property changes, this code assumes that some other code
- * calls the {@code propertyChanged} method every time a property changes.) MBean creation through {@code MBeanServer.createMBean} is disabled
- * by default. Subclasses which need to support MBean creation
- * through {@code createMBean} need to implement a single method {@link
- * #createMBean(String, ObjectName, ObjectName, Object[], String[],
- * boolean)}. Similarly MBean registration and unregistration through {@code
- * registerMBean} and {@code unregisterMBean} are disabled by default.
- * Subclasses which need to support MBean registration and
- * unregistration will need to implement {@link #registerMBean registerMBean}
- * and {@link #unregisterMBean unregisterMBean}. By default {@link MBeanServer#addNotificationListener(ObjectName,
- * NotificationListener, NotificationFilter, Object) addNotificationListener}
- * is accepted for an MBean {@code name} if {@link #getDynamicMBeanFor
- * getDynamicMBeanFor} The simplest way for a subclass that defines Virtual MBeans
- * to support notifications is to create a private {@link VirtualEventManager}
- * and override the method {@link
- * #getNotificationEmitterFor getNotificationEmitterFor} as follows: A notification {@code n} can then be sent from the Virtual MBean
- * called {@code name} by calling {@link VirtualEventManager#publish
- * vem.publish} Make a new {@code MBeanServerSupport} instance. Returns a dynamically created handle that makes it possible to
- * access the named MBean for the duration of a method call. An easy way to create such a {@link DynamicMBean} handle is, for
- * instance, to create a temporary MXBean instance and to wrap it in
- * an instance of
- * {@link javax.management.StandardMBean}.
- * This handle should remain valid for the duration of the call
- * but can then be discarded. Subclasses should implement this method to return
- * the names of all MBeans handled by this object instance. The object returned by getNames() should be safely {@linkplain
- * Set#iterator iterable} even in the presence of other threads that may
- * cause the set of names to change. Typically this means one of the
- * following: List names matching the given pattern.
- * The default implementation of this method calls {@link #getNames()}
- * and returns the subset of those names matching {@code pattern}. Returns a {@link NotificationEmitter} which can be used to
- * subscribe or unsubscribe for notifications with the named
- * mbean. The default implementation of this method calls {@link
- * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object
- * if it is a {@code NotificationEmitter}, otherwise null. See above for further discussion of notification
- * handling. Creates a new MBean in the MBean name space.
- * This operation is not supported in this base class implementation.ObjectInstance
, containing the
- * ObjectName
and the Java class name of the newly
- * instantiated MBean.
- *
- * @exception ReflectionException Wraps a
- * java.lang.ClassNotFoundException
or a
- * java.lang.Exception
that occurred when trying to
- * invoke the MBean's constructor.
- * @exception InstanceAlreadyExistsException The MBean is already
- * under the control of the MBean server.
- * @exception MBeanRegistrationException The
- * preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The
- * MBean will not be registered.
- * @exception MBeanException The constructor of the MBean has
- * thrown an exception
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The className
- * passed in parameter is null, the ObjectName
passed
- * in parameter contains a pattern or no ObjectName
- * is specified for the MBean.
+ * This method should never be called.
+ * Usually hrows UnsupportedOperationException.
*/
- public ObjectInstance createMBean(String className, ObjectName name,
- Object params[], String signature[])
- throws ReflectionException, InstanceAlreadyExistsException,
- MBeanRegistrationException, MBeanException,
- NotCompliantMBeanException;
-
+ public Object instantiate(String className)
+ throws ReflectionException, MBeanException;
/**
- * Instantiates and registers an MBean in the MBean server. The
- * class loader to be used is identified by its object name. An
- * object name is associated to the MBean. If the object name of
- * the loader is not specified, the ClassLoader that loaded the
- * MBean server will be used. If the MBean object name given is
- * null, the MBean must provide its own name by implementing the
- * {@link javax.management.MBeanRegistration MBeanRegistration}
- * interface and returning the name from the {@link
- * javax.management.MBeanRegistration#preRegister preRegister} method.
- *
- * @param className The class name of the MBean to be instantiated.
- * @param name The object name of the MBean. May be null.
- * @param params An array containing the parameters of the
- * constructor to be invoked.
- * @param signature An array containing the signature of the
- * constructor to be invoked.
- * @param loaderName The object name of the class loader to be used.
- *
- * @return An ObjectInstance
, containing the
- * ObjectName
and the Java class name of the newly
- * instantiated MBean.
- *
- * @exception ReflectionException Wraps a
- * java.lang.ClassNotFoundException
or a
- * java.lang.Exception
that occurred when trying to
- * invoke the MBean's constructor.
- * @exception InstanceAlreadyExistsException The MBean is already
- * under the control of the MBean server.
- * @exception MBeanRegistrationException The
- * preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The
- * MBean will not be registered.
- * @exception MBeanException The constructor of the MBean has
- * thrown an exception
- * @exception InstanceNotFoundException The specified class loader
- * is not registered in the MBean server.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The className
- * passed in parameter is null, the ObjectName
passed
- * in parameter contains a pattern or no ObjectName
- * is specified for the MBean.
- *
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public ObjectInstance createMBean(String className, ObjectName name,
- ObjectName loaderName, Object params[],
- String signature[])
- throws ReflectionException, InstanceAlreadyExistsException,
- MBeanRegistrationException, MBeanException,
- NotCompliantMBeanException, InstanceNotFoundException;
-
+ public Object instantiate(String className, ObjectName loaderName)
+ throws ReflectionException, MBeanException,
+ InstanceNotFoundException;
/**
- * Registers a pre-existing object as an MBean with the MBean
- * server. If the object name given is null, the MBean must
- * provide its own name by implementing the {@link
- * javax.management.MBeanRegistration MBeanRegistration} interface
- * and returning the name from the {@link
- * javax.management.MBeanRegistration#preRegister preRegister} method.
- *
- * @param object The MBean to be registered as an MBean.
- * @param name The object name of the MBean. May be null.
- *
- * @return The ObjectInstance
for the MBean that has
- * been registered.
- *
- * @exception InstanceAlreadyExistsException The MBean is already
- * under the control of the MBean server.
- * @exception MBeanRegistrationException The
- * preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The
- * MBean will not be registered.
- * @exception NotCompliantMBeanException This object is not a JMX
- * compliant MBean
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * passed in parameter is null or no object name is specified.
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public ObjectInstance registerMBean(Object object, ObjectName name)
- throws InstanceAlreadyExistsException, MBeanRegistrationException,
- NotCompliantMBeanException;
+ public Object instantiate(String className, Object[] params,
+ String[] signature) throws ReflectionException, MBeanException;
/**
- * Unregisters an MBean from the MBean server. The MBean is
- * identified by its object name. Once the method has been
- * invoked, the MBean may no longer be accessed by its object
- * name.
- *
- * @param name The object name of the MBean to be unregistered.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception MBeanRegistrationException The preDeregister
- * ((MBeanRegistration
interface) method of the MBean
- * has thrown an exception.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or the MBean you are when trying to
- * unregister is the {@link javax.management.MBeanServerDelegate
- * MBeanServerDelegate} MBean.
- *
- */
- public void unregisterMBean(ObjectName name)
- throws InstanceNotFoundException, MBeanRegistrationException;
-
- /**
- * Gets the ObjectInstance
for a given MBean
- * registered with the MBean server.
- *
- * @param name The object name of the MBean.
- *
- * @return The ObjectInstance
associated to the MBean
- * specified by name.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- */
- public ObjectInstance getObjectInstance(ObjectName name)
- throws InstanceNotFoundException;
-
- /**
- * Gets MBeans controlled by the MBean server. This method allows
- * any of the following to be obtained: All MBeans, a set of
- * MBeans specified by pattern matching on the
- * ObjectName
and/or a Query expression, a specific
- * MBean. When the object name is null or no domain and key
- * properties are specified, all objects are to be selected (and
- * filtered if a query is specified). It returns the set of
- * ObjectInstance
objects (containing the
- * ObjectName
and the Java Class name) for the
- * selected MBeans.
- *
- * @param name The object name pattern identifying the MBeans to
- * be retrieved. If null or no domain and key properties are
- * specified, all the MBeans registered will be retrieved.
- * @param query The query expression to be applied for selecting
- * MBeans. If null no query expression will be applied for
- * selecting MBeans.
- *
- * @return A set containing the ObjectInstance
- * objects for the selected MBeans. If no MBean satisfies the
- * query an empty list is returned.
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public SetObjectName
and/or a Query
- * expression, a specific MBean name (equivalent to testing
- * whether an MBean is registered). When the object name is null
- * or no domain and key properties are specified, all objects are
- * selected (and filtered if a query is specified). It returns the
- * set of ObjectNames for the MBeans selected.
- *
- * @param name The object name pattern identifying the MBean names
- * to be retrieved. If null oror no domain and key properties are
- * specified, the name of all registered MBeans will be retrieved.
- * @param query The query expression to be applied for selecting
- * MBeans. If null no query expression will be applied for
- * selecting MBeans.
- *
- * @return A set containing the ObjectNames for the MBeans
- * selected. If no MBean satisfies the query, an empty list is
- * returned.
- */
- public Setjava.lang.IllegalArgumentException
: The object
- * name in parameter is null.
- */
- public boolean isRegistered(ObjectName name);
-
- /**
- * Returns the number of MBeans registered in the MBean server.
- */
- public Integer getMBeanCount();
-
- /**
- * Gets the value of a specific attribute of a named MBean. The MBean
- * is identified by its object name.
- *
- * @param name The object name of the MBean from which the
- * attribute is to be retrieved.
- * @param attribute A String specifying the name of the attribute
- * to be retrieved.
- *
- * @return The value of the retrieved attribute.
- *
- * @exception AttributeNotFoundException The attribute specified
- * is not accessible in the MBean.
- * @exception MBeanException Wraps an exception thrown by the
- * MBean's getter.
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception ReflectionException Wraps a
- * java.lang.Exception
thrown when trying to invoke
- * the setter.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or the attribute in parameter is
- * null.
- */
- public Object getAttribute(ObjectName name, String attribute)
- throws MBeanException, AttributeNotFoundException,
- InstanceNotFoundException, ReflectionException;
-
- /**
- * Enables the values of several attributes of a named MBean. The MBean
- * is identified by its object name.
- *
- * @param name The object name of the MBean from which the
- * attributes are retrieved.
- * @param attributes A list of the attributes to be retrieved.
- *
- * @return The list of the retrieved attributes.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception ReflectionException An exception occurred when
- * trying to invoke the getAttributes method of a Dynamic MBean.
- * @exception RuntimeOperationsException Wrap a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or attributes in parameter is null.
- */
- public AttributeList getAttributes(ObjectName name, String[] attributes)
- throws InstanceNotFoundException, ReflectionException;
+ public Object instantiate(String className, ObjectName loaderName,
+ Object[] params, String[] signature)
+ throws ReflectionException, MBeanException,
+ InstanceNotFoundException;
/**
- * Sets the value of a specific attribute of a named MBean. The MBean
- * is identified by its object name.
- *
- * @param name The name of the MBean within which the attribute is
- * to be set.
- * @param attribute The identification of the attribute to be set
- * and the value it is to be set to.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception AttributeNotFoundException The attribute specified
- * is not accessible in the MBean.
- * @exception InvalidAttributeValueException The value specified
- * for the attribute is not valid.
- * @exception MBeanException Wraps an exception thrown by the
- * MBean's setter.
- * @exception ReflectionException Wraps a
- * java.lang.Exception
thrown when trying to invoke
- * the setter.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or the attribute in parameter is
- * null.
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public void setAttribute(ObjectName name, Attribute attribute)
- throws InstanceNotFoundException, AttributeNotFoundException,
- InvalidAttributeValueException, MBeanException,
- ReflectionException;
-
-
-
- /**
- * Sets the values of several attributes of a named MBean. The MBean is
- * identified by its object name.
- *
- * @param name The object name of the MBean within which the
- * attributes are to be set.
- * @param attributes A list of attributes: The identification of
- * the attributes to be set and the values they are to be set to.
- *
- * @return The list of attributes that were set, with their new
- * values.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception ReflectionException An exception occurred when
- * trying to invoke the getAttributes method of a Dynamic MBean.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or attributes in parameter is null.
- */
- public AttributeList setAttributes(ObjectName name,
- AttributeList attributes)
- throws InstanceNotFoundException, ReflectionException;
+ @Deprecated
+ public ObjectInputStream deserialize(ObjectName name, byte[] data)
+ throws InstanceNotFoundException, OperationsException;
/**
- * Invokes an operation on an MBean.
- *
- * @param name The object name of the MBean on which the method is
- * to be invoked.
- * @param operationName The name of the operation to be invoked.
- * @param params An array containing the parameters to be set when
- * the operation is invoked
- * @param signature An array containing the signature of the
- * operation. The class objects will be loaded using the same
- * class loader as the one used for loading the MBean on which the
- * operation was invoked.
- *
- * @return The object returned by the operation, which represents
- * the result ofinvoking the operation on the MBean specified.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception MBeanException Wraps an exception thrown by the
- * MBean's invoked method.
- * @exception ReflectionException Wraps a
- * java.lang.Exception
thrown while trying to invoke
- * the method.
- */
- public Object invoke(ObjectName name, String operationName,
- Object params[], String signature[])
- throws InstanceNotFoundException, MBeanException,
- ReflectionException;
-
- /**
- * Returns the default domain used for naming the MBean.
- * The default domain name is used as the domain part in the ObjectName
- * of MBeans if no domain is specified by the user.
- */
- public String getDefaultDomain();
-
- /**
- * Returns the list of domains in which any MBean is currently
- * registered.
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public String[] getDomains();
-
- /**
- * listener
exists but does not implement the {@link
- * NotificationListener} interface.
- * @exception IOException A communication problem occurred when
- * talking to the MBean server.
- */
- public void addNotificationListener(ObjectName name,
- ObjectName listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException;
+ @Deprecated
+ public ObjectInputStream deserialize(String className, byte[] data)
+ throws OperationsException, ReflectionException;
/**
- * Removes a listener from a registered MBean.
- *
- * listener
, filter
, and
- * handback
parameters. If there is more than one
- * such listener, only one is removed.filter
and handback
parameters
- * may be null if and only if they are null in a listener to be
- * removed.listener
, filter
, and
- * handback
parameters. If there is more than one
- * such listener, only one is removed.filter
and handback
parameters
- * may be null if and only if they are null in a listener to be
- * removed.MBeanInfo
allowing the
- * retrieval of all attributes and operations of this MBean.
- *
- * @exception IntrospectionException An exception occurred during
- * introspection.
- * @exception InstanceNotFoundException The MBean specified was
- * not found.
- * @exception ReflectionException An exception occurred when
- * trying to invoke the getMBeanInfo of a Dynamic MBean.
- */
- public MBeanInfo getMBeanInfo(ObjectName name)
- throws InstanceNotFoundException, IntrospectionException,
- ReflectionException;
-
-
- /**
- * Returns true if the MBean specified is an instance of the
- * specified class, false otherwise.
- *
- * @param name The ObjectName
of the MBean.
- * @param className The name of the class.
- *
- * @return true if the MBean specified is an instance of the
- * specified class, false otherwise.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- */
- public boolean isInstanceOf(ObjectName name, String className)
- throws InstanceNotFoundException;
-
- /**
- *
- *
- *
- * Special-purpose MBeanServer implementations
- *
- *
- * public class SingletonMBeanServer extends MBeanServerSupport {
- * private final ObjectName objectName;
- * private final DynamicMBean mbean;
- *
- * public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) {
- * this.objectName = objectName;
- * this.mbean = mbean;
- * }
- *
- * @Override
- * protected {@code Set
- *
- *
- * Timer timer = new Timer();
- * DynamicMBean mbean = new {@link javax.management.StandardMBean
- * StandardMBean}(timer, TimerMBean.class);
- * ObjectName name = new ObjectName("com.example:type=Timer");
- * MBeanServer timerMBS = new SingletonMBeanServer(name, mbean);
- *
- *
- * Namespaces containing Virtual MBeans
- *
- *
- * public interface PropertyMBean {
- * public String getValue();
- * }
- *
- * public class PropsMBS extends MBeanServerSupport {
- * private static ObjectName newObjectName(String name) {
- * try {
- * return new ObjectName(name);
- * } catch (MalformedObjectNameException e) {
- * throw new AssertionError(e);
- * }
- * }
- *
- * public static class PropertyImpl implements PropertyMBean {
- * private final String name;
- *
- * public PropertyImpl(String name) {
- * this.name = name;
- * }
- *
- * public String getValue() {
- * return System.getProperty(name);
- * }
- * }
- *
- * @Override
- * public DynamicMBean {@link #getDynamicMBeanFor
- * getDynamicMBeanFor}(ObjectName name)
- * throws InstanceNotFoundException {
- *
- * // Check that the name is a legal one for a Property MBean
- * ObjectName namePattern = newObjectName(
- * "com.example:type=Property,name=\"*\"");
- * if (!namePattern.apply(name))
- * throw new InstanceNotFoundException(name);
- *
- * // Extract the name of the property that the MBean corresponds to
- * String propName = ObjectName.unquote(name.getKeyProperty("name"));
- * if (System.getProperty(propName) == null)
- * throw new InstanceNotFoundException(name);
- *
- * // Construct and return a transient MBean object
- * PropertyMBean propMBean = new PropertyImpl(propName);
- * return new StandardMBean(propMBean, PropertyMBean.class, false);
- * }
- *
- * @Override
- * protected {@code Set
- *
- *
- * public class PropsMBS {
- * ...as above...
- *
- * private final {@link VirtualEventManager} vem = new VirtualEventManager();
- *
- * @Override
- * public NotificationEmitter {@link #getNotificationEmitterFor
- * getNotificationEmitterFor}(
- * ObjectName name) throws InstanceNotFoundException {
- * getDynamicMBeanFor(name); // check that the name is valid
- * return vem.{@link VirtualEventManager#getNotificationEmitterFor
- * getNotificationEmitterFor}(name);
- * }
- *
- * public void propertyChanged(String name, String newValue) {
- * ObjectName objectName = newObjectName(
- * "com.example:type=Property,name=" + ObjectName.quote(name));
- * Notification n = new Notification(
- * "com.example.property.changed", objectName, 0L,
- * "Property " + name + " changed");
- * n.setUserData(newValue);
- * vem.{@link VirtualEventManager#publish publish}(objectName, n);
- * }
- * }
- *
- *
- * MBean creation and deletion
- *
- * Notifications
- *
- * (name)
returns an object that is a
- * {@link NotificationEmitter}. That is appropriate if
- * {@code getDynamicMBeanFor}(name)
always returns the
- * same object for the same {@code name}. But with
- * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object,
- * which is discarded as soon as the MBean request has finished.
- * So a listener added to that object would be immediately forgotten.
- * private final VirtualEventManager vem = new VirtualEventManager();
- *
- * @Override
- * public NotificationEmitter getNotificationEmitterFor(
- * ObjectName name) throws InstanceNotFoundException {
- * // Check that the name is a valid Virtual MBean.
- * // This is the easiest way to do that, but not always the
- * // most efficient:
- * getDynamicMBeanFor(name);
- *
- * // Return an object that supports add/removeNotificationListener
- * // through the VirtualEventManager.
- * return vem.getNotificationEmitterFor(name);
- * }
- *
- *
- * (name, n)
. See the example
- * above.
- *
- *
- * @return the names of all MBeans handled by this object.
- */
- protected abstract Set
Subclasses may redefine this method to provide an implementation.
- * All the various flavors of {@code MBeanServer.createMBean} methods
- * will eventually call this method. A subclass that wishes to
- * support MBean creation through {@code createMBean} thus only
- * needs to provide an implementation for this one method.
- *
- * @param className The class name of the MBean to be instantiated.
- * @param name The object name of the MBean. May be null.
- * @param params An array containing the parameters of the
- * constructor to be invoked.
- * @param signature An array containing the signature of the
- * constructor to be invoked.
- * @param loaderName The object name of the class loader to be used.
- * @param useCLR This parameter is {@code true} when this method
- * is called from one of the {@code MBeanServer.createMBean} methods
- * whose signature does not include the {@code ObjectName} of an
- * MBean class loader to use for loading the MBean class.
- *
- * @return An ObjectInstance
, containing the
- * ObjectName
and the Java class name of the newly
- * instantiated MBean. If the contained ObjectName
- * is n
, the contained Java class name is
- * {@link javax.management.MBeanServer#getMBeanInfo
- * getMBeanInfo(n)}.getClassName()
.
- *
- * @exception ReflectionException Wraps a
- * java.lang.ClassNotFoundException
or a
- * java.lang.Exception
that occurred when trying to
- * invoke the MBean's constructor.
- * @exception InstanceAlreadyExistsException The MBean is already
- * under the control of the MBean server.
- * @exception MBeanRegistrationException The
- * preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The
- * MBean will not be registered.
- * @exception MBeanException The constructor of the MBean has
- * thrown an exception
- * @exception NotCompliantMBeanException This class is not a JMX
- * compliant MBean
- * @exception InstanceNotFoundException The specified class loader
- * is not registered in the MBean server.
- * @exception RuntimeOperationsException Wraps either:
- *
java.lang.IllegalArgumentException
: The className
- * passed in parameter is null, the ObjectName
passed in
- * parameter contains a pattern or no ObjectName
is specified
- * for the MBean; orAttempts to determine whether the named MBean should be - * considered as an instance of a given class. The default implementation - * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} - * to get an MBean object. Then its behaviour is the same as the standard - * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.
- * - * {@inheritDoc} - */ - public boolean isInstanceOf(ObjectName name, String className) - throws InstanceNotFoundException { - - final DynamicMBean instance = nonNullMBeanFor(name); - - try { - final String mbeanClassName = instance.getMBeanInfo().getClassName(); - - if (mbeanClassName.equals(className)) - return true; - - final Object resource; - final ClassLoader cl; - if (instance instanceof DynamicWrapperMBean) { - DynamicWrapperMBean d = (DynamicWrapperMBean) instance; - resource = d.getWrappedObject(); - cl = d.getWrappedClassLoader(); - } else { - resource = instance; - cl = instance.getClass().getClassLoader(); - } - - final Class> classNameClass = Class.forName(className, false, cl); - - if (classNameClass.isInstance(resource)) - return true; - - if (classNameClass == NotificationBroadcaster.class || - classNameClass == NotificationEmitter.class) { - try { - getNotificationEmitterFor(name); - return true; - } catch (Exception x) { - LOG.finest("MBean " + name + - " is not a notification emitter. Ignoring: "+x); - return false; - } - } - - final Class> resourceClass = Class.forName(mbeanClassName, false, cl); - return classNameClass.isAssignableFrom(resourceClass); - } catch (Exception x) { - /* Could be SecurityException or ClassNotFoundException */ - LOG.logp(Level.FINEST, - MBeanServerSupport.class.getName(), - "isInstanceOf", "Exception calling isInstanceOf", x); - return false; - } - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns the string - * "DefaultDomain".
- */ - public String getDefaultDomain() { - return "DefaultDomain"; - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns - * {@link #getNames()}.size().
- */ - public Integer getMBeanCount() { - return getNames().size(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method first calls {@link #getNames - * getNames()} to get a list of all MBean names, - * and from this set of names, derives the set of domains which contain - * MBeans.
- */ - public String[] getDomains() { - final SetThe default implementation of this method will first - * call {@link - * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle - * to the named MBean, - * and then call {@link DynamicMBean#getAttribute getAttribute} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public Object getAttribute(ObjectName name, String attribute) - throws MBeanException, AttributeNotFoundException, - InstanceNotFoundException, ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getAttribute(attribute); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} - * to obtain a handle to the named MBean, - * and then call {@link DynamicMBean#setAttribute setAttribute} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public void setAttribute(ObjectName name, Attribute attribute) - throws InstanceNotFoundException, AttributeNotFoundException, - InvalidAttributeValueException, MBeanException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - mbean.setAttribute(attribute); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#getAttributes getAttributes} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public AttributeList getAttributes(ObjectName name, - String[] attributes) throws InstanceNotFoundException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getAttributes(attributes); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#setAttributes setAttributes} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public AttributeList setAttributes(ObjectName name, AttributeList attributes) - throws InstanceNotFoundException, ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.setAttributes(attributes); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#invoke invoke} - * on that {@link DynamicMBean} handle.
- */ - public Object invoke(ObjectName name, String operationName, - Object[] params, String[] signature) - throws InstanceNotFoundException, MBeanException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.invoke(operationName, params, signature); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo} - * on that {@link DynamicMBean} handle.
- */ - public MBeanInfo getMBeanInfo(ObjectName name) - throws InstanceNotFoundException, IntrospectionException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getMBeanInfo(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will call - * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.{@link MBeanInfo#getClassName getClassName()} to get the - * class name to combine with {@code name} to produce a new - * {@code ObjectInstance}.
- */ - public ObjectInstance getObjectInstance(ObjectName name) - throws InstanceNotFoundException { - final DynamicMBean mbean = nonNullMBeanFor(name); - final String className = mbean.getMBeanInfo().getClassName(); - return new ObjectInstance(name, className); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first call {@link - * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the - * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code - * isRegistered} will return true. If {@code getDynamicMBeanFor} returns - * null or throws {@link InstanceNotFoundException}, {@code isRegistered} - * will return false.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public boolean isRegistered(ObjectName name) { - try { - final DynamicMBean mbean = getDynamicMBeanFor(name); - return mbean!=null; - } catch (InstanceNotFoundException x) { - if (LOG.isLoggable(Level.FINEST)) - LOG.finest("MBean "+name+" is not registered: "+x); - return false; - } - } - - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #queryNames queryNames} - * to get a list of all matching MBeans, and then, for each returned name, - * call {@link #getObjectInstance getObjectInstance(name)}.
- */ - public SetThe default implementation of this method calls {@link #getMatchingNames - * getMatchingNames(pattern)} to obtain a list of MBeans matching - * the given name pattern. If the {@code query} parameter is null, - * this will be the result. Otherwise, it will evaluate the - * {@code query} parameter for each of the returned names, exactly - * as an {@code MBeanServer} would. This might result in - * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called - * several times for each returned name.
- */ - public SetAdds a listener to a registered MBean. A notification emitted by - * the MBean will be forwarded to the listener.
- * - *This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code addNotificationListener} on the - * {@link NotificationEmitter} it returns. - * - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void addNotificationListener(ObjectName name, - NotificationListener listener, NotificationFilter filter, - Object handback) throws InstanceNotFoundException { - final NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.addNotificationListener(listener, filter, handback); - } - - /** - * {@inheritDoc} - * - *
This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code removeNotificationListener} on the - * {@link NotificationEmitter} it returns. - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener) - throws InstanceNotFoundException, ListenerNotFoundException { - final NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.removeNotificationListener(listener); - } - - /** - * {@inheritDoc} - * - *
This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code removeNotificationListener} on the - * {@link NotificationEmitter} it returns. - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener, NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.removeNotificationListener(listener); - } - - - /** - *
Adds a listener to a registered MBean.
- * - *The default implementation of this method first calls - * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}. - * If that successfully returns an object, call it {@code - * mbean}, then (a) if {@code mbean} is an instance of {@link - * NotificationListener} then this method calls {@link - * #addNotificationListener(ObjectName, NotificationListener, - * NotificationFilter, Object) addNotificationListener(name, mbean, filter, - * handback)}, otherwise (b) this method throws an exception as specified - * for this case.
- * - *This default implementation is not appropriate for Virtual MBeans, - * although that only matters if the object returned by {@code - * getDynamicMBeanFor} can be an instance of - * {@code NotificationListener}.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public void addNotificationListener(ObjectName name, ObjectName listenerName, - NotificationFilter filter, Object handback) - throws InstanceNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - addNotificationListener(name, listener, filter, handback); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void removeNotificationListener(ObjectName name, - ObjectName listenerName) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - removeNotificationListener(name, listener); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void removeNotificationListener(ObjectName name, - ObjectName listenerName, NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - removeNotificationListener(name, listener, filter, handback); - } - - private NotificationListener getListenerMBean(ObjectName listenerName) - throws InstanceNotFoundException { - Object mbean = getDynamicMBeanFor(listenerName); - if (mbean instanceof NotificationListener) - return (NotificationListener) mbean; - else { - throw newIllegalArgumentException( - "MBean is not a NotificationListener: " + listenerName); - } - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link InstanceNotFoundException} wrapping - * {@link UnsupportedOperationException}.
- * - * @return the default implementation of this method never returns. - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public ClassLoader getClassLoader(ObjectName loaderName) - throws InstanceNotFoundException { - final UnsupportedOperationException failed = - new UnsupportedOperationException("getClassLoader"); - final InstanceNotFoundException x = - new InstanceNotFoundException(String.valueOf(loaderName)); - x.initCause(failed); - throw x; - } - - /** - * {@inheritDoc} - * - *The default implementation of this method calls - * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies - * the logic just described to the result.
- */ - public ClassLoader getClassLoaderFor(ObjectName mbeanName) - throws InstanceNotFoundException { - final DynamicMBean mbean = nonNullMBeanFor(mbeanName); - if (mbean instanceof DynamicWrapperMBean) - return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); - else - return mbean.getClass().getClassLoader(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns a - * {@link ClassLoaderRepository} containing exactly one loader, - * the {@linkplain Thread#getContextClassLoader() context class loader} - * for the current thread. - * Subclasses can override this method to return a different - * {@code ClassLoaderRepository}.
- */ - public ClassLoaderRepository getClassLoaderRepository() { - // We return a new ClassLoaderRepository each time this - // method is called. This is by design, because the - // SingletonClassLoaderRepository is a very small object and - // getClassLoaderRepository() will not be called very often - // (the connector server calls it once) - in the context of - // MBeanServerSupport there's a very good chance that this method will - // *never* be called. - ClassLoader ccl = Thread.currentThread().getContextClassLoader(); - return Util.getSingleClassLoaderRepository(ccl); - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public ObjectInstance registerMBean(Object object, ObjectName name) - throws InstanceAlreadyExistsException, MBeanRegistrationException, - NotCompliantMBeanException { - throw newUnsupportedException("registerMBean"); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}. - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void unregisterMBean(ObjectName name) - throws InstanceNotFoundException, MBeanRegistrationException { - throw newUnsupportedException("unregisterMBean"); - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, null, params, signature, true)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - Object[] params, String[] signature) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException { - try { - return safeCreateMBean(className, name, null, params, signature, true); - } catch (InstanceNotFoundException ex) { - // should not happen! - throw new MBeanException(ex, "Unexpected exception: " + ex); - } - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className,name, loaderName, params, signature, false)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName, Object[] params, String[] signature) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - return safeCreateMBean(className, name, loaderName, params, signature, false); - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, null, null, null, true)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException { - try { - return safeCreateMBean(className, name, null, null, null, true); - } catch (InstanceNotFoundException ex) { - // should not happen! - throw new MBeanException(ex, "Unexpected exception: " + ex); - } - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, loaderName, null, null, false)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - return safeCreateMBean(className, name, loaderName, null, null, false); - } - - // make sure all exceptions are correctly wrapped in a JMXException - private ObjectInstance safeCreateMBean(String className, - ObjectName name, ObjectName loaderName, Object[] params, - String[] signature, boolean useRepository) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - try { - return createMBean(className, name, loaderName, params, - signature, useRepository); - } catch (ReflectionException x) { throw x; - } catch (InstanceAlreadyExistsException x) { throw x; - } catch (MBeanRegistrationException x) { throw x; - } catch (MBeanException x) { throw x; - } catch (NotCompliantMBeanException x) { throw x; - } catch (InstanceNotFoundException x) { throw x; - } catch (SecurityException x) { throw x; - } catch (JMRuntimeException x) { throw x; - } catch (RuntimeException x) { - throw new RuntimeOperationsException(x, x.toString()); - } catch (Exception x) { - throw new MBeanException(x, x.toString()); - } - } - - - /** - * {@inheritDoc} - * - *
This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className) - throws ReflectionException, MBeanException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, ObjectName loaderName) - throws ReflectionException, MBeanException, - InstanceNotFoundException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, Object[] params, - String[] signature) throws ReflectionException, MBeanException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, ObjectName loaderName, - Object[] params, String[] signature) - throws ReflectionException, MBeanException, - InstanceNotFoundException { - throw new UnsupportedOperationException("Not applicable."); - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(ObjectName name, byte[] data) - throws InstanceNotFoundException, OperationsException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(String className, byte[] data) - throws OperationsException, ReflectionException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(String className, - ObjectName loaderName, byte[] data) - throws InstanceNotFoundException, OperationsException, - ReflectionException { - throw new UnsupportedOperationException("Not applicable."); - } - - - // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException - // if the returned mbean is null. - // The DynamicMBean returned by this method is thus guaranteed to be - // non null. - // - private DynamicMBean nonNullMBeanFor(ObjectName name) - throws InstanceNotFoundException { - if (name == null) - throw newIllegalArgumentException("Null ObjectName"); - if (name.getDomain().equals("")) { - String defaultDomain = getDefaultDomain(); - try { - // XXX change to ObjectName.switchDomain - // current code DOES NOT PRESERVE the order of keys - name = new ObjectName(defaultDomain, name.getKeyPropertyList()); - } catch (Exception e) { - throw newIllegalArgumentException( - "Illegal default domain: " + defaultDomain); - } - } - final DynamicMBean mbean = getDynamicMBeanFor(name); - if (mbean!=null) return mbean; - throw new InstanceNotFoundException(String.valueOf(name)); - } - - static RuntimeException newUnsupportedException(String operation) { - return new RuntimeOperationsException( - new UnsupportedOperationException( - operation+": Not supported in this namespace")); - } - - static RuntimeException newIllegalArgumentException(String msg) { - return new RuntimeOperationsException( - new IllegalArgumentException(msg)); - } - -} diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java Thu Sep 04 14:46:36 2008 +0200 @@ -0,0 +1,236 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.interceptor; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.mbeanserver.MBeanInstantiator; +import com.sun.jmx.mbeanserver.Repository; +import com.sun.jmx.mbeanserver.Util; +import com.sun.jmx.namespace.NamespaceInterceptor; + +import java.util.Queue; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXDomain; +import javax.management.namespace.JMXNamespace; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + +/** + * A dispatcher that dispatches to NamespaceInterceptors. + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public class NamespaceDispatchInterceptor + extends DispatchInterceptorDo not forget to call Return the MBeanServerDelegate representing the MBeanServer.
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Wed Sep 03 14:31:17 2008 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Thu Sep 04 14:46:36 2008 +0200
@@ -25,6 +25,8 @@
package com.sun.jmx.mbeanserver;
+import com.sun.jmx.defaults.JmxProperties;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -42,11 +44,22 @@
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.WeakHashMap;
+import java.util.logging.Level;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.loading.ClassLoaderRepository;
+import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
public class Util {
+ private final static int NAMESPACE_SEPARATOR_LENGTH =
+ NAMESPACE_SEPARATOR.length();
+ public final static String ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?";
+
+
static
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * Note: all the standard JMXConnector implementations are serializable.
+ * This implementation here is not. Should it be?
+ * I believe it must not be serializable unless it becomes
+ * part of a public API (either standard or officially exposed
+ * and supported in a documented com.sun package)
+ **/
+ static class JMXCachingConnector
+ implements JMXConnector {
+
+ // private static final long serialVersionUID = -2279076110599707875L;
+
+ final JMXConnector source;
+
+ // if this object is made serializable, then the variable below
+ // needs to become volatile transient and be lazyly-created...
+ private final
+ Map
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * By default, this method always returns {@code domains}
+ *
+ * @param domains The domains to return.
+ * @param action "getDomains"
+ * @return a filtered list of domains.
+ */
+ String[] checkDomains(String[] domains, String action) {
+ return domains;
+ }
+
+ // from MBeanServerConnection
+ public String getDefaultDomain() throws IOException {
+ try {
+ return source().getDefaultDomain();
+ } catch (RuntimeException ex) {
+ throw makeCompliantRuntimeException(ex);
+ }
+ }
+
+}
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanRegistrationException;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.namespace.JMXNamespaces;
+
+
+/**
+ * An RoutingProxy narrows on a given name space in a
+ * source object implementing MBeanServerConnection.
+ * It is used to implement
+ * {@code JMXNamespaces.narrowToNamespace(...)}.
+ * This abstract class has two concrete subclasses:
+ * {@link RoutingConnectionProxy}: to cd in an MBeanServerConnection. {@link RoutingServerProxy}: to cd in an MBeanServer.
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ * The DO NOT USE THESE CLASSES DIRECTLY
+ This API is a Sun internal API and is subject to changes without notice.
+ The public API through wich these proprietary classes can be
+ invoked is located in
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This class is consulted by {@link javax.management.ObjectName} at
+ * serialization / deserialization time.
+ * The serialization or deserialization context is established by
+ * by the {@link SerialRewritingProcessor} defined in this package.
+ *
+ * These classes are Sun proprietary APIs, subject to change without
+ * notice. Do not use these classes directly.
+ * The public API to rewrite ObjectNames embedded in parameters is
+ * defined in {@link javax.management.namespace.JMXNamespaces}.
+ *
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ * When entering a {@link javax.management.namespace
+ * namespace}, the {@code namespace} prefix is stripped from
+ * ObjectNames contained in input parameters. When leaving a
+ * {@code namespace},
+ * the {@code namespace} prefix is prepended to the ObjectNames contained in
+ * the result parameters returned from that {@code namespace}.
+ * Objects that need to perform these operations usually use a
+ * {@code RewritingProcessor} for that purpose. A default implementation of {@code RewritingProcessor} based on
+ * Java Object Serialization can be
+ * obtained from {@link #newRewritingProcessor newRewritingProcessor}.
+ *
+ * By default, the instances of {@code RewritingProcessor} returned by
+ * {@link #newRewritingProcessor newRewritingProcessor} will rewrite
+ * ObjectNames contained in instances of classes they don't know about by
+ * serializing and then deserializing such object instances. This will
+ * happen even if such instances don't - or can't contain ObjectNames,
+ * because the default implementation of {@code RewritingProcessor} will
+ * not be able to determine whether instances of such classes can/do contain
+ * instance of ObjectNames before serializing/deserializing them.
+ * If you are using custom classes that the default implementation of
+ * {@code RewritingProcessor} don't know about, it can be interesting to
+ * prevent an instance of {@code RewritingProcessor} to serialize/deserialize
+ * instances of such classes for nothing. In that case, you could customize
+ * the behavior of such a {@code RewritingProcessor} by wrapping it in a
+ * custom subclass of {@code RewritingProcessor} as shown below:
+ * Such a subclass may also provide an alternate way of rewriting
+ * custom subclasses for which rewriting is needed - for instance:
+ * initialize(outer,delegate)
+ * before using this object.
+ *
+ * @param outer A pointer to the MBeanServer object that must be
+ * passed to the MBeans when invoking their
+ * {@link javax.management.MBeanRegistration} interface.
+ * @param delegate A pointer to the MBeanServerDelegate associated
+ * with the new MBeanServer. The new MBeanServer must register
+ * this MBean in its MBean repository.
+ * @param instantiator The MBeanInstantiator that will be used to
+ * instantiate MBeans and take care of class loading issues.
+ * @param repository The repository to use for this MBeanServer
+ */
+ public NamespaceDispatchInterceptor(MBeanServer outer,
+ MBeanServerDelegate delegate,
+ MBeanInstantiator instantiator,
+ Repository repository) {
+ localNamespace = new DomainDispatchInterceptor(outer,delegate,
+ instantiator,repository,this);
+ serverName = Util.getMBeanServerSecurityName(delegate);
+ }
+
+ // TODO: Should move that to JMXNamespace? or to ObjectName?
+ /**
+ * Get first name space in ObjectName path. Ignore leading namespace
+ * separators.
+ **/
+ public static String getFirstNamespace(ObjectName name) {
+ if (name == null) return "";
+ final String domain = name.getDomain();
+ if (domain.equals("")) return "";
+
+ int first = 0;
+ int end = domain.indexOf(NAMESPACE_SEPARATOR,first);
+ while (end == first) {
+ first = end+NAMESPACE_SEPARATOR_LENGTH;
+ end = domain.indexOf(NAMESPACE_SEPARATOR,first);
+ if (end == -1) break;
+ }
+
+ if (end == -1) return "";
+
+ final String namespace = domain.substring(first,end);
+
+ return namespace;
+ }
+
+ /**
+ * Called by the DefaultMBeanServerInterceptor, just before adding an
+ * MBean to the repository.
+ *
+ * @param resource the MBean to be registered.
+ * @param logicalName the name of the MBean to be registered.
+ */
+ final void checkLocallyRegistrable(Object resource,
+ ObjectName logicalName) {
+ if (!(resource instanceof JMXNamespace) &&
+ logicalName.getDomain().contains(NAMESPACE_SEPARATOR))
+ throw new IllegalArgumentException(String.valueOf(logicalName)+
+ ": Invalid ObjectName for an instance of " +
+ resource.getClass().getName());
+ }
+
+ final boolean isLocalHandlerNameFor(String namespace,
+ ObjectName handlerName) {
+ return handlerName.getDomain().equals(namespace+NAMESPACE_SEPARATOR) &&
+ JMXNamespace.TYPE_ASSIGNMENT.equals(
+ handlerName.getKeyPropertyListString());
+ }
+
+ @Override
+ final MBeanServer getInterceptorOrNullFor(ObjectName name) {
+ final String namespace = getFirstNamespace(name);
+ if (namespace.equals("") || isLocalHandlerNameFor(namespace,name) ||
+ name.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
+ LOG.finer("dispatching to local name space");
+ return localNamespace;
+ }
+ final NamespaceInterceptor ns = getInterceptor(namespace);
+ if (LOG.isLoggable(Level.FINER)) {
+ if (ns != null) {
+ LOG.finer("dispatching to name space: " + namespace);
+ } else {
+ LOG.finer("no handler for: " + namespace);
+ }
+ }
+ return ns;
+ }
+
+ @Override
+ final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
+ final String namespace = getFirstNamespace(pattern);
+ if (namespace.equals("") || isLocalHandlerNameFor(namespace,pattern) ||
+ pattern.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
+ LOG.finer("dispatching to local name space");
+ return new QueryInterceptor(localNamespace);
+ }
+ final NamespaceInterceptor ns = getInterceptor(namespace);
+ if (LOG.isLoggable(Level.FINER)) {
+ if (ns != null) {
+ LOG.finer("dispatching to name space: " + namespace);
+ } else {
+ LOG.finer("no handler for: " + namespace);
+ }
+ }
+ if (ns == null) return null;
+ return new QueryInterceptor(ns);
+ }
+
+ @Override
+ final ObjectName getHandlerNameFor(String key)
+ throws MalformedObjectNameException {
+ return ObjectName.getInstance(key+NAMESPACE_SEPARATOR,
+ "type", JMXNamespace.TYPE);
+ }
+
+ @Override
+ final public String getHandlerKey(ObjectName name) {
+ return getFirstNamespace(name);
+ }
+
+ @Override
+ final NamespaceInterceptor createInterceptorFor(String key,
+ ObjectName name, JMXNamespace handler,
+ Queue?
, standing for any one
- character, and *
, standing for any string of
- characters, including the empty string.
-
- @param str the string to match, as a character array.
- @param pat the pattern to match the string against, as a
- character array.
-
- @return true if and only if the string matches the pattern.
- */
- /* The algorithm is a classical one. We advance pointers in
- parallel through str and pat. If we encounter a star in pat,
- we remember its position and continue advancing. If at any
- stage we get a mismatch between str and pat, we look to see if
- there is a remembered star. If not, we fail. If so, we
- retreat pat to just past that star and str to the position
- after the last one we tried, and we let the match advance
- again.
-
- Even though there is only one remembered star position, the
- algorithm works when there are several stars in the pattern.
- When we encounter the second star, we forget the first one.
- This is OK, because if we get to the second star in A*B*C
- (where A etc are arbitrary strings), we have already seen AXB.
- We're therefore setting up a match of *C against the remainder
- of the string, which will match if that remainder looks like
- YC, so the whole string looks like AXBYC.
- */
- public static boolean wildmatch(char[] str, char[] pat) {
- int stri; // index in str
- int pati; // index in pat
- int starstri; // index for backtrack if "*" attempt fails
- int starpati; // index for backtrack if "*" attempt fails, +1
- final int strlen = str.length;
- final int patlen = pat.length;
-
- stri = pati = 0;
- starstri = starpati = -1;
-
- /* On each pass through this loop, we either advance pati,
- or we backtrack pati and advance starstri. Since starstri
- is only ever assigned from pati, the loop must terminate. */
- while (true) {
- if (pati < patlen) {
- final char patc = pat[pati];
- switch (patc) {
- case '?':
- if (stri == strlen)
- break;
- stri++;
- pati++;
- continue;
- case '*':
- pati++;
- starpati = pati;
- starstri = stri;
- continue;
- default:
- if (stri < strlen && str[stri] == patc) {
- stri++;
- pati++;
- continue;
- }
- break;
- }
- } else if (stri == strlen)
- return true;
-
- // Mismatched, can we backtrack to a "*"?
- if (starpati < 0 || starstri == strlen)
- return false;
-
- // Retry the match one position later in str
- pati = starpati;
- starstri++;
- stri = starstri;
- }
- }
-
private void addNewDomMoi(final DynamicMBean object,
final String dom,
final ObjectName name,
@@ -370,7 +289,7 @@
if (name.isPattern()) return null;
// Extract the domain name.
- String dom= name.getDomain().intern();
+ String dom = name.getDomain().intern();
// Default domain case
if (dom.length() == 0) {
@@ -480,7 +399,7 @@
name = Util.newObjectName(domain + name.toString());
// Do we have default domain ?
- if (dom == domain) {
+ if (dom == domain) { // ES: OK (dom & domain are interned)
to_default_domain = true;
dom = domain;
} else {
@@ -652,10 +571,9 @@
}
// Pattern matching in the domain name (*, ?)
- char[] dom2Match = name.getDomain().toCharArray();
+ final String dom2Match = name.getDomain();
for (String dom : domainTb.keySet()) {
- char[] theDom = dom.toCharArray();
- if (wildmatch(theDom, dom2Match)) {
+ if (Util.wildpathmatch(dom, dom2Match)) {
final Map?
,
+ standing for any one character,
+ and *
, standing for any string of
+ characters, including the empty string. For instance,
+ {@code wildmatch("sandwich","sa?d*ch",1,4,1,4)} will match
+ {@code "and"} against {@code "a?d"}.
+
+ @param str the string containing the sequence to match.
+ @param pat a string containing a pattern to match the sub string
+ against.
+ @param stri the index in the string at which matching should begin.
+ @param strend the index in the string at which the matching should
+ end.
+ @param pati the index in the pattern at which matching should begin.
+ @param patend the index in the pattern at which the matching should
+ end.
+
+ @return true if and only if the string matches the pattern.
+ */
+ /* The algorithm is a classical one. We advance pointers in
+ parallel through str and pat. If we encounter a star in pat,
+ we remember its position and continue advancing. If at any
+ stage we get a mismatch between str and pat, we look to see if
+ there is a remembered star. If not, we fail. If so, we
+ retreat pat to just past that star and str to the position
+ after the last one we tried, and we let the match advance
+ again.
+
+ Even though there is only one remembered star position, the
+ algorithm works when there are several stars in the pattern.
+ When we encounter the second star, we forget the first one.
+ This is OK, because if we get to the second star in A*B*C
+ (where A etc are arbitrary strings), we have already seen AXB.
+ We're therefore setting up a match of *C against the remainder
+ of the string, which will match if that remainder looks like
+ YC, so the whole string looks like AXBYC.
+ */
+ private static boolean wildmatch(final String str, final String pat,
+ int stri, final int strend, int pati, final int patend) {
+
+ // System.out.println("matching "+pat.substring(pati,patend)+
+ // " against "+str.substring(stri, strend));
+ int starstri; // index for backtrack if "*" attempt fails
+ int starpati; // index for backtrack if "*" attempt fails, +1
+
+ starstri = starpati = -1;
+
+ /* On each pass through this loop, we either advance pati,
+ or we backtrack pati and advance starstri. Since starstri
+ is only ever assigned from pati, the loop must terminate. */
+ while (true) {
+ if (pati < patend) {
+ final char patc = pat.charAt(pati);
+ switch (patc) {
+ case '?':
+ if (stri == strend)
+ break;
+ stri++;
+ pati++;
+ continue;
+ case '*':
+ pati++;
+ starpati = pati;
+ starstri = stri;
+ continue;
+ default:
+ if (stri < strend && str.charAt(stri) == patc) {
+ stri++;
+ pati++;
+ continue;
+ }
+ break;
+ }
+ } else if (stri == strend)
+ return true;
+
+ // Mismatched, can we backtrack to a "*"?
+ if (starpati < 0 || starstri == strend)
+ return false;
+
+ // Retry the match one position later in str
+ pati = starpati;
+ starstri++;
+ stri = starstri;
+ }
+ }
+
+ /** Match a string against a shell-style pattern. The only pattern
+ characters recognized are ?
, standing for any one
+ character, and *
, standing for any string of
+ characters, including the empty string.
+
+ @param str the string to match.
+ @param pat the pattern to match the string against.
+
+ @return true if and only if the string matches the pattern.
+ */
+ public static boolean wildmatch(String str, String pat) {
+ return wildmatch(str,pat,0,str.length(),0,pat.length());
+ }
+
+ /**
+ * Matches a string against a pattern, as a name space path.
+ * This is a special matching where * and ?? don't match //.
+ * The string is split in sub-strings separated by //, and the
+ * pattern is split in sub-patterns separated by //. Each sub-string
+ * is matched against its corresponding sub-pattern.
+ * so com.sun.jmx.namespace
packagecom.sun.jmx.namespace
package contains
+ sun specific implementation classes used to implement the
+ JMX namespaces.
+ javax.management.namespace
+ package.
+
+ * The {@code RewritingProcessor} allows a somewhat larger
+ * transformation in which part of a prefix {@link #newRewritingProcessor
+ * remove} can be replaced by another prefix {@link #newRewritingProcessor
+ * add}. The transformation described above correspond to the case where
+ * {@code remove} is the stripped {@link javax.management.namespace
+ * namespace} prefix (removed when entering the {@code namespace}) and
+ * {@code add} is the empty String {@code ""}.
+ *
+ * It is interesting to note that {@link
+ * javax.management.JMXNamespaces#narrowToNamespace narrowToNamespace}
+ * operations use the inverse transformation (that is, {@code remove} is
+ * the empty String {@code ""} and {@code add} is the {@link
+ * javax.management.namespace namespace} prefix).
+ *
+ * On a more general scale, {@link #rewriteInput rewriteInput} removes
+ * {@link #newRewritingProcessor remove} and the prepend {@link
+ * #newRewritingProcessor add}, and {@link #rewriteOutput rewriteOutput}
+ * does the opposite, removing {@link #newRewritingProcessor add}, and
+ * then adding {@link #newRewritingProcessor remove}.
+ *
+ * An implementation of {@code RewritingProcessor} should make sure that
+ * rewriteInput(rewriteOutput(x,clp),clp)
and
+ * rewriteOutput(rewriteInput(x,clp),clp)
always return
+ * {@code x} or an exact clone of {@code x}.
+ *
+ * public class MyRewritingProcessor extends RewritingProcessor {
+ * MyRewritingProcessor(String remove, String add) {
+ * this(RewritingProcessor.newRewritingProcessor(remove,add));
+ * }
+ * MyRewritingProcessor(RewritingProcessor delegate) {
+ * super(delegate);
+ * }
+ *
+ *
+ *
+ * public class MyRewritingProcessor extends RewritingProcessor {
+ * MyRewritingProcessor(String remove, String add) {
+ * this(RewritingProcessor.newRewritingProcessor(remove,add));
+ * }
+ * MyRewritingProcessor(RewritingProcessor delegate) {
+ * super(delegate);
+ * }
+ *
+ *
+ *
If your application only uses {@link javax.management.MXBean MXBeans}, + * or MBeans using simple types, and doesn't define any custom subclass of + * {@link javax.management.Notification}, you should never write such + * such {@code RewitingProcessor} implementations. + *
+ *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public abstract class RewritingProcessor { + /** + * A logger for this class. + **/ + private final RewritingProcessor delegate; + + /** + * Creates a new instance of RewritingProcessor. + *This is equivalent to calling {@link + * #RewritingProcessor(RewritingProcessor) RewritingProcessor(null)}. + *
+ **/ + protected RewritingProcessor() { + this(null); + } + + /** + * Creates a new instance of RewritingProcessor, with a delegate. + * @param delegate a {@code RewritingProcessor} to which all the + * calls will be delegated. When implementing a subclass + * of {@code RewritingProcessor}, calling {@link + * #rewriteInput super.rewriteInput} will invoke + * {@code delegate.rewriteInput} and calling {@link + * #rewriteOutput super.rewriteOutput} will invoke + * {@code delegate.rewriteOutput}. + * + **/ + protected RewritingProcessor(RewritingProcessor delegate) { + this.delegate = delegate; + } + + /** + * Rewrites ObjectNames when {@link RewritingProcessor leaving} a {@link + * javax.management.namespace namespace}. + *+ * Returns {@code obj}, if it is known that {@code obj} doesn't contain + * any ObjectName, or a new copied instance of {@code obj} in which + * ObjectNames (if any) will have been rewritten, if {@code obj} contains + * ObjectNames, or if it is not known whether {@code obj} contains + * ObjectNames or not. + *
+ *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.rewriteOutput(obj)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param obj The result to be rewritten if needed. + * + * @return {@code obj}, or a clone of {@code obj} in which ObjectNames + * have been rewritten. See this class {@link RewritingProcessor + * description} for more details. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public+ * Returns {@code obj}, if it is known that {@code obj} doesn't contain + * any ObjectName, or a new copied instance of {@code obj} in which + * ObjectNames (if any) will have been rewritten, if {@code obj} contains + * ObjectNames, or if it is not known whether {@code obj} contains + * ObjectNames or not. + *
+ *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.rewriteInput(obj)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param obj The result to be rewritten if needed. + * @return {@code obj}, or a clone of {@code obj} in which ObjectNames + * have been rewritten. See this class {@link RewritingProcessor + * description} for more details. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toSourceContext(targetName)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param targetName The routing target ObjectName to translate. + * @return The ObjectName translated to the source context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectName toSourceContext(ObjectName targetName) { + if (delegate != null) + return delegate.toSourceContext(targetName); + throw new IllegalArgumentException("can't rewrite targetName: "+ + " no delegate."); + } + + /** + * Translate an ObjectName returned from the source context into + * the target (calling) context when {@link RewritingProcessor leaving} a + * {@link javax.management.namespace namespace}. + *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toTargetContext(sourceName)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param sourceName The routing source ObjectName to translate to the + * target context. + * @return The ObjectName translated to the target context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectName toTargetContext(ObjectName sourceName) { + if (delegate != null) + return delegate.toTargetContext(sourceName); + throw new IllegalArgumentException("can't rewrite sourceName: "+ + " no delegate."); + } + + /** + * Translate an ObjectInstance returned from the source context into + * the target (calling) context when {@link RewritingProcessor leaving} a + * {@link javax.management.namespace namespace}. + *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toTargetContext(sourceMoi)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param sourceMoi The routing source ObjectInstance to translate. + * @return The ObjectInstance translated to the target context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + if (delegate != null) + return delegate.toTargetContext(sourceMoi); + throw new IllegalArgumentException("can't rewrite sourceName: "+ + " no delegate."); + } + + /** + * Creates a new default instance of {@link RewritingProcessor}. + * @param remove The prefix to remove from {@link ObjectName ObjectNames} + * when {@link RewritingProcessor entering} the {@link + * javax.management.namespace namespace}. + * @param add The prefix to add to {@link ObjectName ObjectNames} + * when {@link RewritingProcessor entering} the {@link + * javax.management.namespace namespace} (this is performed + * after having removed the {@code remove} prefix. + * @return A new {@link RewritingProcessor} processor object that will + * perform the requested operation, using Java serialization if + * necessary. + **/ + public static RewritingProcessor newRewritingProcessor(String remove, + String add) { + return new DefaultRewritingProcessor(remove,add); + } + +} diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java Thu Sep 04 14:46:36 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace.serial; + +import com.sun.jmx.namespace.ObjectNameRouter; + + +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Class RoutingOnlyProcessor. A RewritingProcessor that uses + * Java Serialization to rewrite ObjectNames contained in + * input and results... + * + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +class RoutingOnlyProcessor extends RewritingProcessor { + + final ObjectNameRouter router; + + public RoutingOnlyProcessor(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of RoutingOnlyProcessor */ + public RoutingOnlyProcessor(final String remove, final String add) { + super(new IdentityProcessor()); + if (remove == null || add == null) + throw new IllegalArgumentException("Null argument"); + router = new ObjectNameRouter(remove,add); + } + + @Override + public final ObjectName toTargetContext(ObjectName sourceName) { + return router.toTargetContext(sourceName,false); + } + + @Override + public final ObjectName toSourceContext(ObjectName targetName) { + return router.toSourceContext(targetName,false); + } + + @Override + public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + return router.toTargetContext(sourceMoi,false); + } +} diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java Thu Sep 04 14:46:36 2008 +0200 @@ -0,0 +1,172 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace.serial; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.Queue; + +import javax.management.ObjectName; + +/** + * Class SerialRewritingProcessor. A RewritingProcessor that uses + * Java Serialization to rewrite ObjectNames contained in + * input & results... + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +class SerialRewritingProcessor extends RewritingProcessor { + + + private static class CloneOutput extends ObjectOutputStream { + Queuecom.sun.jmx.namespace.serial
packageThe com.sun.jmx.namespace.serial
package contains
+ sun specific implementation classes used to switch namespace
+ prefixes in ObjectName during serialization.
+
NEVER USE THESE CLASSES DIRECTLY
++ This API is a Sun internal API and is subject to changes without notice. +
+The public API through which these proprietary classes can be invoked is
+ located in javax.management.namespace.JMXNamespaces
+
An MBeanPermission contains four items of information:
+ *An MBeanPermission contains five items of information:
* *The action is returned by {@link #getActions()}.
* + *The MBean Server name.
+ * + *For a permission you need, this is the {@linkplain + * javax.management.MBeanServerFactory#getMBeanServerName + * name of the MBeanServer} + * containing the MBean for which the MBean + * permission is checked.
+ * + *For a permission you have, this is either the {@linkplain
+ * javax.management.MBeanServerFactory#getMBeanServerName
+ * name of the MBeanServer} in which the MBean
+ * you have this permission for must be registered,
+ * or a pattern against which that MBean Server name will be matched.
+ * An {@code mbeanServerName} pattern can also be empty or the single
+ * character {@code "*"}, both of which will match any {@code MBeanServer} name.
+ *
The class name.
* *For a permission you need, this is the class name of an MBean
@@ -88,7 +106,7 @@
* or operation you can access, or it is empty or the single character
* "*
", both of which grant access to any member.
The object name.
+ *The object name.
* *For a permission you need, this is the {@link ObjectName} of the * MBean you are accessing. For operations that do not reference a @@ -103,15 +121,15 @@ *
If you have an MBeanPermission, it allows operations only if all - * four of the items match.
+ * five of the items match. * - *The class name, member, and object name can be written together - * as a single string, which is the name of this permission. + *
The MBean Server name, class name, member, and object name can be written + * together as a single string, which is the name of this permission. * The name of the permission is the string returned by {@link * Permission#getName() getName()}. The format of the string is:
* *- ** *className#member[objectName]
+ *mbeanServerName::className#member[objectName]
*
The object name is written using the usual syntax for {@link
@@ -119,15 +137,18 @@
* ]
. It is terminated by a ]
character
* that is the last character in the string.
One or more of the className
, member
,
- * or objectName
may be omitted. If the
- * member
is omitted, the #
may be too (but
+ *
One or more of the mbeanServerName
, className
,
+ * member
, or objectName
may be omitted. If the
+ * mbeanServerName
is omitted, the ::
may be too (but
+ * does not have to be).
+ * If the member
is omitted, the #
may be too (but
* does not have to be). If the objectName
is omitted,
* the []
may be too (but does not have to be). It is
- * not legal to omit all three items, that is to have a name
+ * not legal to omit all four items, that is to have a name
* that is the empty string.
One or more of the className
, member
,
+ *
One or more of the mbeanServerName
, className
,
+ * member
,
* or objectName
may be the character "-
",
* which is equivalent to a null value. A null value is implied by
* any value (including another null value) but does not imply any
@@ -247,6 +268,13 @@
private transient ObjectName objectName;
/**
+ * The name of the MBeanServer in which this permission is checked, or
+ * granted. If null, is implied by any MBean Server name
+ * but does not imply any non-null MBean Server name.
+ */
+ private transient String mbeanServerName;
+
+ /**
* Parse actions
parameter.
*/
private void parseActions() {
@@ -283,6 +311,13 @@
throw new IllegalArgumentException("MBeanPermission name " +
"cannot be empty");
+ final int sepIndex = name.indexOf("::");
+ if (sepIndex < 0) {
+ setMBeanServerName("*");
+ } else {
+ setMBeanServerName(name.substring(0,sepIndex));
+ }
+
/* The name looks like "class#member[objectname]". We subtract
elements from the right as we parse, so after parsing the
objectname we have "class#member" and after parsing the
@@ -290,11 +325,14 @@
// Parse ObjectName
- int openingBracket = name.indexOf("[");
+
+ final int start = (sepIndex<0)?0:sepIndex+2;
+ int openingBracket = name.indexOf("[",start);
if (openingBracket == -1) {
// If "[on]" missing then ObjectName("*:*")
//
objectName = ObjectName.WILDCARD;
+ name = name.substring(start);
} else {
if (!name.endsWith("]")) {
throw new IllegalArgumentException("MBeanPermission: " +
@@ -305,11 +343,11 @@
} else {
// Create ObjectName
//
+ String on = name.substring(openingBracket + 1,
+ name.length() - 1);
try {
// If "[]" then ObjectName("*:*")
//
- String on = name.substring(openingBracket + 1,
- name.length() - 1);
if (on.equals(""))
objectName = ObjectName.WILDCARD;
else if (on.equals("-"))
@@ -320,11 +358,11 @@
throw new IllegalArgumentException("MBeanPermission: " +
"The target name does " +
"not specify a valid " +
- "ObjectName");
+ "ObjectName", e);
}
}
- name = name.substring(0, openingBracket);
+ name = name.substring(start, openingBracket);
}
// Parse member
@@ -348,8 +386,9 @@
* Assign fields based on className, member, and objectName
* parameters.
*/
- private void initName(String className, String member,
- ObjectName objectName) {
+ private void initName(String mbeanServerName, String className,
+ String member, ObjectName objectName) {
+ setMBeanServerName(mbeanServerName);
setClassName(className);
setMember(member);
this.objectName = objectName;
@@ -381,19 +420,30 @@
this.member = member;
}
+ private void setMBeanServerName(String mbeanServerName) {
+ if (mbeanServerName == null || mbeanServerName.equals("-")) {
+ this.mbeanServerName = null;
+ } else if (mbeanServerName.equals("")) {
+ this.mbeanServerName = "*";
+ } else {
+ this.mbeanServerName = mbeanServerName;
+ }
+ }
+
+
/**
*
Create a new MBeanPermission object with the specified target name * and actions.
* *The target name is of the form
- * "className#member[objectName]
" where each part is
- * optional. It must not be empty or null.
mbeanServerName::className#member[objectName]
" where
+ * each part is optional. It must not be empty or null.
*
* The actions parameter contains a comma-separated list of the * desired actions granted on the target name. It must not be * empty or null.
* - * @param name the triplet "className#member[objectName]". + * @param name the quadruplet "mbeanServerName::className#member[objectName]". * @param actions the action string. * * @exception IllegalArgumentException if thename
or
@@ -418,6 +468,12 @@
* optional. This will be the result of {@link #getName()} on the
* resultant MBeanPermission.
*
+ * This corresponds to a permission granted for all + * MBean servers present in the JVM and is equivalent to + * {@link #MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission("*",className,member,objectName,actions)}. + *
+ * *The actions parameter contains a comma-separated list of the * desired actions granted on the target name. It must not be * empty or null.
@@ -439,17 +495,67 @@ String member, ObjectName objectName, String actions) { + this("*",className,member,objectName,actions); + } - super(makeName(className, member, objectName)); - initName(className, member, objectName); + /** + *Create a new MBeanPermission object with the specified target name + * (MBean Server name, class name, member, object name) and actions.
+ * + *The MBean Server name, class name, member and object name
+ * parameters define a target name of the form
+ * "mbeanServerName::className#member[objectName]
" where each
+ * part is optional. This will be the result of {@link #getName()} on the
+ * resultant MBeanPermission.
+ * If the mbeanServerName
is empty or exactly {@code "*"}, then
+ * "{@code mbeanServerName::}" is omitted in that result.
+ *
The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param mbeanServerName the name of the {@code MBeanServer} to which this + * permission applies. + * May be null or"-"
, which represents an MBeanServer name
+ * that is implied by any MBeanServer name but does not imply any other
+ * MBeanServer name.
+ * @param className the class name to which this permission applies.
+ * May be null or "-"
, which represents a class name
+ * that is implied by any class name but does not imply any other
+ * class name.
+ * @param member the member to which this permission applies. May
+ * be null or "-"
, which represents a member that is
+ * implied by any member but does not imply any other member.
+ * @param objectName the object name to which this permission
+ * applies. May be null, which represents an object name that is
+ * implied by any object name but does not imply any other object
+ * name.
+ * @param actions the action string.
+ *
+ * @since 1.7
+ */
+ public MBeanPermission(String mbeanServerName,
+ String className,
+ String member,
+ ObjectName objectName,
+ String actions) {
+
+ super(makeName(mbeanServerName,className, member, objectName));
+ initName(mbeanServerName,className, member, objectName);
this.actions = actions;
parseActions();
}
- private static String makeName(String className, String member,
+ private static String makeName(String mbeanServerName, String className,
+ String member,
ObjectName objectName) {
final StringBuilder name = new StringBuilder();
+ if (mbeanServerName == null)
+ mbeanServerName = "-";
+ if (!mbeanServerName.equals("") && !mbeanServerName.equals("*"))
+ name.append(mbeanServerName).append("::");
if (className == null)
className = "-";
name.append(className);
@@ -991,6 +1097,9 @@
*
* If this object's mbeanServerName is a pattern, then p's + * mbeanServerName is matched against that pattern. An empty + * mbeanServerName is equivalent to "{@code *}". A null + * mbeanServerName is equivalent to "{@code -}".
+ *If this object's mbeanServerName is "*
" or is
+ * empty, p's mbeanServerName always matches it.
If this object's className is "*
", p's
* className always matches it. If it is "a.*
", p's
* className matches it if it begins with "a.
".
User code does not usually implement this interface. Instead, * an object that implements this interface is obtained with one of - * the methods in the {@link MBeanServerFactory} class.
+ * the methods in the {@link javax.management.MBeanServerFactory} class. * *Every MBean which is added to the MBean server becomes
* manageable: its attributes and operations become remotely
@@ -62,8 +62,12 @@
* JMImplementation:type=MBeanServerDelegate
.
An object obtained from the {@link - * MBeanServerFactory#createMBeanServer(String) createMBeanServer} or - * {@link MBeanServerFactory#newMBeanServer(String) newMBeanServer} + * MBeanServerFactory#createMBeanServer(String) createMBeanServer}, {@link + * MBeanServerFactory#createNamedMBeanServer(String,String) createNamedMBeanServer}, + * {@link + * MBeanServerFactory#newMBeanServer(String) newMBeanServer}, or + * {@link + * MBeanServerFactory#newNamedMBeanServer(String,String) newNamedMBeanServer} * methods of the {@link MBeanServerFactory} class applies security * checks to its methods, as follows.
* @@ -73,9 +77,26 @@ * *Assuming that there is a security manager, or that the
* implementation chooses to make checks anyway, the checks are made
- * as detailed below. In what follows, className
is the
+ * as detailed below.
+ * In what follows, and unless otherwise specified:
+ *
className
is the
* string returned by {@link MBeanInfo#getClassName()} for the target
- * MBean.
+ * MBean,If a security check fails, the method throws {@link * SecurityException}.
@@ -89,78 +110,86 @@ * *For the {@link #invoke invoke} method, the caller's * permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, operationName, name, "invoke")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, operationName, name, "invoke")}. + * * *For the {@link #getAttribute getAttribute} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, attribute, name, "getAttribute")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, attribute, name, + * "getAttribute")}. * *For the {@link #getAttributes getAttributes} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "getAttribute")}. + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName,className, null, name, "getAttribute")}. * Additionally, for each attribute a in the {@link * AttributeList}, if the caller's permissions do not imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, a, name, "getAttribute")}, the + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, a, name, + * "getAttribute")}, the * MBean server will behave as if that attribute had not been in the * supplied list.
* *For the {@link #setAttribute setAttribute} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, attrName, name, "setAttribute")}, where
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, attrName, name,
+ * "setAttribute")}, where
* attrName
is {@link Attribute#getName()
* attribute.getName()}.
For the {@link #setAttributes setAttributes} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "setAttribute")}. + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "setAttribute")}. * Additionally, for each attribute a in the {@link * AttributeList}, if the caller's permissions do not imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, a, name, "setAttribute")}, the + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, a, name, + * "setAttribute")}, the * MBean server will behave as if that attribute had not been in the * supplied list.
* *For the addNotificationListener
methods,
* the caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name,
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name,
* "addNotificationListener")}.
For the removeNotificationListener
methods,
* the caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name,
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name,
* "removeNotificationListener")}.
For the {@link #getMBeanInfo getMBeanInfo} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "getMBeanInfo")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "getMBeanInfo")}. + * * *For the {@link #getObjectInstance getObjectInstance} method, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "getObjectInstance")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, + * "getObjectInstance")}. * *For the {@link #isInstanceOf isInstanceOf} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "isInstanceOf")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "isInstanceOf")}. + * * *For the {@link #queryMBeans queryMBeans} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(null, null, name, "queryMBeans")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, null, null, null, "queryMBeans")}.
* Additionally, for each MBean that matches name
,
* if the caller's permissions do not imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "queryMBeans")}, the
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name, "queryMBeans")}, the
* MBean server will behave as if that MBean did not exist.
Certain query elements perform operations on the MBean server. @@ -179,10 +208,10 @@ * *
For the {@link #getDomains getDomains} method, the caller's * permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(null, null, name, "getDomains")}. Additionally, - * for each domain d in the returned array, if the caller's - * permissions do not imply {@link + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, null, null, null, "getDomains")}. + * Additionally, for each domain d in the returned array, if the + * caller's permissions do not imply {@link * MBeanPermission#MBeanPermission(String,String,ObjectName,String) * MBeanPermission(null, null, new ObjectName("d:x=x"), * "getDomains")}, the domain is eliminated from the array. Here, @@ -191,21 +220,22 @@ * *
For the {@link #getClassLoader getClassLoader} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, loaderName, + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, loaderName, * "getClassLoader")}.
* *For the {@link #getClassLoaderFor getClassLoaderFor} method, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, mbeanName, + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, mbeanName, * "getClassLoaderFor")}.
* *For the {@link #getClassLoaderRepository * getClassLoaderRepository} method, the caller's permissions must * imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(null, null, null, "getClassLoaderRepository")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, null, null, null, + * "getClassLoaderRepository")}. * *For the deprecated deserialize
methods, the
* required permissions are the same as for the methods that replace
@@ -213,15 +243,15 @@
*
*
For the instantiate
methods, the caller's
* permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, null, "instantiate")}.
For the {@link #registerMBean registerMBean} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "registerMBean")}. Here
- * className
is the string returned by {@link
- * MBeanInfo#getClassName()} for an object of this class.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name, "registerMBean")}.
*
*
If the MBeanPermission
check succeeds, the MBean's
* class is validated by checking that its {@link
@@ -241,8 +271,9 @@
*
*
For the {@link #unregisterMBean unregisterMBean} method, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "unregisterMBean")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "unregisterMBean")}. + * * * * diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/MBeanServerDelegate.java --- a/jdk/src/share/classes/javax/management/MBeanServerDelegate.java Wed Sep 03 14:31:17 2008 +0200 +++ b/jdk/src/share/classes/javax/management/MBeanServerDelegate.java Thu Sep 04 14:46:36 2008 +0200 @@ -25,7 +25,9 @@ package javax.management; +import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.defaults.ServiceName; +import com.sun.jmx.mbeanserver.Util; /** * Represents the MBean server from the management point of view. @@ -39,6 +41,7 @@ /** The MBean server agent identification.*/ private String mbeanServerId ; + private String mbeanServerName; /** The NotificationBroadcasterSupport object that sends the notifications */ @@ -68,6 +71,7 @@ public MBeanServerDelegate () { stamp = getStamp(); broadcaster = new NotificationBroadcasterSupport() ; + mbeanServerName=null; } @@ -82,14 +86,103 @@ try { localHost = java.net.InetAddress.getLocalHost().getHostName(); } catch (java.net.UnknownHostException e) { + JmxProperties.MISC_LOGGER.finest("Can't get local host name, " + + "using \"localhost\" instead. Cause is: "+e); localHost = "localhost"; } - mbeanServerId = localHost + "_" + stamp; + mbeanServerId = + Util.insertMBeanServerName(localHost + "_" + stamp, + mbeanServerName); } return mbeanServerId; } /** + * The name of the MBeanServer. + * @return The name of the MBeanServer, or {@value + * javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if no + * name was specified. + * + * @since 1.7 + * @see #setMBeanServerName + */ + public synchronized String getMBeanServerName() { + if (Util.isMBeanServerNameUndefined(mbeanServerName)) + return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; + return mbeanServerName; + } + + /** + * Sets the name of the MBeanServer. The name will be embedded into the + * {@link #getMBeanServerId MBeanServerId} using the following format:The characters {@code ':'} (colon), {@code ';'} (semicolon ), + * {@code '*'} (star) and {@code '?'} (question mark) are not legal in an + * MBean Server name.
+ *For instance, if the {@code mbeanServerName} provided is + * {@code "com.mycompany.myapp.server1"}, and the original + * {@code MBeanServerId} was {@code "myhost_1213353064145"}, + * then {@code mbeanServerName} will be + * embedded in the {@code MBeanServerId} - and the new value of the + * {@code MBeanServerId} will be: + *
+ *+ * "myhost_1213353064145;mbeanServerName=com.mycompany.myapp.server1" + *+ *
Note: The {@code mbeanServerName} is usually set by the + * {@code MBeanServerFactory}. It is set only once, before the + * MBean Server is returned by the factory. Once the MBean Server name is + * set, it is not possible to change it. + *
+ * @param mbeanServerName The MBeanServer name. + * @throws IllegalArgumentException if the MBeanServerName is already set + * to a different value, or if the provided name contains + * illegal characters, or if the provided name is {@code ""} + * (the empty string) or "-" (dash). + * @throws UnsupportedOperationException if this object is of a legacy + * subclass of MBeanServerDelegate which overrides {@link + * #getMBeanServerId()} + * in a way that doesn't support setting an MBeanServer name. + * @see MBeanServerFactory#getMBeanServerName + * @since 1.7 + */ + public synchronized void setMBeanServerName(String mbeanServerName) { + // Sets the name on the delegate. For complex backward + // compatibility reasons it is not possible to give the + // name to the MBeanServerDelegate constructor. + // + // The method setMBeanServerName() will call getMBeanServerId() + // to check that the name is accurately set in the MBeanServerId. + // If not (which could happen if a custom MBeanServerDelegate + // implementation overrides getMBeanServerId() and was not updated + // with respect to JMX 2.0 spec), this method will throw an + // IllegalStateException... + + // will fail if mbeanServerName is illegal + final String name = Util.checkServerName(mbeanServerName); + + // can only set mbeanServerDelegate once. + if (this.mbeanServerName != null && !this.mbeanServerName.equals(name)) + throw new IllegalArgumentException( + "MBeanServerName already set to a different value"); + + this.mbeanServerName = name; + + // will fail if mbeanServerId already has a different mbeanServerName + mbeanServerId = + Util.insertMBeanServerName(getMBeanServerId(),name); + + // check that we don't have a subclass which overrides + // getMBeanServerId() without setting mbeanServerName + if (!name.equals( + Util.extractMBeanServerName(getMBeanServerId()))) + throw new UnsupportedOperationException( + "Can't set MBeanServerName in MBeanServerId - " + + "unsupported by "+this.getClass().getName()+"?"); + // OK: at this point we know that we have correctly set mbeanServerName. + } + + /** * Returns the full name of the JMX specification implemented * by this product. * @@ -210,15 +303,8 @@ * * @since 1.6 */ - public static final ObjectName DELEGATE_NAME; - static { - try { - DELEGATE_NAME = - new ObjectName("JMImplementation:type=MBeanServerDelegate"); - } catch (MalformedObjectNameException e) { - throw new Error("Can't initialize delegate name", e); - } - } + public static final ObjectName DELEGATE_NAME = + Util.newObjectName("JMImplementation:type=MBeanServerDelegate"); /* Return a timestamp that is monotonically increasing even if System.currentTimeMillis() isn't (for example, if you call this diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/MBeanServerFactory.java --- a/jdk/src/share/classes/javax/management/MBeanServerFactory.java Wed Sep 03 14:31:17 2008 +0200 +++ b/jdk/src/share/classes/javax/management/MBeanServerFactory.java Thu Sep 04 14:46:36 2008 +0200 @@ -25,16 +25,19 @@ package javax.management; +import com.sun.jmx.defaults.JmxProperties; import static com.sun.jmx.defaults.JmxProperties.JMX_INITIAL_BUILDER; import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; -import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor; import com.sun.jmx.mbeanserver.GetPropertyAction; +import com.sun.jmx.mbeanserver.Util; import java.security.AccessController; import java.security.Permission; import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import javax.management.loading.ClassLoaderRepository; + /** *Provides MBean server references. There are no instances of * this class.
@@ -80,10 +83,53 @@ * returned by the default MBeanServerBuilder implementation, for the purpose * of e.g. adding an additional security layer. * + *Since version 2.0 of the JMX API, when creating + * an MBeanServer, + * it is possible to specify an {@linkplain #getMBeanServerName + * MBean Server name}. + * To create an MBean Server with a name, the MBeanServerFactory provides two + * new methods:
+ *The name of the MBeanServer is stored in the + * {@linkplain MBeanServerDelegate MBean Server delegate MBean} + * and is embedded in its {@link MBeanServerDelegate#getMBeanServerId + * MBeanServerId} attribute.
+ *The name of the MBeanServer is particularly useful when + * MBean permissions are checked: + * it makes it + * possible to distinguish between an MBean named "X" in MBeanServer named + * "M1", and another MBean of the same name "X" in another MBeanServer named + * "M2".
+ *When naming MBean servers it is recommended to use a name that starts + * with a Java package name. It is also recommended that the default domain and + * the MBeanServer name be the same.
+ * * @since 1.5 */ public class MBeanServerFactory { + /** + * The MBean Server name that will be + * checked by a permission you need + * when checking access to an MBean registered in an MBeanServer for + * which no MBeanServer name was specified. + * + * @since 1.7 + */ + public final static String DEFAULT_MBEANSERVER_NAME = "default"; + /* * There are no instances of this class so don't generate the * default public constructor. @@ -222,13 +268,78 @@ *javax.management.builder.initial
exists and can be
* instantiated but is not assignment compatible with {@link
* MBeanServerBuilder}.
+ *
+ * @see #createNamedMBeanServer
*/
public static MBeanServer createMBeanServer(String domain) {
- checkPermission("createMBeanServer");
+ return createMBeanServer(null,domain);
+ }
- final MBeanServer mBeanServer = newMBeanServer(domain);
- addMBeanServer(mBeanServer);
- return mBeanServer;
+ /**
+ * Return a new object implementing the {@link MBeanServer} + * interface with the specified + * MBean Server name + * and default domain name. The given MBean server name + * is used in security checks, and + * can also be used to {@linkplain #findMBeanServerByName(java.lang.String) + * find an MBeanServer by name}. The given + * domain name is used as the domain part in the ObjectName of + * MBeans when the domain is specified by the user is null.
+ * + *The MBeanServer reference is internally kept. This will
+ * allow findMBeanServer
to return a reference to
+ * this MBeanServer object.
{@link
+ * MBeanServerPermission}("createMBeanServer")
.
+ *
+ * @exception JMRuntimeException if the property
+ * javax.management.builder.initial
exists but the
+ * class it names cannot be instantiated through a public
+ * no-argument constructor; or if the instantiated builder returns
+ * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
+ * newMBeanServerDelegate} or {@link
+ * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
+ *
+ * @exception ClassCastException if the property
+ * javax.management.builder.initial
exists and can be
+ * instantiated but is not assignment compatible with {@link
+ * MBeanServerBuilder}.
+ *
+ * @exception IllegalArgumentException if the specified
+ * {@code mbeanServerName} is empty, or is {@code "-"}, or contains a
+ * character which is not legal.
+ *
+ * @exception UnsupportedOperationException if the specified
+ * {@code mbeanServerName} cannot be set.
+ *
+ * @since 1.7
+ */
+ public static MBeanServer createNamedMBeanServer(String mbeanServerName,
+ String domain) {
+ return createMBeanServer(mbeanServerName, domain);
}
/**
@@ -307,6 +418,88 @@
* MBeanServerBuilder}.
*/
public static MBeanServer newMBeanServer(String domain) {
+ return newMBeanServer(null,domain);
+ }
+
+ /**
+ * Return a new object implementing the MBeanServer interface + * with the specified MBean server name + * and default domain name, without keeping an + * internal reference to this new object. The given MBean server name + * is used in security checks. + * The given domain name + * is used as the domain part in the ObjectName of MBeans when the + * domain is specified by the user is null.
+ * + *No reference is kept. findMBeanServer
and
+ * findMBeanServerByName
will not
+ * be able to return a reference to this MBeanServer object, but
+ * the garbage collector will be able to remove the MBeanServer
+ * object when it is no longer referenced.
{@link
+ * MBeanServerPermission}("newMBeanServer")
.
+ *
+ * @exception JMRuntimeException if the property
+ * javax.management.builder.initial
exists but the
+ * class it names cannot be instantiated through a public
+ * no-argument constructor; or if the instantiated builder returns
+ * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
+ * newMBeanServerDelegate} or {@link
+ * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
+ *
+ * @exception ClassCastException if the property
+ * javax.management.builder.initial
exists and can be
+ * instantiated but is not assignment compatible with {@link
+ * MBeanServerBuilder}.
+ *
+ * @exception IllegalArgumentException if the specified
+ * {@code mbeanServerName} is empty, or is {@code "-"},
+ * or contains a character which is not legal.
+ *
+ * @exception UnsupportedOperationException if the specified
+ * {@code mbeanServerName} cannot be set.
+ *
+ * @since 1.7
+ */
+ public static MBeanServer newNamedMBeanServer(String mbeanServerName,
+ String domain) {
+ return newMBeanServer(mbeanServerName, domain);
+ }
+
+ private static MBeanServer createMBeanServer(String mbeanServerName,
+ String domain) {
+ checkPermission("createMBeanServer");
+
+ final MBeanServer mBeanServer =
+ newMBeanServer(mbeanServerName,domain);
+ addMBeanServer(mBeanServer);
+ return mBeanServer;
+ }
+
+ private static MBeanServer newMBeanServer(String mbeanServerName,
+ String domain) {
checkPermission("newMBeanServer");
// Get the builder. Creates a new one if necessary.
@@ -316,20 +509,50 @@
synchronized(mbsBuilder) {
final MBeanServerDelegate delegate =
- mbsBuilder.newMBeanServerDelegate();
+ mbsBuilder.newMBeanServerDelegate();
if (delegate == null) {
final String msg =
- "MBeanServerBuilder.newMBeanServerDelegate() " +
- "returned null";
+ "MBeanServerBuilder.newMBeanServerDelegate() " +
+ "returned null";
throw new JMRuntimeException(msg);
}
+
+ // Sets the name on the delegate. For complex backward
+ // compatibility reasons it is not possible to give the
+ // name to the MBeanServerDelegate constructor.
+ //
+ // The method setMBeanServerName() will call getMBeanServerId()
+ // to check that the name is accurately set in the MBeanServerId.
+ // If not (which could happen if a custom MBeanServerDelegate
+ // implementation overrides getMBeanServerId() and was not updated
+ // with respect to JMX 2.0 spec, this method will throw an
+ // IllegalStateException...
+ //
+ if (!Util.isMBeanServerNameUndefined(mbeanServerName)) {
+ delegate.setMBeanServerName(mbeanServerName);
+ }
+
final MBeanServer mbeanServer =
- mbsBuilder.newMBeanServer(domain,null,delegate);
+ mbsBuilder.newMBeanServer(domain,null,delegate);
if (mbeanServer == null) {
final String msg =
- "MBeanServerBuilder.newMBeanServer() returned null";
+ "MBeanServerBuilder.newMBeanServer() returned null";
throw new JMRuntimeException(msg);
}
+
+ // double check that the MBeanServer name is correctly set.
+ // "*" might mean that the caller doesn't have the permission
+ // to see the MBeanServer name.
+ //
+ final String mbsName = Util.getMBeanServerSecurityName(mbeanServer);
+ if (!mbsName.equals(Util.checkServerName(mbeanServerName))
+ && !mbsName.equals("*")) {
+ throw new UnsupportedOperationException(
+ "can't create MBeanServer with name \""+
+ mbeanServerName+"\" using "+
+ builder.getClass().getName());
+ }
+
return mbeanServer;
}
}
@@ -363,7 +586,7 @@
ArrayListReturns a list of registered MBeanServer objects with the given name. A
+ * registered MBeanServer object is one that was created by one of
+ * the createMBeanServer
or createNamedMBeanServer
+ * methods and not subsequently released with releaseMBeanServer
.
See the section about MBean Server names + * above.
+ * + * @param mbeanServerName The name of the MBeanServer to + * retrieve. If this parameter is null, all registered MBeanServers + * in this JVM are returned. + * Otherwise, only those MBeanServers that have a name + * matchingmbeanServerName
are returned: this
+ * parameter can be a pattern, where {@code '*'} matches any
+ * sequence of characters and {@code '?'} matches any character.MBeanServerId
attribute of its delegate MBean:
+ * this method will parse the MBeanServerId
to get the
+ * MBeanServer name. If this parameter is equal to {@code "*"} then
+ * all registered MBeanServers in this JVM are returned, whether they have
+ * a name or not: {@code findMBeanServerByName(null)},
+ * {@code findMBeanServerByName("*")} and {@code findMBeanServer(null)},
+ * are equivalent. It is also possible to get all MBeanServers for which
+ * no name was specified by calling findMBeanServerByName({@value
+ * #DEFAULT_MBEANSERVER_NAME})
.
+ *
+ * @return A list of MBeanServer objects.
+ *
+ * @exception SecurityException if there is a SecurityManager and the
+ * caller's permissions do not include or imply {@link
+ * MBeanServerPermission}("findMBeanServer")
.
+ *
+ * @see #getMBeanServerName(MBeanServer)
+ * @since 1.7
+ */
+ public synchronized static
+ ListFor instance, if an MBeanServer is created using {@link
+ * #createNamedMBeanServer(java.lang.String, java.lang.String)
+ * server =
+ * MBeanServerFactory.createNamedMBeanServer("com.mycompany.myapp.server1",
+ * null)} then {@code MBeanServerFactory.getMBeanServerName(server)}
+ * will return {@code "com.mycompany.myapp.server1"} and
+ * server.getAttribute({@link
+ * javax.management.MBeanServerDelegate#DELEGATE_NAME
+ * MBeanServerDelegate.DELEGATE_NAME}, "MBeanServerId")
will return
+ * something like
+ * {@code "myhost_1213353064145;mbeanServerName=com.mycompany.myapp.server1"}.
+ *
See the section about MBean Server names + * above.
+ * @param server A named (or unnamed) MBeanServer. + * @return the name of the MBeanServer if found, or + * {@value #DEFAULT_MBEANSERVER_NAME} if no name is + * present in its MBeanServerId, or "*" if its + * MBeanServerId couldn't be obtained. Returning "*" means that + * only {@link MBeanPermission}s that allow all MBean Server names + * will apply to this MBean Server. + * @see MBeanServerDelegate + * @since 1.7 + */ + public static String getMBeanServerName(MBeanServer server) { + return Util.getMBeanServerSecurityName(server); + } + + /** * Return the ClassLoaderRepository used by the given MBeanServer. - * This method is equivalent to {@link MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}. + * This method is equivalent to {@link + * MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}. * @param server The MBeanServer under examination. Since JMX 1.2, * ifserver
is null
, the result is a
* {@link NullPointerException}. This behavior differs from what
@@ -387,21 +701,23 @@
*
**/
public static ClassLoaderRepository getClassLoaderRepository(
- MBeanServer server) {
+ MBeanServer server) {
return server.getClassLoaderRepository();
}
- private static String mBeanServerName(MBeanServer mbs) {
+ private static String mBeanServerId(MBeanServer mbs) {
try {
return (String) mbs.getAttribute(MBeanServerDelegate.DELEGATE_NAME,
- "MBeanServerId");
+ "MBeanServerId");
} catch (JMException e) {
+ JmxProperties.MISC_LOGGER.finest(
+ "Ignoring exception while getting MBeanServerId: "+e);
return null;
}
}
private static void checkPermission(String action)
- throws SecurityException {
+ throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Permission perm = new MBeanServerPermission(action);
@@ -425,16 +741,16 @@
}
private static final ArrayList- * Wildcard matching routine by Karl Heuer. Public Domain.
- */
- private static boolean wildmatch(char[] s, char[] p, int si, int pi) {
- char c;
- final int slen = s.length;
- final int plen = p.length;
-
- while (pi < plen) { // While still string
- c = p[pi++];
- if (c == '?') {
- if (++si > slen) return false;
- } else if (c == '*') { // Wildcard
- if (pi >= plen) return true;
- do {
- if (wildmatch(s,p,si,pi)) return true;
- } while (++si < slen);
- return false;
- } else {
- if (si >= slen || c != s[si++]) return false;
- }
- }
- return (si == slen);
- }
// Category : Internal utilities <==============================
@@ -1177,15 +1205,43 @@
cn = (String)in.readObject();
}
+ final JMXNamespaceContext ctxt =
+ JMXNamespaceContext.getDeserializationContext();
try {
- construct(cn);
+ construct(changeContext(ctxt,cn));
} catch (NullPointerException e) {
throw new InvalidObjectException(e.toString());
+ } catch (IllegalArgumentException e) {
+ throw new InvalidObjectException(e.toString());
} catch (MalformedObjectNameException e) {
throw new InvalidObjectException(e.toString());
}
}
+ private String changeContext(JMXNamespaceContext context, String nameString) {
+ final String old = context.prefixToRemove;
+ final String nw = context.prefixToAdd;
+ final int ol = old.length();
+ if (nameString.startsWith(NAMESPACE_SEPARATOR)) return nameString;
+ if (ol>0) {
+ if (!nameString.startsWith(old) ||
+ !nameString.startsWith(NAMESPACE_SEPARATOR,ol))
+ throw new IllegalArgumentException(
+ "Serialized ObjectName does not start with " + old +
+ ": " + nameString);
+ nameString = nameString.substring(ol+NAMESPACE_SEPARATOR_LENGTH);
+ }
+ if (!nw.equals("")) {
+ nameString = nw + NAMESPACE_SEPARATOR + nameString;
+ }
+ // TODO remove this hack
+ // if (nameString.endsWith("//javax.management.service:type1=event_client_delegeate_mbean,type2=default")) {
+ // System.err.println("old="+old+", nw="+nw);
+ // Thread.currentThread().dumpStack();
+ // throw new Error("************************ Gotcha!");
+ // }
+ return nameString;
+ }
/**
* Serializes an {@link ObjectName} to an {@link ObjectOutputStream}.
@@ -1248,15 +1304,22 @@
private void writeObject(ObjectOutputStream out)
throws IOException {
+ final JMXNamespaceContext ctxt =
+ JMXNamespaceContext.getSerializationContext();
+
if (compat)
{
// Serializes this instance in the old serial form
// Read CR 6441274 before making any changes to this code
ObjectOutputStream.PutField fields = out.putFields();
- fields.put("domain", _canonicalName.substring(0, _domain_length));
+ final String domain =
+ changeContext(ctxt,_canonicalName.substring(0, _domain_length));
+ final String cn =
+ changeContext(ctxt,_canonicalName);
+ fields.put("domain", domain);
fields.put("propertyList", getKeyPropertyList());
fields.put("propertyListString", getKeyPropertyListString());
- fields.put("canonicalName", _canonicalName);
+ fields.put("canonicalName", cn);
fields.put("pattern", (_domain_pattern || _property_list_pattern));
fields.put("propertyPattern", _property_list_pattern);
out.writeFields();
@@ -1266,7 +1329,8 @@
// Serializes this instance in the new serial form
//
out.defaultWriteObject();
- out.writeObject(getSerializedNameString());
+
+ out.writeObject(changeContext(ctxt,getSerializedNameString()));
}
}
@@ -1397,6 +1461,27 @@
}
/**
+ * Returns an {@code ObjectName} that is the same as this one but
+ * with the specified domain.
+ * This method preserves the original key order in the new instance.
+ * If the provided name has a key property pattern, it will also be
+ * preserved in the returned instance.
+ *
+ * @param newDomain The new domain for the returned instance;
+ * must not be null.
+ * @return A new {@code ObjectName} that is the same as {@code this}
+ * except the domain is {@code newDomain}.
+ * @throws NullPointerException if {@code newDomain} is null.
+ * @throws MalformedObjectNameException if the new domain is syntactically
+ * illegal.
+ * @since 1.7
+ **/
+ public final ObjectName withDomain(String newDomain)
+ throws NullPointerException, MalformedObjectNameException {
+ return new ObjectName(newDomain, this);
+ }
+
+ /**
* Construct an object name from the given string.
*
* @param name A string representation of the object name.
@@ -1550,7 +1635,7 @@
throw new NullPointerException("key property can't be null");
for (int i = 0; i < _ca_array.length; i++) {
Property prop = _ca_array[i];
- String key = prop.getKeyString(_canonicalName);
+ String key = prop.getKeyString(_canonicalName,_domain_length);
if (key.equals(property))
return (prop instanceof PatternProperty);
}
@@ -1630,8 +1715,10 @@
Property prop;
for (int i = len - 1; i >= 0; i--) {
prop = _ca_array[i];
- _propertyList.put(prop.getKeyString(_canonicalName),
- prop.getValueString(_canonicalName));
+ _propertyList.put(prop.getKeyString(_canonicalName,
+ _domain_length),
+ prop.getValueString(_canonicalName,
+ _domain_length));
}
}
}
@@ -1716,7 +1803,8 @@
}
}
- return new String(dest_chars);
+ final String name = new String(dest_chars);
+ return name;
}
/**
@@ -1734,7 +1822,7 @@
if (_kp_array.length == 0) return offset;
final char[] dest_chars = data;
- final char[] value = _canonicalName.toCharArray();
+ final char[] value = canonicalChars;
int index = offset;
final int len = _kp_array.length;
@@ -1742,7 +1830,7 @@
for (int i = 0; i < len; i++) {
final Property prop = _kp_array[i];
final int prop_len = prop._key_length + prop._value_length + 1;
- System.arraycopy(value, prop._key_index, dest_chars, index,
+ System.arraycopy(value, prop._key_index+_domain_length, dest_chars, index,
prop_len);
index += prop_len;
if (i < last ) dest_chars[index++] = ',';
@@ -1816,7 +1904,7 @@
// (because usage of intern())
ObjectName on = (ObjectName) object;
String on_string = on._canonicalName;
- if (_canonicalName == on_string) return true;
+ if (_canonicalName == on_string) return true; // ES: OK
// Because we are sharing canonical form between object names,
// we have finished the comparison at this stage ==> unequal
@@ -1997,9 +2085,9 @@
private final boolean matchDomains(ObjectName name) {
if (_domain_pattern) {
// wildmatch domains
- final char[] dom_pattern = getDomain().toCharArray();
- final char[] dom_string = name.getDomain().toCharArray();
- return wildmatch(dom_string,dom_pattern,0,0);
+ // This ObjectName is the pattern
+ // The other ObjectName is the string.
+ return Util.wildpathmatch(name.getDomain(),getDomain());
}
return getDomain().equals(name.getDomain());
}
@@ -2025,7 +2113,7 @@
// index in receiver
//
final Property p = props[i];
- final String k = p.getKeyString(cn);
+ final String k = p.getKeyString(cn,_domain_length);
final String v = nameProps.get(k);
// Did we find a value for this key ?
//
@@ -2034,15 +2122,13 @@
//
if (_property_value_pattern && (p instanceof PatternProperty)) {
// wildmatch key property values
- final char[] val_pattern =
- p.getValueString(cn).toCharArray();
- final char[] val_string = v.toCharArray();
- if (wildmatch(val_string,val_pattern,0,0))
+ // p is the property pattern, v is the string
+ if (Util.wildmatch(v,p.getValueString(cn,_domain_length)))
continue;
else
return false;
}
- if (v.equals(p.getValueString(cn))) continue;
+ if (v.equals(p.getValueString(cn,_domain_length))) continue;
return false;
}
return true;
@@ -2109,6 +2195,10 @@
* @since 1.6
*/
public int compareTo(ObjectName name) {
+ // Quick optimization:
+ //
+ if (name == this) return 0;
+
// (1) Compare domains
//
int domainValue = this.getDomain().compareTo(name.getDomain());
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/event/EventClient.java
--- a/jdk/src/share/classes/javax/management/event/EventClient.java Wed Sep 03 14:31:17 2008 +0200
+++ b/jdk/src/share/classes/javax/management/event/EventClient.java Thu Sep 04 14:46:36 2008 +0200
@@ -29,6 +29,7 @@
import com.sun.jmx.event.LeaseRenewer;
import com.sun.jmx.event.ReceiverBuffer;
import com.sun.jmx.event.RepeatedSingletonJob;
+import com.sun.jmx.namespace.JMXNamespaceUtils;
import com.sun.jmx.mbeanserver.PerThreadGroupPool;
import com.sun.jmx.remote.util.ClassLogger;
@@ -1063,6 +1064,24 @@
return clientId;
}
+ /**
+ * Returns a JMX Connector that will use an {@link EventClient}
+ * to subscribe for notifications. If the server doesn't have
+ * an {@link EventClientDelegateMBean}, then the connector will
+ * use the legacy notification mechanism instead.
+ *
+ * @param wrapped The underlying JMX Connector wrapped by the returned
+ * connector.
+ *
+ * @return A JMX Connector that will uses an {@link EventClient}, if
+ * available.
+ *
+ * @see EventClient#getEventClientConnection(MBeanServerConnection)
+ */
+ public static JMXConnector withEventClient(final JMXConnector wrapped) {
+ return JMXNamespaceUtils.withEventClient(wrapped);
+ }
+
private static final PerThreadGroupPool
+ * Note: A JMXNamespace MBean cannot be registered + * simultaneously in two different + * MBean servers, or indeed in the same MBean Server with two + * different names. It is however possible to give the same MBeanServer + * instance to two different JMXNamespace MBeans, and thus create a graph + * rather than a tree. + *
+ * + *To view the content of a namespace, you will usually use an + * instance of {@link JMXNamespaceView}. For instance, given the + * namespace {@code "foo"} created above, you would do: + *
+ *+ * final JMXNamespaceView view = new JMXNamespaceView(server); + * System.out.println("List of namespaces: "+Arrays.toString({@link JMXNamespaceView#list() view.list()})); + * + * final JMXNamespaceView foo = {@link JMXNamespaceView#down view.down("foo")}; + * System.out.println({@link JMXNamespaceView#where() foo.where()}+" contains: " + + * {@link JMXNamespaceView#getMBeanServerConnection foo.getMBeanServerConnection()}.queryNames(null,null)); + *+ * + *
A special {@link JMXNamespacePermission} is defined to check access + * to MBean within namespaces.
+ *When a JMXNamespace MBean is registered in an
+ * MBean server created through the default {@link
+ * javax.management.MBeanServerBuilder}, and if a {@link
+ * SecurityManager SecurityManager} is
+ * {@linkplain System#getSecurityManager() present}, the MBeanServer will
+ * check a {@link JMXNamespacePermission} before invoking
+ * any method on the {@linkplain #getSourceServer source MBeanServer} of the
+ * JMXNamespace.
+ * {@linkplain JMXNamespacePermission JMX Namespace Permissions} are similar to
+ * {@linkplain javax.management.MBeanPermission MBean Permissions}, except
+ * that you usually cannot specify an MBean class name. You can however
+ * specify object name patterns - which will allow you for example to only grant
+ * permissions for MBeans having a specific {@code type=
+ * Another difference is that {@link JMXNamespacePermission
+ * JMXNamespacePermission} also specifies from which namespace and which
+ * MBean server the permission is granted.
+ * In the rest of this document, the following terms are used: {@code server name} is the
+ * name of the
+ * MBeanServer in which the permission is granted.
+ * The name of an {@code MBeanServer} can be obtained by calling {@link
+ * javax.management.MBeanServerFactory#getMBeanServerName
+ * MBeanServerFactory.getMBeanServerName(mbeanServer)}
+ * {@code namespace} is the name of the namespace
+ * in the named MBean server for which the
+ * permission is granted. It doesn't contain any
+ * {@link JMXNamespaces#NAMESPACE_SEPARATOR namespace separator}.
+ * {@code mbean} is the name
+ * of the MBean in that {@code namespace}. This is the name of the MBean
+ * in the namespace's {@link JMXNamespace#getSourceServer() source mbean server}.
+ * It might contain no, one, or several {@link
+ * JMXNamespaces#NAMESPACE_SEPARATOR namespace separators}.
+ * For instance let's assume that some piece of code calls:
+ * Assuming that there is a security manager, or that the
+ * implementation chooses to make checks anyway, the checks that will
+ * be made in that case are:
+ * For any of these MBean servers, if no name was supplied when
+ * creating that MBeanServer the {@link JMXNamespacePermission} is
+ * created with an {@code mbeanServerName} equal to
+ * {@value javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}.
+ * If the namespace {@code a} is in fact a remote {@code MBeanServer},
+ * for instance because namespace {@code a} is implemented by a {@link
+ * JMXRemoteNamespace} pointing to a distant MBeanServer located in
+ * another JMX agent, then checks 2,
+ * 3, and 4 will not
+ * be performed in the local JVM. They might or might not be performed in
+ * the remote agent, depending on how access control and permission
+ * checking are configured in the remote agent, and how authentication
+ * is configured in the connector used by the {@link
+ * JMXRemoteNamespace}.
+ * In all cases, {@linkplain JMXNamespacePermission JMX Namespace Permissions}
+ * are checked as follows: First, if there is no security manager ({@link
+ * System#getSecurityManager()} is null), then an implementation of
+ * of MBeanServer that supports JMX namespaces is free not to make any
+ * checks. Assuming that there is a security manager, or that the
+ * implementation chooses to make checks anyway, the checks are made
+ * as detailed below. If a security check fails, the method throws {@link
+ * SecurityException}. For the {@link MBeanServer#invoke invoke} method, the caller's
+ * permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <operation name>, <namespace>//<mbean>, "invoke")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * For the {@link MBeanServer#getAttribute getAttribute} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <attribute>, <namespace>//<mbean>, "getAttribute")}.
+ * For the {@link MBeanServer#getAttributes getAttributes} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <null>, <namespace>//<mbean>, "getAttribute")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * Additionally, for each attribute att in the {@link
+ * javax.management.AttributeList}, if the caller's permissions do not
+ * imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, att,
+ * <namespace>//<mbean>, "getAttribute")}, the
+ * MBean server will behave as if that attribute had not been in the
+ * supplied list. For the {@link MBeanServer#setAttribute setAttribute} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <attrName>, <namespace>//<mbean>, "setAttribute")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace, and
+ * For the {@link MBeanServer#setAttributes setAttributes} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, "setAttribute")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * Additionally, for each attribute att in the {@link
+ * javax.management.AttributeList}, if the caller's permissions do not
+ * imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, att, <namespace>//<mbean>, "setAttribute")},
+ * the MBean server will behave as if that attribute had not been in the
+ * supplied list. For the For the For the {@link MBeanServer#getMBeanInfo getMBeanInfo} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "getMBeanInfo")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * For the {@link MBeanServer#getObjectInstance getObjectInstance} method,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "getObjectInstance")},
+ * where mbean server name/a> is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * For the {@link MBeanServer#isInstanceOf isInstanceOf} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "isInstanceOf")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * For the {@link MBeanServer#queryMBeans queryMBeans} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, null,
+ * "queryMBeans")}.
+ * Additionally, for each MBean {@code mbean} that matches {@code pattern},
+ * if the caller's permissions do not imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "queryMBeans")}, the
+ * MBean server will behave as if that MBean did not exist. Certain query elements perform operations on the MBean server.
+ * However these operations are usually performed by the MBeanServer at the
+ * bottom of the namespace path, and therefore, do not involve any
+ * {@link JMXNamespacePermission} permission check. They might involve
+ * {@link javax.management.MBeanPermission} checks depending on how security
+ * in the JVM in which the bottom MBeanServer resides is implemented.
+ * See {@link javax.management.MBeanServer} for more details.
+ * For the {@link MBeanServer#queryNames queryNames} method, the checks
+ * are the same as for For the {@link MBeanServer#getClassLoader getClassLoader} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<loaderName>,
+ * "getClassLoader")},
+ * where mbean server name/a> is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * loaderName is the name of the ClassLoader MBean
+ * which is accessed, in that namespace.
+ * For the {@link MBeanServer#getClassLoaderFor getClassLoaderFor} method,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "getClassLoaderFor")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * For the {@link MBeanServer#registerMBean registerMBean} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
+ * "registerMBean")}. Here
+ * For the For the {@link MBeanServer#unregisterMBean unregisterMBean} method,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "unregisterMBean")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which is
+ * being unregistered, relative to that namespace.
+ *
+ *
+ *
+ *
+ * final MBeanServer mbeanServer = ...;
+ * final ObjectName name = new ObjectName("a//b//c//D:k=v");
+ * mbeanServer.getAttribute(name,"Foo");
+ *
+ *
+ *
+ * JMXNamespacePermission(mbeanServerName, "Foo", "a//b//c//D:k=v",
+ * "getAttribute")
+ * (where {@code mbeanServerName=MBeanServerFactory.getMBeanServerName(mbeanServer)},
+ * namespace="a"
, and {@code mbean="b//c//D:k=v"})
+ * JMXNamespacePermission(aSourceServerName,"Foo","b//c//D:k=v",
+ * "getAttribute")}
+ * (where
+ * {@code aSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(a))},
+ * namespace="b"
, and {@code mbean="c//D:k=v"}),
+ * JMXNamespacePermission(bSourceServerName,"Foo","c//D:k=v",
+ * "getAttribute")}
+ * (where
+ * {@code bSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(b))},
+ * namespace="c"
, and {@code mbean="D:k=v"}),
+ *
+ *
+ *
+ * attrName
is {@link javax.management.Attribute#getName()
+ * attribute.getName()}.addNotificationListener
methods,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "addNotificationListener")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * removeNotificationListener
methods,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "removeNotificationListener")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * queryMBeans
except that
+ * "queryNames"
is used instead of
+ * "queryMBeans"
in the JMXNamespacePermission
+ * objects. Note that a "queryMBeans"
permission implies
+ * the corresponding "queryNames"
permission.class name
is the string returned by {@code
+ * obj.getClass().getName()} where {@code obj} is the mbean reference,
+ * is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean which is being
+ * registered, relative to that namespace.
+ *
+ * createMBean
methods, the caller's
+ * permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
+ * "instantiate")} and
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
+ * "registerMBean")}, where
+ * class name
is the string passed as first argument to the {@code
+ * createMBean} method,
+ * mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean which is being
+ * created, relative to that namespace.
+ *
+ *
It must be noted that if all namespaces are local, and all + * local namespaces are implemented by regular MBean servers, that is, there + * are no {@linkplain MBeanServerSupport Virtual Namespaces}, then + * simple {@linkplain javax.management.MBeanPermission MBean Permission} + * checks might be enough to secure an application. + * In that case, it is possible to specify the following {@link + * JMXNamespacePermission} permission in the policy file, which implies all + * other JMX namespace permissions: + *
+ *+ * permission javax.management.namespace.JMXNamespacePermission "*::*[]", "*"; + *+ * + * @since 1.7 + */ +public class JMXNamespace + implements JMXNamespaceMBean, MBeanRegistration { + + /** + * The standard value of the {@code type} + * property key that must be used to construct valid {@link + * JMXNamespaceMBean} ObjectNames.
{@value #TYPE_ASSIGNMENT}
.
+ **/
+ public static final String TYPE_ASSIGNMENT = "type="+TYPE;
+
+ private volatile MBeanServer mbeanServer; // the mbean server in which
+ // this MBean is registered.
+ private volatile ObjectName objectName; // the ObjectName of this MBean.
+ private final MBeanServer sourceServer; // the MBeanServer within = the
+ // name space (or the MBean server
+ // that contains it).
+ private final String uuid;
+
+ /**
+ * Creates a new JMXNamespace implemented by means of an MBean Server.
+ * A namespace is equivalent to an MBeanServer within an MBean Server.
+ * The {@code sourceServer} provided to this constructor is the MBean Server
+ * within.
+ * @param sourceServer the MBean server that implemented by this namespace.
+ * @see #getSourceServer
+ */
+ public JMXNamespace(MBeanServer sourceServer) {
+ this.sourceServer = sourceServer;
+ this.uuid = UUID.randomUUID().toString();
+ }
+
+ /**
+ * This method is part of the {@link MBeanRegistration} interface.
+ * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
+ * interface in order to get a handle to the MBean server in which it is
+ * registered. It also check the validity of its own ObjectName.
+ * + * This method is called by the MBean server. + * Application classes should never call this method directly. + *
+ * If this method is overridden, the overriding method should call + * {@code super.preRegister(server,name)}. + * @see MBeanRegistration#preRegister MBeanRegistration + * @see JMXNamespaces#getNamespaceObjectName getNamespaceObjectName + * @param name The object name of the MBean. name must be a + * syntactically valid JMXNamespace name, as returned by + * {@link JMXNamespaces#getNamespaceObjectName(java.lang.String) + * getNamespaceObjectName(namespace)}. + * @return The name under which the MBean is to be registered. + * @throws IllegalArgumentException if the name supplied is not valid. + * @throws Exception can be thrown by subclasses. + */ + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (objectName != null && ! objectName.equals(name)) + throw new IllegalStateException( + "Already registered under another name: " + objectName); + objectName = validateHandlerName(name); + mbeanServer = server; + return name; + } + + /** + * Validate the ObjectName supplied to preRegister. + * This method is introduced to allow standard subclasses to use + * an alternate naming scheme. For instance - if we want to + * reuse JMXNamespace in order to implement sessions... + * It is however only available for subclasses in this package. + **/ + ObjectName validateHandlerName(ObjectName supliedName) { + if (supliedName == null) + throw new IllegalArgumentException("Must supply a valid name"); + final String dirName = JMXNamespaces. + normalizeNamespaceName(supliedName.getDomain()); + final ObjectName handlerName = + JMXNamespaces.getNamespaceObjectName(dirName); + if (!supliedName.equals(handlerName)) + throw new IllegalArgumentException("invalid name space name: "+ + supliedName); + return supliedName; + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * The {@link JMXNamespace} class uses the {@link MBeanRegistration} + * interface in order to get a handle to the MBean server in which it is + * registered. + *
+ * This method is called by the MBean server. Application classes should + * not call this method directly. Subclasses are free to override this + * method with their own specific behavior - but the overriding method + * shoud still call {@code super.postRegister(registrationDone)}. + * @see MBeanRegistration#postRegister MBeanRegistration + */ + public void postRegister(Boolean registrationDone) { + // nothing to do + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * The {@link JMXNamespace} class uses the {@link MBeanRegistration} + * interface in order to get a handle to the MBean server in which it is + * registered. + *
+ * This method is called by the MBean server. Application classes should + * not call this method directly. Subclasses are free to override this + * method with their own specific behavior - but the overriding method + * shoud still call {@code super.preDeregister()}. + * @see MBeanRegistration#preDeregister MBeanRegistration + */ + public void preDeregister() throws Exception { + // nothing to do + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * It allows the {@code JMXNamespace} MBean to perform any operations + * needed after having been unregistered in the MBean server. + *
+ * This method is called by the MBean server. Application classes should
+ * not call this method directly. If a subclass overrides this
+ * method, the overriding method shoud call {@code super.postDeregister()}.
+ * @see MBeanRegistration#postDeregister MBeanRegistration
+ */
+ public void postDeregister() {
+ mbeanServer = null;
+ objectName = null;
+ }
+
+
+ /**
+ * Returns the MBeanServer in which this MBean is registered,
+ * or null. Chiefly of interest for subclasses.
+ * @return the MBeanServer supplied to {@link #preRegister}.
+ **/
+ public final MBeanServer getMBeanServer() {
+ return mbeanServer;
+ }
+
+ /**
+ * Returns the MBeanServer that contains or emulates the source
+ * namespace. When a JMXNamespace MBean is registered in an
+ * MBean server created through the default {@link
+ * javax.management.MBeanServerBuilder}, the MBeanServer will
+ * check {@link JMXNamespacePermission} before invoking
+ * any method on the source MBeanServer of the JMXNamespace.
+ * See JMX Namespace Permission Checks
+ * above.
+ * @return an MBeanServer view of the source namespace
+ **/
+ public MBeanServer getSourceServer() {
+ return sourceServer;
+ }
+
+ /**
+ * Returns the ObjectName with which this MBean was registered,
+ * or null. Chiefly of interest for subclasses.
+ * @return the ObjectName supplied to {@link #preRegister}.
+ **/
+ public final ObjectName getObjectName() {
+ return objectName;
+ }
+
+ /**
+ * HandlerName used in traces.
+ **/
+ String getHandlerName() {
+ final ObjectName name = getObjectName();
+ if (name != null) return name.toString();
+ return this.toString();
+ }
+
+ /**
+ * In this class, this method returns {@link #getSourceServer
+ * getSourceServer()}.{@link javax.management.MBeanServer#getMBeanCount
+ * getMBeanCount()}.
+ *
This default behaviour may be redefined in subclasses.
+ * @throws java.io.IOException can be thrown by subclasses.
+ */
+ public Integer getMBeanCount() throws IOException {
+ return getSourceServer().getMBeanCount();
+ }
+
+ /**
+ * In this class, this method returns {@link #getSourceServer
+ * getSourceServer()}.{@link javax.management.MBeanServer#getDomains
+ * getDomains()}.
+ *
This default behaviour may be redefined in subclasses.
+ * @throws java.io.IOException can be thrown by subclasses.
+ */
+ public String[] getDomains() throws IOException {
+ return getSourceServer().getDomains();
+ }
+
+ /**
+ * In this class, this method returns {@link #getSourceServer
+ * getSourceServer()}.{@link javax.management.MBeanServer#getDefaultDomain
+ * getDefaultDomain()}.
+ *
This default behaviour may be redefined in subclasses.
+ * @throws java.io.IOException can be thrown by subclasses.
+ */
+ public String getDefaultDomain() throws IOException {
+ return getSourceServer().getDefaultDomain();
+ }
+
+ public final String getUUID() {
+ return uuid;
+ }
+
+}
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.namespace;
+
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * A {@link JMXNamespace} is an MBean that handles a name space in the
+ * MBeanServer hierarchical name space.
+ * @see JMXNamespace
+ * @since 1.7
+ */
+public interface JMXNamespaceMBean {
+
+ // Note: since getDomains(), getDefaultDomain(), and getMBeanCount()
+ // don't take any ObjectName parameters, the only efficient way
+ // to get these data is to call the corresponding method on the
+ // JMXNamespaceMBean that handles the name space.
+ //
+ // We need these methods to implement 'cd' (JMXNamespaces.narrowToNamespace)
+ // correctly.
+ //
+
+ /**
+ * Returns the list of domains currently implemented in the name space
+ * handled by this {@link JMXNamespace}.
+ * @throws IOException if the domain list cannot be obtained due to
+ * I/O problems (communication failures etc...).
+ * @return the list of domains currently implemented in the name space
+ * handled by this {@link JMXNamespace}.
+ * @see javax.management.MBeanServerConnection#getDomains
+ * MBeanServerConnection.getDomains
+ **/
+ public String[] getDomains() throws IOException;
+
+ /**
+ * Returns the default domain for the name space handled by
+ * this {@link JMXNamespace}.
+ * @throws IOException if the default domain cannot be obtained due to
+ * I/O problems (communication failures etc...).
+ * @return the default domain for the name space handled by
+ * this {@link JMXNamespace}.
+ * @see javax.management.MBeanServerConnection#getDefaultDomain
+ * MBeanServerConnection.getDefaultDomain
+ **/
+ public String getDefaultDomain() throws IOException;
+
+ /**
+ * Returns the number of MBeans registered in the name space handled by
+ * this {@link JMXNamespace}.
+ *
+ * @return the number of MBeans registered in the name space handled by
+ * this {@link JMXNamespace}.
+ *
+ * @throws IOException if the MBean count cannot be obtained due to
+ * I/O problems (communication failures etc...).
+ * @see javax.management.MBeanServerConnection#getMBeanCount
+ * MBeanServerConnection.getMBeanCount
+ */
+ public Integer getMBeanCount() throws IOException;
+
+ /**
+ * Returns a {@link java.util.UUID UUID string} which uniquely identifies
+ * this {@linkplain JMXNamespace} MBean.
+ * This information can be used to detect loops in the JMX name space graph.
+ * @return A unique ID identifying this MBean.
+ * @throws IOException if the MBean UUID cannot be obtained due to
+ * I/O problems (communication failures etc...).
+ */
+ public String getUUID() throws IOException;
+
+}
diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/namespace/JMXNamespacePermission.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespacePermission.java Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,1474 @@
+/*
+ * Copyright 2002-2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.namespace;
+
+import javax.management.*;
+import com.sun.jmx.mbeanserver.Util;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.security.Permission;
+
+/**
+ *
A permission controlling access to MBeans located in namespaces. + * If a security manager has been set using {@link + * System#setSecurityManager}, most operations on an MBean mounted in a + * namespace require that the caller's permissions imply a + * JMXNamespacePermission appropriate for the operation. + * This is described in detail in the + * documentation for the + * JMXNamespace + * class.
+ * + *As with other {@link Permission} objects, + * a JMXNamespacePermission can represent either a permission that + * you have or a permission that you need. + * When a sensitive operation is being checked for permission, + * a JMXNamespacePermission is constructed + * representing the permission you need. The operation is only + * allowed if the permissions you have {@linkplain #implies imply} the + * permission you need.
+ * + *A JMXNamespacePermission contains four items of information:
+ * + *The action.
+ *For a permission you need,
+ * this is one of the actions in the list below. For a permission you have, this is
+ * a comma-separated list of those actions, or *
,
+ * representing all actions.
The action is returned by {@link #getActions()}.
+ * + *The MBean Server name.
+ * + *For a permission you need, this is the {@linkplain + * javax.management.MBeanServerFactory#getMBeanServerName + * name of the MBeanServer} + * from which the MBean is accessed.
+ * + *For a permission you have, this is either the {@linkplain
+ * javax.management.MBeanServerFactory#getMBeanServerName
+ * name of the MBeanServer} from which the MBean
+ * for which you have this permission is accessed,
+ * or a pattern against which that MBean Server name will be matched.
+ * An {@code mbeanServername} pattern can also be empty, or the single
+ * character {@code "*"}, both of which match any {@code MBeanServer} name.
+ * The string {@code "-"} doesn't match any MBeanServer name.
+ *
Example:
+ *+ * // grant permission to invoke the operation "stop" on any MBean + * // whose name matches "a//**//*:type=JMXConnectorServer" when + * // accessed from any MBeanServer whose name matches myapp.*" + * permission javax.management.namespace.JMXNamespacePermission "myapp.*::stop[a//**//*:type=JMXConnectorServer]", "invoke"; + *+ * + *
The member.
+ * + *For a permission you need, this is the name of the attribute or + * operation you are accessing. For operations that do not reference + * an attribute or operation, the member is null.
+ * + *For a permission you have, this is either the name of an attribute
+ * or operation you can access, or it is empty or the single character
+ * "*
", both of which grant access to any member.
There is a special case for actions {@code registerMBean} and + * {@code instantiate}, where for a permission you need, {@code member} + * indicates the name of the class for which you are trying + * to create, instantiate, or register an MBean instance. For a + * permission you have, it is a pattern that will be matched against + * the full class name of the MBean being created, instantiated, or + * registered. + *
+ * + * + *The object name.
+ * + *For a permission you need, this is the {@link ObjectName} of the
+ * MBean you are accessing. It is of the form {@code
+ * For operations that do not reference a
+ * single MBean, the object name is null. It is never an object
+ * name pattern.
+ *
For a permission you have, this is the {@link ObjectName} of the
+ * MBean or MBeans you can access. It is of the form
+ * {@code **
matches any number of sub namespaces
+ * recursively, but only if used as a complete namespace path element,
+ * as in **//b//c//D:k=v
or a//**//c//D:k=v
+ * - see below.
+ *
If you have a JMXNamespacePermission, it allows operations only + * if all four of the items match.
+ * + *The MBeanServer name, + * member, and object name + * can be written together + * as a single string, which is the name of this permission. + * The name of the permission is the string returned by {@link + * java.security.Permission#getName() getName()}. + * The format of the string is:
+ * + *+ * {@code+ * + *:: [ // ]} + *
+ * The {@code
+ * {@code *::+ *[ // ]}
+ * {@code ::[ // ]}
+ * {@code[ // ]}
+ *
+ * The {@code ?
will match any single
+ * character, and *
will match any sequence of characters,
+ * except {@value
+ * javax.management.namespace.JMXNamespaces#NAMESPACE_SEPARATOR}
+ * In addition, when included in a namespace path the special
+ * path element **
matches any number of sub namespaces
+ * recursively.
+ * A {@code **//*:*
thus means that the permission is
+ * granted for all MBeans in all namespaces, recursively (see
+ * below for more details.
+ *
Namespace permission checking may be tricky to configure, depending
+ * on whether the namespaces crossed to reach the MBean are local or
+ * remote.
+ * For instance, let a//b//D:k=v
be an MBean exposing an
+ * attribute Foo
.
+ * If namespace a
is a plain JMXNamespace pointing to
+ * a local MBeanServer in the same JVM, then the permissions you need
+ * to get the attribute Foo
will be:
+ *
+ * // granting permission to access attribute 'Foo' of MBean a//b//D:k=v + * // from MBeanServer named 'srv1' + * // This permission will be checked by the MBeanServer that contains 'a'. + * srv1::Foo[a//b//D:k=v] + * + * // Since a is local, you also need the following additional permission, + * // which will be checked by the MBeanServer 'srv2' that contains 'b': + * // + * // granting permission to access attribute 'Foo' of MBean b//D:k=v from + * // 'srv2' + * srv2::Foo[b//D:k=v] + *+ *
On the other hand, if namespace a
is a JMXRemoteNamespace
+ * pointing to an MBeanServer in a remote JVM, then the only permission you
+ * need to get the attribute Foo
will be:
+ *
+ * // granting permission to access attribute 'Foo' of MBean a//b//D:k=v + * // from 'srv1' + * srv1::Foo[a//b//D:k=v] + *+ *
The namespace b
resides in the remote JVM, and
+ * therefore the permissions concerning access to MBeans from
+ * namespace 'b' will only be checked in the remote JVM, if that JVM is
+ * configured to do so.
+ *
The {@code ]
. It is terminated by a ]
character
+ * that is the last character in the string.
+ *
Below are some examples of permission names:
+ *+ * // allows access to Foo in 'a//b//*:*' from any MBeanServer in the JVM. + * Foo[a//b//*:*] + * + * // allows access to Foo in all subnamespaces of 'a//b', but only for + * // MBeanServers whose name matches 'myapp.*' + * myapp.*::Foo[a//b//**//*:*] + * + * // allows access to Foo from all namespaces in the MBeanServer named + * // 'myapp.srv1' - but not recursively. + * myapp.srv1::Foo[*//*:*] + *+ *
For instance, the first two permissions listed above + * will let through {@code getAttribute("a//b//D:k=v","Foo");} in + * all MBeanServers, but will block access to + * {@code getAttribute("a//b//c//D:k=v","Foo");} in MBeanServers whose + * name do not start with {@code "myapp."}. + *
+ * + *+ * // allows access to Foo in all namespaces, recursively. + * // + * *::Foo[**//*:*] + * + * // This permission name is the equivalent to the permission names above: + * // Foo[**//*:*] and Foo[] are equivalent. + * // + * Foo[] + * + * // This permission name is the equivalent to the two permission names + * // above: + * // Foo[**//*:*], Foo[], Foo are equivalent. + * // + * Foo + * + * // allows access to Foo from all namespaces - but not recursively. + * // This wildcard permission complements the previous one: it allows + * // access to 'Foo' from an MBean directly registered in any local namespace. + * // + * Foo[*//*:*] + * + *+ *
Note on wildcards: In an object name pattern, a path element
+ * of exactly **
corresponds to a meta
+ * wildcard that will match any number of sub namespaces. Hence:
pattern | matches | doesn't match | + * + *
---|---|---|
**//D:k=v |
+ * a//D:k=v + * a//b//D:k=v + * a//b//c//D:k=v |
+ * D:k=v |
a//**//D:k=v |
+ * a//b//D:k=v + * a//b//c//D:k=v |
+ * b//b//c//D:k=v + * a//D:k=v + * D:k=v |
a//**//e//D:k=v |
+ * a//b//e//D:k=v + * a//b//c//e//D:k=v |
+ * a//b//c//c//D:k=v + * b//b//c//e//D:k=v + * a//e//D:k=v + * e//D:k=v |
a//b**//e//D:k=v |
+ * a//b//e//D:k=v |
+ * a//b//c//e//D:k=v + * because in that case b** + * is not a meta-wildcard - and b** + * is thus equivalent to b* . |
If {@code member
or object name
may be omitted.
+ * If the object name
is omitted,
+ * the []
may be too (but does not have to be). It is
+ * not legal to omit all items, that is to have a name
+ * which is the empty string.
If {@code
+ * One or more of the MBean Server name,
+ * member
+ * or object name may be the character "-
",
+ * which is equivalent to a null value. A null value is implied by
+ * any value (including another null value) but does not imply any
+ * other value.
+ *
The possible actions are these:
+ * + *In a comma-separated list of actions, spaces are allowed before + * and after each action.
+ * + * @since 1.7 + */ +public class JMXNamespacePermission extends Permission { + + private static final long serialVersionUID = -2416928705275160661L; + + private static final String WILDPATH = "**" + + JMXNamespaces.NAMESPACE_SEPARATOR + "*"; + + /** + * Actions list. + */ + private static final int AddNotificationListener = 0x00001; + private static final int GetAttribute = 0x00002; + private static final int GetClassLoader = 0x00004; + private static final int GetClassLoaderFor = 0x00008; + private static final int GetClassLoaderRepository = 0x00010; + // No GetDomains because it is not possible to route a call to + // getDomains() on a NamespaceInterceptor - getDomains() doesn't + // have any ObjectName. + // private static final int GetDomains = 0x00020; + private static final int GetMBeanInfo = 0x00040; + private static final int GetObjectInstance = 0x00080; + private static final int Instantiate = 0x00100; + private static final int Invoke = 0x00200; + private static final int IsInstanceOf = 0x00400; + private static final int QueryMBeans = 0x00800; + private static final int QueryNames = 0x01000; + private static final int RegisterMBean = 0x02000; + private static final int RemoveNotificationListener = 0x04000; + private static final int SetAttribute = 0x08000; + private static final int UnregisterMBean = 0x10000; + + /** + * No actions. + */ + private static final int NONE = 0x00000; + + /** + * All actions. + */ + // No GetDomains because it is not possible to route a call to + // getDomains() on a NamespaceInterceptor - getDomains() doesn't + // have any ObjectName. + // + private static final int ALL = + AddNotificationListener | + GetAttribute | + GetClassLoader | + GetClassLoaderFor | + GetClassLoaderRepository | + GetMBeanInfo | + GetObjectInstance | + Instantiate | + Invoke | + IsInstanceOf | + QueryMBeans | + QueryNames | + RegisterMBean | + RemoveNotificationListener | + SetAttribute | + UnregisterMBean; + + /** + * The actions string. + */ + private String actions; + + /** + * The actions mask. + */ + private transient int mask; + + /** + * The name of the MBeanServer in which this permission is checked, or + * granted. If null, is implied by any MBean server name + * but does not imply any non-null MBean server name. + */ + private transient String mbeanServerName; + + /** + * The member that must match. If null, is implied by any member + * but does not imply any non-null member. + */ + private transient String member; + + /** + * The objectName that must match. If null, is implied by any + * objectName but does not imply any non-null objectName. + */ + private transient ObjectName objectName; + + /** + * If objectName is missing from name, then allnames will be + * set to true. + */ + private transient boolean allnames = false; + + /** + * Parseactions
parameter.
+ */
+ private void parseActions() {
+
+ int amask;
+
+ if (actions == null)
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
+ "actions can't be null");
+ if (actions.equals(""))
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
+ "actions can't be empty");
+
+ amask = getMask(actions);
+
+ if ((amask & ALL) != amask)
+ throw new IllegalArgumentException("Invalid actions mask");
+ if (amask == NONE)
+ throw new IllegalArgumentException("Invalid actions mask");
+ this.mask = amask;
+ }
+
+ /**
+ * Parse name
parameter.
+ */
+ private void parseName() {
+ String name = getName();
+
+ if (name == null)
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission name " +
+ "cannot be null");
+
+ if (name.equals(""))
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission name " +
+ "cannot be empty");
+ final int sepIndex = name.indexOf("::");
+ if (sepIndex < 0) {
+ setMBeanServerName("*");
+ } else {
+ setMBeanServerName(name.substring(0,sepIndex));
+ }
+
+ /* The name looks like "mbeanServerName::member[objectname]".
+ We subtract elements from the right as we parse, so after
+ parsing the objectname we have "class#member" and after parsing the
+ member we have "class". Each element is optional. */
+
+ // Parse ObjectName
+
+ final int start = (sepIndex<0)?0:sepIndex+2;
+ int openingBracket = name.indexOf("[",start);
+ if (openingBracket == -1) {
+ // If "[on]" missing then ObjectName("*:*")
+ //
+ objectName = null;
+ allnames = true;
+ openingBracket=name.length();
+ } else {
+ if (!name.endsWith("]")) {
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
+ "The ObjectName in the " +
+ "target name must be " +
+ "included in square " +
+ "brackets");
+ } else {
+ // Create ObjectName
+ //
+ String on = name.substring(openingBracket + 1,
+ name.length() - 1);
+ try {
+ // If "[]" then allnames are implied
+ //
+ final ObjectName target;
+ final boolean all;
+ if (on.equals("")) {
+ target = null;
+ all = true;
+ } else if (on.equals("-")) {
+ target = null;
+ all = false;
+ } else {
+ target = new ObjectName(on);
+ all = false;
+ }
+ setObjectName(target,all);
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalArgumentException(
+ "JMXNamespaceAccessPermission: " +
+ "The target name does " +
+ "not specify a valid " +
+ "ObjectName", e);
+ }
+ }
+ }
+
+ final String memberName = name.substring(start,openingBracket);
+ setMember(memberName);
+ }
+
+ private void setObjectName(ObjectName target, boolean all) {
+ if (target != null &&
+ !Util.wildpathmatch(target.getDomain(), WILDPATH)) {
+ throw new IllegalArgumentException(
+ "The target name does not contain " +
+ "any namespace: "+String.valueOf(target));
+ } else if (target != null) {
+ final String domain = target.getDomain();
+ final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length();
+ final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR);
+ if (sepc < 0 || (sepc+seplen)==domain.length()) {
+ throw new IllegalArgumentException(String.valueOf(target)+
+ ": no namespace in domain");
+ }
+ }
+ objectName = target;
+ allnames = all;
+ }
+
+ /**
+ * Assign fields based on className, member, and objectName
+ * parameters.
+ */
+// private void initName(String namespaceName, String member,
+// ObjectName objectName, boolean allnames) {
+// setNamespace(namespaceName);
+ private void initName(String mbeanServerName, String member,
+ ObjectName mbeanName, boolean all) {
+ setMBeanServerName(mbeanServerName);
+ setMember(member);
+ setObjectName(mbeanName, all);
+ }
+
+ private void setMBeanServerName(String mbeanServerName) {
+ if (mbeanServerName == null || mbeanServerName.equals("-")) {
+ this.mbeanServerName = null;
+ } else if (mbeanServerName.equals("")) {
+ this.mbeanServerName = "*";
+ } else {
+ this.mbeanServerName = mbeanServerName;
+ }
+ }
+
+ private void setMember(String member) {
+ if (member == null || member.equals("-"))
+ this.member = null;
+ else if (member.equals(""))
+ this.member = "*";
+ else
+ this.member = member;
+ }
+
+ /**
+ * Create a new JMXNamespacePermission object with the + * specified target name and actions.
+ * + *The target name is of the form
+ * "mbeanServerName::member[objectName]
" where each part is
+ * optional. This target name must not be empty or null.
+ * If objectName
is present, it is of
+ * the form namespace//MBeanName
.
+ *
+ * For a permission you need, {@code mbeanServerName} is the + * name of the MBeanServer from + * which {@code objectName} is being accessed. + *
+ *+ * For a permission you have, {@code mbeanServerName} is the + * name of the MBeanServer from + * which access to {@code objectName} is granted. + * It can also be a pattern, and if omitted, {@code "*"} is assumed, + * meaning that access to {@code objectName} is granted in all + * MBean servers in the JVM. + *
+ * + *The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param name the triplet "mbeanServerName::member[objectName]". + * IfobjectName
is present, it is of
+ * the form namespace//MBeanName
.
+ * @param actions the action string.
+ *
+ * @exception IllegalArgumentException if the name
or
+ * actions
is invalid.
+ */
+ public JMXNamespacePermission(String name, String actions) {
+ super(name);
+
+ parseName();
+
+ this.actions = actions;
+ parseActions();
+ }
+
+ /**
+ * Create a new JMXNamespacePermission object with the specified + * target name (namespace name, member, object name) and actions.
+ * + *The {@code MBeanServer} name, member and object name
+ * parameters define a target name of the form
+ * "mbeanServerName::member[objectName]
" where each
+ * part is optional. This will be the result of {@link #getName()} on the
+ * resultant JMXNamespacePermission.
+ * If the mbeanServerName
is empty or exactly {@code "*"}, then
+ * "{@code mbeanServerName::}" is omitted in that result.
+ *
The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param mbeanServerName the name of the {@code MBeanServer} to which this + * permission applies. + * May be null or"-"
, which represents an MBeanServer name
+ * that is implied by any MBeanServer name but does not imply any other
+ * MBeanServer name.
+ * @param member the member to which this permission applies. May
+ * be null or "-"
, which represents a member that is
+ * implied by any member but does not imply any other member.
+ * @param objectName the object name to which this permission
+ * applies.
+ * May be null, which represents an object name that is
+ * implied by any object name but does not imply any other object
+ * name. If not null, the {@code objectName} must be of the
+ * form {@code Create a new JMXNamespacePermission object with the specified + * MBean Server name, member, and actions.
+ * + *The {@code MBeanServer} name and member
+ * parameters define a target name of the form
+ * "mbeanServerName::member[]
" where each
+ * part is optional. This will be the result of {@link #getName()} on the
+ * resultant JMXNamespacePermission.
+ * If the mbeanServerName
is empty or exactly {@code "*"}, then
+ * "{@code mbeanServerName::}" is omitted in that result.
+ *
The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param mbeanServerName the name of the {@code MBeanServer} to which this + * permission applies. + * May be null or"-"
, which represents an MBeanServer name
+ * that is implied by any MBeanServer name but does not imply any other
+ * MBeanServer name.
+ * @param member the member to which this permission applies. May
+ * be null or "-"
, which represents a member that is
+ * implied by any member but does not imply any other member.
+ * @param actions the action string.
+ */
+ public JMXNamespacePermission(String mbeanServerName,
+ String member,
+ String actions) {
+ this(mbeanServerName,member,null,true,actions);
+ // this(member,null,allnames,actions);
+ }
+
+ /**
+ * Create a new JMXNamespacePermission object with the specified + * target name (namespace name, member, object name) and actions.
+ * + *The MBean Server name, member and object name parameters define a
+ * target name of the form
+ * "mbeanServerName::member[objectName]
" where each part is
+ * optional. This will be the result of {@link
+ * java.security.Permission#getName() getName()} on the
+ * resultant JMXNamespacePermission.
The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param mbeanServerName the name of the {@code MBeanServer} to which this + * permission applies. + * May be null or"-"
, which represents an MBeanServer name
+ * that is implied by any MBeanServer name but does not imply any other
+ * MBeanServer name.
+ * @param member the member to which this permission applies. May
+ * be null or "-"
, which represents a member that is
+ * implied by any member but does not imply any other member.
+ * @param objectName the object name to which this permission
+ * applies. If null, and allnames is false, represents an object
+ * name that is implied by any object name but does not imply any
+ * other object name. Otherwise, if allnames is true, it represents
+ * a meta wildcard that matches all object names. It is equivalent to
+ * a missing objectName ("[]") in the {@link
+ * java.security.Permission#getName() name} property.
+ * @param allnames represent a meta wildcard indicating that the
+ * objectName was not specified. This implies all objectnames
+ * that match "*:*" and all object names that match
+ * "**//*:*"
+ * @param actions the action string.
+ */
+ private JMXNamespacePermission(String mbeanServerName,
+ String member,
+ ObjectName objectName,
+ boolean allnames,
+ String actions) {
+
+ super(makeName(mbeanServerName,
+ member, objectName, allnames));
+ initName(mbeanServerName,
+ member, objectName, allnames);
+
+ this.actions = actions;
+ parseActions();
+ }
+
+ private static String makeName(String mbeanServerName,
+ String memberName, ObjectName objName, boolean allMBeans) {
+ final StringBuilder name = new StringBuilder();
+ if (mbeanServerName == null)
+ mbeanServerName = "-";
+ if (!mbeanServerName.equals("") && !mbeanServerName.equals("*"))
+ name.append(mbeanServerName).append("::");
+ if (memberName == null)
+ memberName = "-";
+ name.append(memberName);
+ if (objName == null) {
+ if (allMBeans)
+ name.append("[]");
+ else
+ name.append("[-]");
+ } else {
+ final String domain = objName.getDomain();
+ final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length();
+ final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR);
+ if (sepc < 0 || (sepc+seplen)==domain.length()) {
+ throw new IllegalArgumentException(String.valueOf(objName)+
+ ": no namespace in domain");
+ }
+ final String can = objName.getCanonicalName();
+ name.append("[").append(can).append("]");
+ }
+ return name.toString();
+ }
+
+ /**
+ * Returns the "canonical string representation" of the actions. That is,
+ * this method always returns actions in alphabetical order.
+ *
+ * @return the canonical string representation of the actions.
+ */
+ public String getActions() {
+
+ if (actions == null)
+ actions = getActions(this.mask);
+
+ return actions;
+ }
+
+ /**
+ * Returns the "canonical string representation"
+ * of the actions from the mask.
+ */
+ private static String getActions(int mask) {
+ final StringBuilder sb = new StringBuilder();
+ boolean comma = false;
+
+ if ((mask & AddNotificationListener) == AddNotificationListener) {
+ comma = true;
+ sb.append("addNotificationListener");
+ }
+
+ if ((mask & GetAttribute) == GetAttribute) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getAttribute");
+ }
+
+ if ((mask & GetClassLoader) == GetClassLoader) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getClassLoader");
+ }
+
+ if ((mask & GetClassLoaderFor) == GetClassLoaderFor) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getClassLoaderFor");
+ }
+
+ if ((mask & GetClassLoaderRepository) == GetClassLoaderRepository) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getClassLoaderRepository");
+ }
+
+ if ((mask & GetMBeanInfo) == GetMBeanInfo) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getMBeanInfo");
+ }
+
+ if ((mask & GetObjectInstance) == GetObjectInstance) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getObjectInstance");
+ }
+
+ if ((mask & Instantiate) == Instantiate) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("instantiate");
+ }
+
+ if ((mask & Invoke) == Invoke) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("invoke");
+ }
+
+ if ((mask & IsInstanceOf) == IsInstanceOf) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("isInstanceOf");
+ }
+
+ if ((mask & QueryMBeans) == QueryMBeans) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("queryMBeans");
+ }
+
+ if ((mask & QueryNames) == QueryNames) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("queryNames");
+ }
+
+ if ((mask & RegisterMBean) == RegisterMBean) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("registerMBean");
+ }
+
+ if ((mask & RemoveNotificationListener) == RemoveNotificationListener) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("removeNotificationListener");
+ }
+
+ if ((mask & SetAttribute) == SetAttribute) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("setAttribute");
+ }
+
+ if ((mask & UnregisterMBean) == UnregisterMBean) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("unregisterMBean");
+ }
+
+ // No GetDomains because it is not possible to route a call to
+ // getDomains() on a NamespaceInterceptor - getDomains() doesn't
+ // have any ObjectName.
+
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return this.getName().hashCode() + this.getActions().hashCode();
+ }
+
+ /**
+ * Converts an action String to an integer action mask.
+ *
+ * @param action the action string.
+ * @return the action mask.
+ */
+ private static int getMask(String action) {
+
+ /*
+ * BE CAREFUL HERE! PARSING ORDER IS IMPORTANT IN THIS ALGORITHM.
+ *
+ * The 'string length' test must be performed for the lengthiest
+ * strings first.
+ *
+ * In this permission if the "unregisterMBean" string length test is
+ * performed after the "registerMBean" string length test the algorithm
+ * considers the 'unregisterMBean' action as being the 'registerMBean'
+ * action and a parsing error is returned.
+ */
+
+ int mask = NONE;
+
+ if (action == null) {
+ return mask;
+ }
+
+ if (action.equals("*")) {
+ return ALL;
+ }
+
+ char[] a = action.toCharArray();
+
+ int i = a.length - 1;
+ if (i < 0)
+ return mask;
+
+ while (i != -1) {
+ char c;
+
+ // skip whitespace
+ while ((i!=-1) && ((c = a[i]) == ' ' ||
+ c == '\r' ||
+ c == '\n' ||
+ c == '\f' ||
+ c == '\t'))
+ i--;
+
+ // check for the known strings
+ int matchlen;
+
+ // No GetDomains because it is not possible to route a call to
+ // getDomains() on a NamespaceInterceptor - getDomains() doesn't
+ // have any ObjectName.
+
+ if (i >= 25 && /* removeNotificationListener */
+ (a[i-25] == 'r') &&
+ (a[i-24] == 'e') &&
+ (a[i-23] == 'm') &&
+ (a[i-22] == 'o') &&
+ (a[i-21] == 'v') &&
+ (a[i-20] == 'e') &&
+ (a[i-19] == 'N') &&
+ (a[i-18] == 'o') &&
+ (a[i-17] == 't') &&
+ (a[i-16] == 'i') &&
+ (a[i-15] == 'f') &&
+ (a[i-14] == 'i') &&
+ (a[i-13] == 'c') &&
+ (a[i-12] == 'a') &&
+ (a[i-11] == 't') &&
+ (a[i-10] == 'i') &&
+ (a[i-9] == 'o') &&
+ (a[i-8] == 'n') &&
+ (a[i-7] == 'L') &&
+ (a[i-6] == 'i') &&
+ (a[i-5] == 's') &&
+ (a[i-4] == 't') &&
+ (a[i-3] == 'e') &&
+ (a[i-2] == 'n') &&
+ (a[i-1] == 'e') &&
+ (a[i] == 'r')) {
+ matchlen = 26;
+ mask |= RemoveNotificationListener;
+ } else if (i >= 23 && /* getClassLoaderRepository */
+ (a[i-23] == 'g') &&
+ (a[i-22] == 'e') &&
+ (a[i-21] == 't') &&
+ (a[i-20] == 'C') &&
+ (a[i-19] == 'l') &&
+ (a[i-18] == 'a') &&
+ (a[i-17] == 's') &&
+ (a[i-16] == 's') &&
+ (a[i-15] == 'L') &&
+ (a[i-14] == 'o') &&
+ (a[i-13] == 'a') &&
+ (a[i-12] == 'd') &&
+ (a[i-11] == 'e') &&
+ (a[i-10] == 'r') &&
+ (a[i-9] == 'R') &&
+ (a[i-8] == 'e') &&
+ (a[i-7] == 'p') &&
+ (a[i-6] == 'o') &&
+ (a[i-5] == 's') &&
+ (a[i-4] == 'i') &&
+ (a[i-3] == 't') &&
+ (a[i-2] == 'o') &&
+ (a[i-1] == 'r') &&
+ (a[i] == 'y')) {
+ matchlen = 24;
+ mask |= GetClassLoaderRepository;
+ } else if (i >= 22 && /* addNotificationListener */
+ (a[i-22] == 'a') &&
+ (a[i-21] == 'd') &&
+ (a[i-20] == 'd') &&
+ (a[i-19] == 'N') &&
+ (a[i-18] == 'o') &&
+ (a[i-17] == 't') &&
+ (a[i-16] == 'i') &&
+ (a[i-15] == 'f') &&
+ (a[i-14] == 'i') &&
+ (a[i-13] == 'c') &&
+ (a[i-12] == 'a') &&
+ (a[i-11] == 't') &&
+ (a[i-10] == 'i') &&
+ (a[i-9] == 'o') &&
+ (a[i-8] == 'n') &&
+ (a[i-7] == 'L') &&
+ (a[i-6] == 'i') &&
+ (a[i-5] == 's') &&
+ (a[i-4] == 't') &&
+ (a[i-3] == 'e') &&
+ (a[i-2] == 'n') &&
+ (a[i-1] == 'e') &&
+ (a[i] == 'r')) {
+ matchlen = 23;
+ mask |= AddNotificationListener;
+ } else if (i >= 16 && /* getClassLoaderFor */
+ (a[i-16] == 'g') &&
+ (a[i-15] == 'e') &&
+ (a[i-14] == 't') &&
+ (a[i-13] == 'C') &&
+ (a[i-12] == 'l') &&
+ (a[i-11] == 'a') &&
+ (a[i-10] == 's') &&
+ (a[i-9] == 's') &&
+ (a[i-8] == 'L') &&
+ (a[i-7] == 'o') &&
+ (a[i-6] == 'a') &&
+ (a[i-5] == 'd') &&
+ (a[i-4] == 'e') &&
+ (a[i-3] == 'r') &&
+ (a[i-2] == 'F') &&
+ (a[i-1] == 'o') &&
+ (a[i] == 'r')) {
+ matchlen = 17;
+ mask |= GetClassLoaderFor;
+ } else if (i >= 16 && /* getObjectInstance */
+ (a[i-16] == 'g') &&
+ (a[i-15] == 'e') &&
+ (a[i-14] == 't') &&
+ (a[i-13] == 'O') &&
+ (a[i-12] == 'b') &&
+ (a[i-11] == 'j') &&
+ (a[i-10] == 'e') &&
+ (a[i-9] == 'c') &&
+ (a[i-8] == 't') &&
+ (a[i-7] == 'I') &&
+ (a[i-6] == 'n') &&
+ (a[i-5] == 's') &&
+ (a[i-4] == 't') &&
+ (a[i-3] == 'a') &&
+ (a[i-2] == 'n') &&
+ (a[i-1] == 'c') &&
+ (a[i] == 'e')) {
+ matchlen = 17;
+ mask |= GetObjectInstance;
+ } else if (i >= 14 && /* unregisterMBean */
+ (a[i-14] == 'u') &&
+ (a[i-13] == 'n') &&
+ (a[i-12] == 'r') &&
+ (a[i-11] == 'e') &&
+ (a[i-10] == 'g') &&
+ (a[i-9] == 'i') &&
+ (a[i-8] == 's') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 'e') &&
+ (a[i-5] == 'r') &&
+ (a[i-4] == 'M') &&
+ (a[i-3] == 'B') &&
+ (a[i-2] == 'e') &&
+ (a[i-1] == 'a') &&
+ (a[i] == 'n')) {
+ matchlen = 15;
+ mask |= UnregisterMBean;
+ } else if (i >= 13 && /* getClassLoader */
+ (a[i-13] == 'g') &&
+ (a[i-12] == 'e') &&
+ (a[i-11] == 't') &&
+ (a[i-10] == 'C') &&
+ (a[i-9] == 'l') &&
+ (a[i-8] == 'a') &&
+ (a[i-7] == 's') &&
+ (a[i-6] == 's') &&
+ (a[i-5] == 'L') &&
+ (a[i-4] == 'o') &&
+ (a[i-3] == 'a') &&
+ (a[i-2] == 'd') &&
+ (a[i-1] == 'e') &&
+ (a[i] == 'r')) {
+ matchlen = 14;
+ mask |= GetClassLoader;
+ } else if (i >= 12 && /* registerMBean */
+ (a[i-12] == 'r') &&
+ (a[i-11] == 'e') &&
+ (a[i-10] == 'g') &&
+ (a[i-9] == 'i') &&
+ (a[i-8] == 's') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 'e') &&
+ (a[i-5] == 'r') &&
+ (a[i-4] == 'M') &&
+ (a[i-3] == 'B') &&
+ (a[i-2] == 'e') &&
+ (a[i-1] == 'a') &&
+ (a[i] == 'n')) {
+ matchlen = 13;
+ mask |= RegisterMBean;
+ } else if (i >= 11 && /* getAttribute */
+ (a[i-11] == 'g') &&
+ (a[i-10] == 'e') &&
+ (a[i-9] == 't') &&
+ (a[i-8] == 'A') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 't') &&
+ (a[i-5] == 'r') &&
+ (a[i-4] == 'i') &&
+ (a[i-3] == 'b') &&
+ (a[i-2] == 'u') &&
+ (a[i-1] == 't') &&
+ (a[i] == 'e')) {
+ matchlen = 12;
+ mask |= GetAttribute;
+ } else if (i >= 11 && /* getMBeanInfo */
+ (a[i-11] == 'g') &&
+ (a[i-10] == 'e') &&
+ (a[i-9] == 't') &&
+ (a[i-8] == 'M') &&
+ (a[i-7] == 'B') &&
+ (a[i-6] == 'e') &&
+ (a[i-5] == 'a') &&
+ (a[i-4] == 'n') &&
+ (a[i-3] == 'I') &&
+ (a[i-2] == 'n') &&
+ (a[i-1] == 'f') &&
+ (a[i] == 'o')) {
+ matchlen = 12;
+ mask |= GetMBeanInfo;
+ } else if (i >= 11 && /* isInstanceOf */
+ (a[i-11] == 'i') &&
+ (a[i-10] == 's') &&
+ (a[i-9] == 'I') &&
+ (a[i-8] == 'n') &&
+ (a[i-7] == 's') &&
+ (a[i-6] == 't') &&
+ (a[i-5] == 'a') &&
+ (a[i-4] == 'n') &&
+ (a[i-3] == 'c') &&
+ (a[i-2] == 'e') &&
+ (a[i-1] == 'O') &&
+ (a[i] == 'f')) {
+ matchlen = 12;
+ mask |= IsInstanceOf;
+ } else if (i >= 11 && /* setAttribute */
+ (a[i-11] == 's') &&
+ (a[i-10] == 'e') &&
+ (a[i-9] == 't') &&
+ (a[i-8] == 'A') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 't') &&
+ (a[i-5] == 'r') &&
+ (a[i-4] == 'i') &&
+ (a[i-3] == 'b') &&
+ (a[i-2] == 'u') &&
+ (a[i-1] == 't') &&
+ (a[i] == 'e')) {
+ matchlen = 12;
+ mask |= SetAttribute;
+ } else if (i >= 10 && /* instantiate */
+ (a[i-10] == 'i') &&
+ (a[i-9] == 'n') &&
+ (a[i-8] == 's') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 'a') &&
+ (a[i-5] == 'n') &&
+ (a[i-4] == 't') &&
+ (a[i-3] == 'i') &&
+ (a[i-2] == 'a') &&
+ (a[i-1] == 't') &&
+ (a[i] == 'e')) {
+ matchlen = 11;
+ mask |= Instantiate;
+ } else if (i >= 10 && /* queryMBeans */
+ (a[i-10] == 'q') &&
+ (a[i-9] == 'u') &&
+ (a[i-8] == 'e') &&
+ (a[i-7] == 'r') &&
+ (a[i-6] == 'y') &&
+ (a[i-5] == 'M') &&
+ (a[i-4] == 'B') &&
+ (a[i-3] == 'e') &&
+ (a[i-2] == 'a') &&
+ (a[i-1] == 'n') &&
+ (a[i] == 's')) {
+ matchlen = 11;
+ mask |= QueryMBeans;
+ } else if (i >= 9 && /* queryNames */
+ (a[i-9] == 'q') &&
+ (a[i-8] == 'u') &&
+ (a[i-7] == 'e') &&
+ (a[i-6] == 'r') &&
+ (a[i-5] == 'y') &&
+ (a[i-4] == 'N') &&
+ (a[i-3] == 'a') &&
+ (a[i-2] == 'm') &&
+ (a[i-1] == 'e') &&
+ (a[i] == 's')) {
+ matchlen = 10;
+ mask |= QueryNames;
+ } else if (i >= 5 && /* invoke */
+ (a[i-5] == 'i') &&
+ (a[i-4] == 'n') &&
+ (a[i-3] == 'v') &&
+ (a[i-2] == 'o') &&
+ (a[i-1] == 'k') &&
+ (a[i] == 'e')) {
+ matchlen = 6;
+ mask |= Invoke;
+ } else {
+ // parse error
+ throw new IllegalArgumentException("Invalid permission: " +
+ action);
+ }
+
+ // make sure we didn't just match the tail of a word
+ // like "ackbarfaccept". Also, skip to the comma.
+ boolean seencomma = false;
+ while (i >= matchlen && !seencomma) {
+ switch(a[i-matchlen]) {
+ case ',':
+ seencomma = true;
+ break;
+ case ' ': case '\r': case '\n':
+ case '\f': case '\t':
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid permission: " +
+ action);
+ }
+ i--;
+ }
+
+ // point i at the location of the comma minus one (or -1).
+ i -= matchlen;
+ }
+
+ return mask;
+ }
+
+ /**
+ * Checks if this JMXNamespacePermission object "implies" the + * specified permission.
+ * + *More specifically, this method returns true if:
+ * + *If this object's mbeanServerName is a pattern, then p's + * mbeanServerName is matched against that pattern. An empty + * mbeanServerName is equivalent to "{@code *}". A null + * mbeanServerName is equivalent to "{@code -}".
+ *If this object's mbeanServerName is "*
" or is
+ * empty, p's mbeanServerName always matches it.
If this object's member is "*
", p's
+ * member always matches it.
If this object's objectName n1 is an object name pattern, + * p's objectName n2 matches it if + * {@link ObjectName#equals n1.equals(n2)} or if + * {@link ObjectName#apply n1.apply(n2)}.
+ * + *A permission that includes the queryMBeans
action
+ * is considered to include queryNames
as well.
+ * @param obj the object we are testing for equality with this object. + * @return true if obj is an JMXNamespacePermission, and has the + * same name and actions as this JMXNamespacePermission object. + */ + public boolean equals(Object obj) { + if (obj == this) + return true; + + if (! (obj instanceof JMXNamespacePermission)) + return false; + + JMXNamespacePermission that = (JMXNamespacePermission) obj; + + return (this.mask == that.mask) && + (this.getName().equals(that.getName())); + } + + /** + * Deserialize this object based on its name and actions. + */ + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + parseName(); + parseActions(); + } +} diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/namespace/JMXNamespaceView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaceView.java Thu Sep 04 14:46:36 2008 +0200 @@ -0,0 +1,300 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import java.io.IOException; +import java.util.Set; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +/** + * This class makes it possible to navigate easily within a hierarchical + * namespace view. + * + *
+ * MBeanServerConnnection rootConnection = ...; + * + * // create a view at the local root of the namespace hierarchy. + * // + * JMXNamespaceView view = new JMXNamespaceView(rootConnection); + * + * // list all top level namespaces + * String[] list = view.list(); + * + * // select one namespace from the list + * String whereToGo = ... ; + * + * // go down to the selected namespace: + * view = view.down(whereToGo); + * System.out.println("I am now in: " + view.where()); + * System.out.println("I can see these MBeans:" + + * view.getMBeanServerConnection().queryNames(null,null)); + * + * // list sub namespaces in current view ('whereToGo') + * list = view.list(); + * System.out.println("Here are the sub namespaces of "+view.where()+": "+ + * Arrays.toString(list)); + * + * // go up one level + * view = view.up(); + * System.out.println("I am now back to: " + + * (view.isRoot() ? "root namespace" : view.where())); + *+ * @since 1.7 + */ +public class JMXNamespaceView { + + private static final ObjectName ALL_NAMESPACES; + static { + try { + ALL_NAMESPACES = ObjectName.getInstance("*" + + JMXNamespaces.NAMESPACE_SEPARATOR + ":"+ + JMXNamespace.TYPE_ASSIGNMENT); + } catch (MalformedObjectNameException x) { + throw new ExceptionInInitializerError(x); + } + } + private static final int NAMESPACE_SEPARATOR_LENGTH = + JMXNamespaces.NAMESPACE_SEPARATOR.length(); + + private final JMXNamespaceView parent; + private final MBeanServerConnection here; + private final String where; + + private static MBeanServerConnection checkRoot(MBeanServerConnection root) { + if (root == null) + throw new IllegalArgumentException( + "namespaceRoot: null is not a valid value"); + return root; + } + + /** + * Creates a view at the top of a JMX namespace hierarchy. + * @param namespaceRoot The {@code MBeanServerConnection} at the + * top of the hierarchy. + */ + public JMXNamespaceView(MBeanServerConnection namespaceRoot) { + this(null,checkRoot(namespaceRoot),""); + } + + // This constructor should remain private. A user can only create + // JMXNamespaceView at the top of the hierarchy. + // JMXNamespaceView sub nodes are created by their parent nodes. + private JMXNamespaceView(JMXNamespaceView parent, + MBeanServerConnection here, String where) { + this.parent = parent; + this.here = here; + this.where = where; + } + + /** + * Returns the path leading to the namespace in this view, from + * the top of the hierarchy. + * @return The path to the namespace in this view. + */ + public String where() { + return where; + } + + /** + * Lists all direct sub namespaces in this view. The returned strings + * do not contain the {@code //} separator. + * + * @return A list of direct sub name spaces accessible from this + * namespace. + * @throws IOException if the attempt to list the namespaces fails because + * of a communication problem. + */ + public String[] list() throws IOException { + final Set
+ * JMX.narrowToNamespace(this.root().getMBeanServerConnection(), + * this.where()); + *+ * @return A MBeanServerConnection to the namespace shown by this view. + */ + public MBeanServerConnection getMBeanServerConnection() { + return here; + } + + /** + *
Get the name of the JMXNamespaceMBean handling the namespace shown by + * this view, relative to the root of the hierarchy. If we are at the root + * of the hierarchy, this method returns {@code null}.
+ * + *You can use this method to make a proxy for the JMXNamespaceMBean + * as follows:
+ * + *+ * JMXNamespaceView view = ...; + * ObjectName namespaceMBeanName = view.getJMXNamespaceMBeanName(); + * JMXNamespaceMBean namespaceMBean = JMX.newMBeanProxy( + * view.root().getMBeanServerConnection(), namespaceMBeanName, + * JMXNamespaceMBean.class); + *+ * + * @return The name of the {@code JMXNamespaceMBean} handling the namespace + * shown by this view, or {@code null}. + */ + public ObjectName getJMXNamespaceMBeanName() { + if (parent == null) + return null; + else + return JMXNamespaces.getNamespaceObjectName(where); + } + + @Override + public int hashCode() { + return where.hashCode(); + } + + /** + * Returns true if this object is equal to the given object. The + * two objects are equal if the other object is also a {@code + * JMXNamespaceView} and both objects have the same {@linkplain #root root} + * MBeanServerConnection and the same {@linkplain #where path}. + * @param o the other object to compare to. + * @return true if both objects are equal. + */ + @Override + public boolean equals(Object o) { + if (o==this) return true; + if (! (o instanceof JMXNamespaceView)) return false; + if (!where.equals(((JMXNamespaceView)o).where)) return false; + return root().getMBeanServerConnection().equals( + ((JMXNamespaceView)o).root().getMBeanServerConnection()); + } + + private JMXNamespaceView makeJMXNamespaceView(final JMXNamespaceView root, + final JMXNamespaceView directParent, final String pathFromRoot) { + if (pathFromRoot.equals("")) return root; + + return new JMXNamespaceView(directParent, + narrowToNamespace(root.getMBeanServerConnection(), + pathFromRoot),pathFromRoot); + } + + private MBeanServerConnection narrowToNamespace(MBeanServerConnection root, + String path) { + if (root instanceof MBeanServer) + return JMXNamespaces.narrowToNamespace((MBeanServer)root, path); + return JMXNamespaces.narrowToNamespace(root, path); + } + +} diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java Thu Sep 04 14:46:36 2008 +0200 @@ -0,0 +1,374 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.namespace.JMXNamespaceUtils; +import com.sun.jmx.namespace.ObjectNameRouter; +import com.sun.jmx.namespace.serial.RewritingProcessor; +import com.sun.jmx.namespace.RoutingConnectionProxy; +import com.sun.jmx.namespace.RoutingServerProxy; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; + +/** + * Static constants and utility methods to help work with + * JMX name spaces. There are no instances of this class. + * @since 1.7 + */ +public class JMXNamespaces { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + /** Creates a new instance of JMXNamespaces */ + private JMXNamespaces() { + } + + /** + * The name space separator. This is an alias for {@link + * ObjectName#NAMESPACE_SEPARATOR}. + **/ + public static final String NAMESPACE_SEPARATOR = + ObjectName.NAMESPACE_SEPARATOR; + private static final int NAMESPACE_SEPARATOR_LENGTH = + NAMESPACE_SEPARATOR.length(); + + + /** + * Returns a connector connected to a sub name space exposed through + * the parent connector. + * @param parent the parent connector. + * @param namespace the {@linkplain javax.management.namespace name space} + * to which the returned connector is + * connected. + * @return A connector connected to a sub name space exposed through + * the parent connector. + **/ + public static JMXConnector narrowToNamespace(final JMXConnector parent, + final String namespace) + throws IOException { + + return JMXNamespaceUtils.cd(parent,namespace,true); + } + + /** + * Creates a new {@code MBeanServerConnection} proxy on a + * {@linkplain javax.management.namespace sub name space} + * of the given parent. + * + * @param parent The parent {@code MBeanServerConnection} that contains + * the name space. + * @param namespace The {@linkplain javax.management.namespace + * name space} in which to narrow. + * @return A new {@code MBeanServerConnection} proxy that shows the content + * of that name space. + * @throws IllegalArgumentException if the name space does not exist, or + * if a proxy for that name space cannot be created. + */ + public static MBeanServerConnection narrowToNamespace( + MBeanServerConnection parent, + String namespace) { + if (LOG.isLoggable(Level.FINER)) + LOG.finer("Making MBeanServerConnection for: " +namespace); + return RoutingConnectionProxy.cd(parent,namespace); + } + + /** + * Creates a new {@code MBeanServer} proxy on a + * {@linkplain javax.management.namespace sub name space} + * of the given parent. + * + * @param parent The parent {@code MBeanServer} that contains + * the name space. + * @param namespace The {@linkplain javax.management.namespace + * name space} in which to narrow. + * @return A new {@code MBeanServer} proxy that shows the content + * of that name space. + * @throws IllegalArgumentException if either argument is null, + * or the name space does not exist, or if a proxy for that name space + * cannot be created. + */ + public static MBeanServer narrowToNamespace(MBeanServer parent, + String namespace) { + if (LOG.isLoggable(Level.FINER)) + LOG.finer("Making NamespaceServerProxy for: " +namespace); + return RoutingServerProxy.cd(parent,namespace); + } + + /** + * Returns an object that is the same as the given object except that + * any {@link ObjectName} it might contain has its domain modified. + * The returned object might be identical to the given object if it + * does not contain any {@code ObjectName} values or if none of them + * were modified. + * This method will replace a prefix ({@code toRemove}) from the path of + * the ObjectNames contained in {@code obj} by another prefix + * ({@code toAdd}). + * Therefore, all contained ObjectNames must have a path that start with + * the given {@code toRemove} prefix. If one of them doesn't, an {@link + * IllegalArgumentException} is thrown. + *
+ * For instance, if {@code obj} contains the ObjectName
+ * {@code x//y//z//d:k=x}, and {@code toAdd} is {@code v//w}, and
+ * {@code toRemove}
+ * is {@code x//y} this method will return a copy of {@code obj} that
+ * contains {@code v//w//z//d:k=x}.
+ * On the other hand, if {@code obj} contains the ObjectName
+ * {@code x//y//z//d:k=x}, and {@code toAdd} is {@code v//w}, and
+ * {@code toRemove} is {@code v} this method
+ * will raise an exception, because {@code x//y//z//d:k=x} doesn't start
+ * with {@code v}
+ *
Note: the default implementation of this method can use the + * Java serialization framework to clone and replace ObjectNames in the + * provided {@code obj}. It will usually fail if {@code obj} is not + * Java serializable, or contains objects which are not Java + * serializable. + *
+ * @param obj The object to deep-rewrite + * @param toRemove a prefix already present in contained ObjectNames. + * If {@code toRemove} is the empty string {@code ""}, nothing + * will be removed from the contained ObjectNames. + * @param toAdd the prefix that will replace (@code toRemove} in contained + * ObjectNames. + * If {@code toAdd} is the empty string {@code ""}, nothing + * will be added to the contained ObjectNames. + * @return the rewritten object, or possibly {@code obj} if nothing needed + * to be changed. + * @throws IllegalArgumentException if {@code obj} couldn't be rewritten or + * if {@code toRemove} or {@code toAdd} is null. + **/ + public static+ * You can call {@link #connect() connect()} and {@link #close close()} + * several times. This MBean will emit an {@link AttributeChangeNotification} + * when the value of its {@link #isConnected Connected} attribute changes. + *
+ *+ * The JMX Remote Namespace MBean is not connected until {@link + * #connect() connect()} is explicitly called. The usual sequence of code to + * create a JMX Remote Namespace is thus: + *
+ *+ * final String namespace = "mynamespace"; + * final ObjectName name = {@link JMXNamespaces#getNamespaceObjectName + * JMXNamespaces.getNamespaceObjectName(namespace)}; + * final JMXServiceURL remoteServerURL = .... ; + * final Map+ *optionsMap = .... ; + * final MBeanServer masterMBeanServer = .... ; + * final JMXRemoteNamespace namespaceMBean = {@link #newJMXRemoteNamespace + * JMXRemoteNamespace.newJMXRemoteNamespace(remoteServerURL, optionsMap)}; + * masterMBeanServer.registerMBean(namespaceMBean, name); + * namespaceMBean.connect(); + * // or: masterMBeanServer.invoke(name, {@link #connect() "connect"}, null, null); + *
+ * The JMX Remote Namespace MBean will register for {@linkplain + * JMXConnectionNotification JMX Connection Notifications} with its underlying + * {@link JMXConnector}. When a JMX Connection Notification indicates that + * the underlying connection has failed, the JMX Remote Namespace MBean + * closes its underlying connector and switches its {@link #isConnected + * Connected} attribute to false, emitting an {@link + * AttributeChangeNotification}. + *
+ *+ * At this point, a managing application (or an administrator connected + * through a management console) can attempt to reconnect the + * JMX Remote Namespace MBean by calling its {@link #connect() connect()} method + * again. + *
+ *Note that when the connection with the remote namespace fails, or when + * {@link #close} is called, then any notification subscription to + * MBeans registered in that namespace will be lost - unless a custom + * {@linkplain javax.management.event event service} supporting connection-less + * mode was used. + *
+ * @since 1.7 + */ +public class JMXRemoteNamespace + extends JMXNamespace + implements JMXRemoteNamespaceMBean, NotificationEmitter { + + /** + * A logger for this class. + */ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + private static final Logger PROBE_LOG = Logger.getLogger( + JmxProperties.NAMESPACE_LOGGER_NAME+".probe"); + + + // This connection listener is used to listen for connection events from + // the underlying JMXConnector. It is used in particular to maintain the + // "connected" state in this MBean. + // + private static class ConnectionListener implements NotificationListener { + private final JMXRemoteNamespace handler; + private ConnectionListener(JMXRemoteNamespace handler) { + this.handler = handler; + } + public void handleNotification(Notification notification, + Object handback) { + if (!(notification instanceof JMXConnectionNotification)) + return; + final JMXConnectionNotification cn = + (JMXConnectionNotification)notification; + handler.checkState(this,cn,(JMXConnector)handback); + } + } + + // When the JMXRemoteNamespace is originally created, it is not connected, + // which means that the source MBeanServer should be one that throws + // exceptions for most methods. When it is subsequently connected, + // the methods should be forwarded to the MBeanServerConnection. + // We handle this using MBeanServerConnectionWrapper. The + // MBeanServerConnection that is supplied to the constructor of + // MBeanServerConnectionWrapper is ignored (and in fact it is null) + // because the one that is actually used is the one supplied by the + // override of getMBeanServerConnection(). + private static class JMXRemoteNamespaceDelegate + extends MBeanServerConnectionWrapper + implements DynamicProbe { + private volatile JMXRemoteNamespace parent=null; + + JMXRemoteNamespaceDelegate() { + super(null,null); + } + @Override + public MBeanServerConnection getMBeanServerConnection() { + return parent.getMBeanServerConnection(); + } + @Override + public ClassLoader getDefaultClassLoader() { + return parent.getDefaultClassLoader(); + } + + // Because this class is instantiated in the super() call from the + // constructor of JMXRemoteNamespace, it cannot be an inner class. + // This method achieves the effect that an inner class would have + // had, of giving the class a reference to the outer "this". + synchronized void initParentOnce(JMXRemoteNamespace parent) { + if (this.parent != null) + throw new UnsupportedOperationException("parent already set"); + this.parent=parent; + + } + + public boolean isProbeRequested() { + return this.parent.isProbeRequested(); + } + } + + private static final MBeanNotificationInfo connectNotification = + new MBeanNotificationInfo(new String[] { + AttributeChangeNotification.ATTRIBUTE_CHANGE}, + "Connected", + "Emitted when the Connected state of this object changes"); + + private static long seqNumber=0; + + private final NotificationBroadcasterSupport broadcaster; + private final ConnectionListener listener; + private final JMXServiceURL jmxURL; + private final Map+ * This constructor is provided for subclasses. + * To create a new instance of {@code JMXRemoteNamespace} call + * {@link #newJMXRemoteNamespace + * JMXRemoteNamespace.newJMXRemoteNamespace(sourceURL, optionsMap)}. + *
+ * @param sourceURL a JMX service URL that can be used to {@linkplain + * #connect() connect} to the + * source MBean Server. The source MBean Server is the remote + * MBean Server which contains the MBeans that will be mirrored + * in this namespace. + * @param optionsMap the options map that will be passed to the + * {@link JMXConnectorFactory} when {@linkplain + * JMXConnectorFactory#newJMXConnector creating} the + * {@link JMXConnector} used to {@linkplain #connect() connect} + * to the remote source MBean Server. Can be null, which is + * equivalent to an empty map. + * @see #newJMXRemoteNamespace JMXRemoteNamespace.newJMXRemoteNamespace + * @see #connect + */ + protected JMXRemoteNamespace(JMXServiceURL sourceURL, + Map+ * @see #connect + * @return The {@code JMXServiceURL} used to connect to the remote + * name space. + */ + public JMXServiceURL getJMXServiceURL() { + return jmxURL; + } + + /** + * In this class, this method never returns {@code null}, and the + * address returned is the {@link #getJMXServiceURL JMXServiceURL} + * that is used by this object to {@linkplain #connect} to the remote + * name space.
+ * This behaviour might be overriden by subclasses, if needed.
+ * For instance, a subclass might want to return {@code null} if it
+ * doesn't want to expose that JMXServiceURL.
+ */
+ public JMXServiceURL getAddress() {
+ return getJMXServiceURL();
+ }
+
+ private Map
+ * The implementation should probably look like:
+ * This method can be called by subclasses in order to send their own
+ * notifications.
+ * In that case, these subclasses might also need to override
+ * {@link #getNotificationInfo} in order to declare their own
+ * {@linkplain MBeanNotificationInfo notification types}.
+ *
+ * This method first calls {@link JMXConnectorFactory#newJMXConnector
+ * JMXConnectorFactory.newJMXConnector(jmxURL, env)} to obtain a new
+ * JMX connector, and returns that.
+ *
+ * A subclass of {@link JMXRemoteNamespace} can provide an implementation
+ * that connects to a sub namespace of the remote server by subclassing
+ * this class in the following way:
+ *
+ * final MBeanNotificationInfo[] myOwnNotifs = { .... };
+ * final MBeanNotificationInfo[] parentNotifs =
+ * super.getNotificationInfo();
+ * final Set
+ */
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ return broadcaster.getNotificationInfo();
+ }
+
+ public void removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {
+ broadcaster.removeNotificationListener(listener);
+ }
+
+ public void removeNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback)
+ throws ListenerNotFoundException {
+ broadcaster.removeNotificationListener(listener, filter, handback);
+ }
+
+ private static synchronized long getNextSeqNumber() {
+ return seqNumber++;
+ }
+
+
+ /**
+ * Sends a notification to registered listeners. Before the notification
+ * is sent, the following steps are performed:
+ *
+ *
+ * class JMXRemoteSubNamespace extends JMXRemoteNamespace {
+ * private final String subnamespace;
+ * JMXRemoteSubNamespace(JMXServiceURL url,
+ * Map{@code
+ *
+ * Some connectors, like the JMXMP connector server defined by the + * version 1.2 of the JMX API may not have been upgraded to use the + * new {@linkplain javax.management.event Event Service} defined in this + * version of the JMX API. + *
+ * In that case, and if the remote server to which this JMXRemoteNamespace
+ * connects also contains namespaces, it may be necessary to configure
+ * explicitly an {@linkplain
+ * javax.management.event.EventClientDelegate#newForwarder()
+ * Event Client Forwarder} on the remote server side, and to force the use
+ * of an {@link EventClient} on this client side.
+ *
+ * A subclass of {@link JMXRemoteNamespace} can provide an implementation
+ * of {@code newJMXConnector} that will force notification subscriptions
+ * to flow through an {@link EventClient} over a legacy protocol by
+ * overriding this method in the following way:
+ *
+ * class JMXRemoteEventClientNamespace extends JMXRemoteNamespace { + * JMXRemoteSubNamespaceConnector(JMXServiceURL url, + * Map+ *env) { + * super(url,options); + * } + * protected JMXConnector newJMXConnector(JMXServiceURL url, + * Map env) throws IOException { + * final JMXConnector inner = super.newJMXConnector(url,env); + * return {@link EventClient#withEventClient( + * JMXConnector) EventClient.withEventClient(inner)}; + * } + * } + *
+ * Note that the remote server also needs to provide an {@link
+ * javax.management.event.EventClientDelegateMBean}: only configuring
+ * the client side (this object) is not enough.
+ * In summary, this technique should be used if the remote server
+ * supports JMX namespaces, but uses a JMX Connector Server whose
+ * implementation does not transparently use the new Event Service
+ * (as would be the case with the JMXMPConnectorServer implementation
+ * from the reference implementation of the JMX Remote API 1.0
+ * specification).
+ *
+ * The source MBeans will not appear in the target name space until the + * JMXRemoteNamespaceMBean is connected. + *
+ * It is possible to call {@code connect()}, {@link #close close()}, and + * {@code connect()} again. + * However, closing the connection with the remote name space may cause + * notification listeners to be lost, unless the client explicitly uses + * the new {@linkplain javax.management.event JMX event service}. + *
+ * @throws IOException if connection to the remote source name space fails. + * @see #isConnected isConnected + **/ + public void connect() + throws IOException; + + /** + * Closes the connection with the remote source name space. + * If the connection is already closed, do nothing. + * Otherwise, closes the underlying {@link + * javax.management.remote.JMXConnector}. + *
Once closed, it is possible to reopen the connection by + * calling {@link #connect connect}. + *
+ * @throws IOException if the connection to the remote source name space + * can't be closed properly. + * @see #isConnected isConnected + **/ + public void close() + throws IOException; + + /** + * Tells whether the connection to the remote source name space is opened. + * @see #connect connect + * @see #close close + * @return {@code true} if connected. + **/ + public boolean isConnected(); + + /** + * Returns the {@link JMXServiceURL} address that points to the remote name + * space mirrored by this {@link JMXNamespaceMBean JMXNamespace MBean}, + * if available. + * @return The {@link JMXServiceURL} address that points to the remote name + * space mirrored by this {@link JMXNamespaceMBean JMXNamespace MBean}, + * or {@code null}. + */ + public JMXServiceURL getAddress(); +} diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java Thu Sep 04 14:46:36 2008 +0200 @@ -0,0 +1,703 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import com.sun.jmx.mbeanserver.Util; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.security.AccessController; +import java.util.Set; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.loading.ClassLoaderRepository; + +/** + *An object of this class implements the MBeanServer interface + * and, for each of its methods forwards the request to a wrapped + * {@link MBeanServerConnection} object. + * Some methods of the {@link MBeanServer} interface do not have + * any equivalent in {@link MBeanServerConnection}. In that case, an + * {@link UnsupportedOperationException} will be thrown. + * + *
A typical use of this class is to apply a {@link QueryExp} object locally,
+ * on an MBean that resides in a remote MBeanServer. Since an
+ * MBeanServerConnection is not an MBeanServer, it cannot be passed
+ * to the setMBeanServer()
method of the {@link QueryExp}
+ * object. However, this object can.
This method is called each time an IOException is raised when + * trying to forward an operation to the underlying + * MBeanServerConnection, as a result of calling + * {@link #getMBeanServerConnection()} or as a result of invoking the + * operation on the returned connection. Since the methods in + * {@link MBeanServer} are not declared to throw {@code IOException}, + * this method must return a {@code RuntimeException} to be thrown + * instead. Typically, the original {@code IOException} will be in the + * {@linkplain Throwable#getCause() cause chain} of the {@code + * RuntimeException}.
+ * + *Subclasses may redefine this method if they need to perform any + * specific handling of IOException (logging etc...).
+ * + * @param x The raised IOException. + * @param method The name of the method in which the exception was + * raised. This is one of the methods of the MBeanServer + * interface. + * + * @return A RuntimeException that should be thrown by the caller. + * In this default implementation, this is a + * {@link RuntimeException} wrapping x. + **/ + protected RuntimeException wrapIOException(IOException x, String method) { + return Util.newRuntimeIOException(x); + } + + // Take care of getMBeanServerConnection returning null. + // + private synchronized MBeanServerConnection connection() + throws IOException { + final MBeanServerConnection c = getMBeanServerConnection(); + if (c == null) + throw new IOException("MBeanServerConnection unavailable"); + return c; + } + + //-------------------------------------------- + //-------------------------------------------- + // + // Implementation of the MBeanServer interface + // + //-------------------------------------------- + //-------------------------------------------- + + /** + * Forward this method to the + * wrapped object. + */ + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + try { + connection().addNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw wrapIOException(x,"addNotificationListener"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public void addNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + try { + connection().addNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw wrapIOException(x,"addNotificationListener"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance createMBean(String className, ObjectName name) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + try { + return connection().createMBean(className, name); + } catch (IOException x) { + throw wrapIOException(x,"createMBean"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance createMBean(String className, ObjectName name, + Object params[], String signature[]) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + try { + return connection().createMBean(className, name, + params, signature); + } catch (IOException x) { + throw wrapIOException(x,"createMBean"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + try { + return connection().createMBean(className, name, loaderName); + } catch (IOException x) { + throw wrapIOException(x,"createMBean"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName, + Object params[], + String signature[]) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + try { + return connection().createMBean(className, name, loaderName, + params, signature); + } catch (IOException x) { + throw wrapIOException(x,"createMBean"); + } + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + * @deprecated see {@link MBeanServer#deserialize(ObjectName,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + throw new UnsupportedOperationException("deserialize"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + * @deprecated see {@link MBeanServer#deserialize(String,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + throw new UnsupportedOperationException("deserialize"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + * @deprecated see {@link MBeanServer#deserialize(String,ObjectName,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, + byte[] data) + throws + InstanceNotFoundException, + OperationsException, + ReflectionException { + throw new UnsupportedOperationException("deserialize"); + } + + /** + * Forward this method to the + * wrapped object. + */ + public Object getAttribute(ObjectName name, String attribute) + throws + MBeanException, + AttributeNotFoundException, + InstanceNotFoundException, + ReflectionException { + try { + return connection().getAttribute(name, attribute); + } catch (IOException x) { + throw wrapIOException(x,"getAttribute"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return connection().getAttributes(name, attributes); + } catch (IOException x) { + throw wrapIOException(x,"getAttributes"); + } + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + throw new UnsupportedOperationException("getClassLoader"); + } + + /** + * Returns the {@linkplain #getDefaultClassLoader() default class loader}. + * This behavior can be changed by subclasses. + */ + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + return getDefaultClassLoader(); + } + + /** + *Returns a {@link ClassLoaderRepository} based on the class loader + * returned by {@link #getDefaultClassLoader()}.
+ * @return a {@link ClassLoaderRepository} that contains a single + * class loader, returned by {@link #getDefaultClassLoader()}. + **/ + public ClassLoaderRepository getClassLoaderRepository() { + // We return a new ClassLoaderRepository each time this method is + // called. This is by design, because there's no guarantee that + // getDefaultClassLoader() will always return the same class loader. + return Util.getSingleClassLoaderRepository(getDefaultClassLoader()); + } + + /** + * Forward this method to the + * wrapped object. + */ + public String getDefaultDomain() { + try { + return connection().getDefaultDomain(); + } catch (IOException x) { + throw wrapIOException(x,"getDefaultDomain"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public String[] getDomains() { + try { + return connection().getDomains(); + } catch (IOException x) { + throw wrapIOException(x,"getDomains"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public Integer getMBeanCount() { + try { + return connection().getMBeanCount(); + } catch (IOException x) { + throw wrapIOException(x,"getMBeanCount"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public MBeanInfo getMBeanInfo(ObjectName name) + throws + InstanceNotFoundException, + IntrospectionException, + ReflectionException { + try { + return connection().getMBeanInfo(name); + } catch (IOException x) { + throw wrapIOException(x,"getMBeanInfo"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + try { + return connection().getObjectInstance(name); + } catch (IOException x) { + throw wrapIOException(x,"getObjectInstance"); + } + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public Object instantiate(String className) + throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("instantiate"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public Object instantiate(String className, + Object params[], + String signature[]) + throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("instantiate"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("instantiate"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public Object instantiate(String className, ObjectName loaderName, + Object params[], String signature[]) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("instantiate"); + } + + /** + * Forward this method to the + * wrapped object. + */ + public Object invoke(ObjectName name, String operationName, + Object params[], String signature[]) + throws + InstanceNotFoundException, + MBeanException, + ReflectionException { + try { + return connection().invoke(name,operationName,params,signature); + } catch (IOException x) { + throw wrapIOException(x,"invoke"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + try { + return connection().isInstanceOf(name, className); + } catch (IOException x) { + throw wrapIOException(x,"isInstanceOf"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public boolean isRegistered(ObjectName name) { + try { + return connection().isRegistered(name); + } catch (IOException x) { + throw wrapIOException(x,"isRegistered"); + } + } + + /** + * Forward this method to the + * wrapped object. + * If an IOException is raised, returns an empty Set. + */ + public SetBase class for custom implementations of the {@link MBeanServer} + * interface. The commonest use of this class is as the {@linkplain + * JMXNamespace#getSourceServer() source server} for a {@link + * JMXNamespace}, although this class can be used anywhere an {@code + * MBeanServer} instance is required. Note that the usual ways to + * obtain an {@code MBeanServer} instance are either to use {@link + * java.lang.management.ManagementFactory#getPlatformMBeanServer() + * ManagementFactory.getPlatformMBeanServer()} or to use the {@code + * newMBeanServer} or {@code createMBeanServer} methods from {@link + * javax.management.MBeanServerFactory MBeanServerFactory}. {@code + * MBeanServerSupport} is for certain cases where those are not + * appropriate.
+ * + *There are two main use cases for this class: special-purpose MBeanServer implementations, + * and namespaces containing Virtual MBeans. The next + * sections explain these use cases.
+ * + *In the simplest case, a subclass needs to implement only two methods:
+ * + *Subclasses can create such {@link DynamicMBean} MBeans on the fly - for + * instance, using the class {@link javax.management.StandardMBean}, just for + * the duration of an MBeanServer method call.
+ * + *In some cases + * the general-purpose {@code MBeanServer} that you get from + * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not + * appropriate. You might need different security checks, or you might + * want a mock {@code MBeanServer} suitable for use in tests, or you might + * want a simplified and optimized {@code MBeanServer} for a special purpose.
+ * + *As an example of a special-purpose {@code MBeanServer}, the class {@link + * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs + * an {@code MBeanServer} instance every time it filters a notification, + * with just one MBean that represents the notification. Although it could + * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code + * MBeanServer} will be quicker to create, use less memory, and have simpler + * methods that execute faster.
+ * + *Here is an example of a special-purpose {@code MBeanServer} + * implementation that contains exactly one MBean, which is specified at the + * time of creation.
+ * + *+ * public class SingletonMBeanServer extends MBeanServerSupport { + * private final ObjectName objectName; + * private final DynamicMBean mbean; + * + * public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) { + * this.objectName = objectName; + * this.mbean = mbean; + * } + * + * @Override + * protected {@code Set+ * + *} {@link #getNames getNames}() { + * return Collections.singleton(objectName); + * } + * + * @Override + * public DynamicMBean {@link #getDynamicMBeanFor + * getDynamicMBeanFor}(ObjectName name) + * throws InstanceNotFoundException { + * if (objectName.equals(name)) + * return mbean; + * else + * throw new InstanceNotFoundException(name); + * } + * } + *
Using this class, you could make an {@code MBeanServer} that contains + * a {@link javax.management.timer.Timer Timer} MBean like this:
+ * + *+ * Timer timer = new Timer(); + * DynamicMBean mbean = new {@link javax.management.StandardMBean + * StandardMBean}(timer, TimerMBean.class); + * ObjectName name = new ObjectName("com.example:type=Timer"); + * MBeanServer timerMBS = new SingletonMBeanServer(name, mbean); + *+ * + *
When {@code getDynamicMBeanFor} always returns the same object for the + * same name, as here, notifications work in the expected way: if the object + * is a {@link NotificationEmitter} then listeners can be added using + * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) MBeanServer.addNotificationListener}. If + * {@code getDynamicMBeanFor} does not always return the same object for the + * same name, more work is needed to make notifications work, as described + * below.
+ * + *Virtual MBeans are MBeans that do not exist as Java objects, + * except transiently while they are being accessed. This is useful when + * there might be very many of them, or when keeping track of their creation + * and deletion might be expensive or hard. For example, you might have one + * MBean per system process. With an ordinary {@code MBeanServer}, you would + * have to list the system processes in order to create an MBean object for + * each one, and you would have to track the arrival and departure of system + * processes in order to create or delete the corresponding MBeans. With + * Virtual MBeans, you only need the MBean for a given process at the exact + * point where it is referenced with a call such as + * {@link MBeanServer#getAttribute MBeanServer.getAttribute}.
+ * + *Here is an example of an {@code MBeanServer} implementation that has + * one MBean for every system property. The system property {@code "java.home"} + * is represented by the MBean called {@code + * com.example:type=Property,name="java.home"}, with an attribute called + * {@code Value} that is the value of the property.
+ * + *+ * public interface PropertyMBean { + * public String getValue(); + * } + * + * public class PropsMBS extends MBeanServerSupport { + * private static ObjectName newObjectName(String name) { + * try { + * return new ObjectName(name); + * } catch (MalformedObjectNameException e) { + * throw new AssertionError(e); + * } + * } + * + * public static class PropertyImpl implements PropertyMBean { + * private final String name; + * + * public PropertyImpl(String name) { + * this.name = name; + * } + * + * public String getValue() { + * return System.getProperty(name); + * } + * } + * + * @Override + * public DynamicMBean {@link #getDynamicMBeanFor + * getDynamicMBeanFor}(ObjectName name) + * throws InstanceNotFoundException { + * + * // Check that the name is a legal one for a Property MBean + * ObjectName namePattern = newObjectName( + * "com.example:type=Property,name=\"*\""); + * if (!namePattern.apply(name)) + * throw new InstanceNotFoundException(name); + * + * // Extract the name of the property that the MBean corresponds to + * String propName = ObjectName.unquote(name.getKeyProperty("name")); + * if (System.getProperty(propName) == null) + * throw new InstanceNotFoundException(name); + * + * // Construct and return a transient MBean object + * PropertyMBean propMBean = new PropertyImpl(propName); + * return new StandardMBean(propMBean, PropertyMBean.class, false); + * } + * + * @Override + * protected {@code Set+ * + *} {@link #getNames getNames}() { + * {@code Set names = new TreeSet ();} + * Properties props = System.getProperties(); + * for (String propName : props.stringPropertyNames()) { + * ObjectName objectName = newObjectName( + * "com.example:type=Property,name=" + + * ObjectName.quote(propName)); + * names.add(objectName); + * } + * return names; + * } + * } + *
Because the {@code getDynamicMBeanFor} method + * returns a different object every time it is called, the default handling + * of notifications will not work, as explained below. + * In this case it does not matter, because the object returned by {@code + * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link + * MBeanServer#addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) MBeanServer.addNotificationListener} will + * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean + * for property {@code "foo"} emitted a notification every time that property + * changed, we would need to do it as shown below. (Because there is no API to + * be informed when a property changes, this code assumes that some other code + * calls the {@code propertyChanged} method every time a property changes.)
+ * + *+ * public class PropsMBS { + * ...as above... + * + * private final {@link VirtualEventManager} vem = new VirtualEventManager(); + * + * @Override + * public NotificationEmitter {@link #getNotificationEmitterFor + * getNotificationEmitterFor}( + * ObjectName name) throws InstanceNotFoundException { + * getDynamicMBeanFor(name); // check that the name is valid + * return vem.{@link VirtualEventManager#getNotificationEmitterFor + * getNotificationEmitterFor}(name); + * } + * + * public void propertyChanged(String name, String newValue) { + * ObjectName objectName = newObjectName( + * "com.example:type=Property,name=" + ObjectName.quote(name)); + * Notification n = new Notification( + * "com.example.property.changed", objectName, 0L, + * "Property " + name + " changed"); + * n.setUserData(newValue); + * vem.{@link VirtualEventManager#publish publish}(objectName, n); + * } + * } + *+ * + *
MBean creation through {@code MBeanServer.createMBean} is disabled + * by default. Subclasses which need to support MBean creation + * through {@code createMBean} need to implement a single method {@link + * #createMBean(String, ObjectName, ObjectName, Object[], String[], + * boolean)}.
+ * + *Similarly MBean registration and unregistration through {@code + * registerMBean} and {@code unregisterMBean} are disabled by default. + * Subclasses which need to support MBean registration and + * unregistration will need to implement {@link #registerMBean registerMBean} + * and {@link #unregisterMBean unregisterMBean}.
+ * + *By default {@link MBeanServer#addNotificationListener(ObjectName,
+ * NotificationListener, NotificationFilter, Object) addNotificationListener}
+ * is accepted for an MBean {@code name} if {@link #getDynamicMBeanFor
+ * getDynamicMBeanFor}(name)
returns an object that is a
+ * {@link NotificationEmitter}. That is appropriate if
+ * {@code getDynamicMBeanFor}(name)
always returns the
+ * same object for the same {@code name}. But with
+ * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object,
+ * which is discarded as soon as the MBean request has finished.
+ * So a listener added to that object would be immediately forgotten.
The simplest way for a subclass that defines Virtual MBeans + * to support notifications is to create a private {@link VirtualEventManager} + * and override the method {@link + * #getNotificationEmitterFor getNotificationEmitterFor} as follows:
+ * + *+ * private final VirtualEventManager vem = new VirtualEventManager(); + * + * @Override + * public NotificationEmitter getNotificationEmitterFor( + * ObjectName name) throws InstanceNotFoundException { + * // Check that the name is a valid Virtual MBean. + * // This is the easiest way to do that, but not always the + * // most efficient: + * getDynamicMBeanFor(name); + * + * // Return an object that supports add/removeNotificationListener + * // through the VirtualEventManager. + * return vem.getNotificationEmitterFor(name); + * } + *+ * + *
A notification {@code n} can then be sent from the Virtual MBean
+ * called {@code name} by calling {@link VirtualEventManager#publish
+ * vem.publish}(name, n)
. See the example
+ * above.
Make a new {@code MBeanServerSupport} instance.
+ */ + protected MBeanServerSupport() { + } + + /** + *Returns a dynamically created handle that makes it possible to + * access the named MBean for the duration of a method call.
+ * + *An easy way to create such a {@link DynamicMBean} handle is, for + * instance, to create a temporary MXBean instance and to wrap it in + * an instance of + * {@link javax.management.StandardMBean}. + * This handle should remain valid for the duration of the call + * but can then be discarded.
+ * @param name the name of the MBean for which a request was received. + * @return a {@link DynamicMBean} handle that can be used to invoke + * operations on the named MBean. + * @throws InstanceNotFoundException if no such MBean is supposed + * to exist. + */ + public abstract DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException; + + /** + *Subclasses should implement this method to return + * the names of all MBeans handled by this object instance.
+ * + *The object returned by getNames() should be safely {@linkplain + * Set#iterator iterable} even in the presence of other threads that may + * cause the set of names to change. Typically this means one of the + * following:
+ * + *List names matching the given pattern. + * The default implementation of this method calls {@link #getNames()} + * and returns the subset of those names matching {@code pattern}.
+ * + * @param pattern an ObjectName pattern + * @return the list of MBean names that match the given pattern. + */ + protected SetReturns a {@link NotificationEmitter} which can be used to + * subscribe or unsubscribe for notifications with the named + * mbean.
+ * + *The default implementation of this method calls {@link + * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object + * if it is a {@code NotificationEmitter}, otherwise null. See above for further discussion of notification + * handling.
+ * + * @param name The name of the MBean whose notifications are being + * subscribed, or unsuscribed. + * + * @return A {@link NotificationEmitter} that can be used to subscribe or + * unsubscribe for notifications emitted by the named MBean, or {@code + * null} if the MBean does not emit notifications and should not be + * considered as a {@code NotificationEmitter}. + * + * @throws InstanceNotFoundException if {@code name} is not the name of + * an MBean in this {@code MBeanServer}. + */ + public NotificationEmitter getNotificationEmitterFor(ObjectName name) + throws InstanceNotFoundException { + DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean instanceof NotificationEmitter) + return (NotificationEmitter) mbean; + else + return null; + } + + private NotificationEmitter getNonNullNotificationEmitterFor( + ObjectName name) + throws InstanceNotFoundException { + NotificationEmitter emitter = getNotificationEmitterFor(name); + if (emitter == null) { + IllegalArgumentException iae = new IllegalArgumentException( + "Not a NotificationEmitter: " + name); + throw new RuntimeOperationsException(iae); + } + return emitter; + } + + /** + *Creates a new MBean in the MBean name space. + * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws an {@link + * UnsupportedOperationException} + * wrapped in a {@link RuntimeOperationsException}. + * + *Subclasses may redefine this method to provide an implementation.
+ * All the various flavors of {@code MBeanServer.createMBean} methods
+ * will eventually call this method. A subclass that wishes to
+ * support MBean creation through {@code createMBean} thus only
+ * needs to provide an implementation for this one method.
+ *
+ * @param className The class name of the MBean to be instantiated.
+ * @param name The object name of the MBean. May be null.
+ * @param params An array containing the parameters of the
+ * constructor to be invoked.
+ * @param signature An array containing the signature of the
+ * constructor to be invoked.
+ * @param loaderName The object name of the class loader to be used.
+ * @param useCLR This parameter is {@code true} when this method
+ * is called from one of the {@code MBeanServer.createMBean} methods
+ * whose signature does not include the {@code ObjectName} of an
+ * MBean class loader to use for loading the MBean class.
+ *
+ * @return An ObjectInstance
, containing the
+ * ObjectName
and the Java class name of the newly
+ * instantiated MBean. If the contained ObjectName
+ * is n
, the contained Java class name is
+ * {@link javax.management.MBeanServer#getMBeanInfo
+ * getMBeanInfo(n)}.getClassName()
.
+ *
+ * @exception ReflectionException Wraps a
+ * java.lang.ClassNotFoundException
or a
+ * java.lang.Exception
that occurred when trying to
+ * invoke the MBean's constructor.
+ * @exception InstanceAlreadyExistsException The MBean is already
+ * under the control of the MBean server.
+ * @exception MBeanRegistrationException The
+ * preRegister
(MBeanRegistration
+ * interface) method of the MBean has thrown an exception. The
+ * MBean will not be registered.
+ * @exception MBeanException The constructor of the MBean has
+ * thrown an exception
+ * @exception NotCompliantMBeanException This class is not a JMX
+ * compliant MBean
+ * @exception InstanceNotFoundException The specified class loader
+ * is not registered in the MBean server.
+ * @exception RuntimeOperationsException Wraps either:
+ *
java.lang.IllegalArgumentException
: The className
+ * passed in parameter is null, the ObjectName
passed in
+ * parameter contains a pattern or no ObjectName
is specified
+ * for the MBean; orAttempts to determine whether the named MBean should be + * considered as an instance of a given class. The default implementation + * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} + * to get an MBean object. Then its behaviour is the same as the standard + * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.
+ * + * {@inheritDoc} + */ + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + + final DynamicMBean instance = nonNullMBeanFor(name); + + try { + final String mbeanClassName = instance.getMBeanInfo().getClassName(); + + if (mbeanClassName.equals(className)) + return true; + + final Object resource; + final ClassLoader cl; + if (instance instanceof DynamicWrapperMBean) { + DynamicWrapperMBean d = (DynamicWrapperMBean) instance; + resource = d.getWrappedObject(); + cl = d.getWrappedClassLoader(); + } else { + resource = instance; + cl = instance.getClass().getClassLoader(); + } + + final Class> classNameClass = Class.forName(className, false, cl); + + if (classNameClass.isInstance(resource)) + return true; + + if (classNameClass == NotificationBroadcaster.class || + classNameClass == NotificationEmitter.class) { + try { + getNotificationEmitterFor(name); + return true; + } catch (Exception x) { + LOG.finest("MBean " + name + + " is not a notification emitter. Ignoring: "+x); + return false; + } + } + + final Class> resourceClass = Class.forName(mbeanClassName, false, cl); + return classNameClass.isAssignableFrom(resourceClass); + } catch (Exception x) { + /* Could be SecurityException or ClassNotFoundException */ + LOG.logp(Level.FINEST, + MBeanServerSupport.class.getName(), + "isInstanceOf", "Exception calling isInstanceOf", x); + return false; + } + } + + /** + * {@inheritDoc} + * + *The default implementation of this method returns the string + * "DefaultDomain".
+ */ + public String getDefaultDomain() { + return "DefaultDomain"; + } + + /** + * {@inheritDoc} + * + *The default implementation of this method returns + * {@link #getNames()}.size().
+ */ + public Integer getMBeanCount() { + return getNames().size(); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method first calls {@link #getNames + * getNames()} to get a list of all MBean names, + * and from this set of names, derives the set of domains which contain + * MBeans.
+ */ + public String[] getDomains() { + final SetThe default implementation of this method will first + * call {@link + * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle + * to the named MBean, + * and then call {@link DynamicMBean#getAttribute getAttribute} + * on that {@link DynamicMBean} handle.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.getAttribute(attribute); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} + * to obtain a handle to the named MBean, + * and then call {@link DynamicMBean#setAttribute setAttribute} + * on that {@link DynamicMBean} handle.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + mbean.setAttribute(attribute); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a + * handle to the named MBean, + * and then call {@link DynamicMBean#getAttributes getAttributes} + * on that {@link DynamicMBean} handle.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public AttributeList getAttributes(ObjectName name, + String[] attributes) throws InstanceNotFoundException, + ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.getAttributes(attributes); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a + * handle to the named MBean, + * and then call {@link DynamicMBean#setAttributes setAttributes} + * on that {@link DynamicMBean} handle.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public AttributeList setAttributes(ObjectName name, AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.setAttributes(attributes); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a + * handle to the named MBean, + * and then call {@link DynamicMBean#invoke invoke} + * on that {@link DynamicMBean} handle.
+ */ + public Object invoke(ObjectName name, String operationName, + Object[] params, String[] signature) + throws InstanceNotFoundException, MBeanException, + ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.invoke(operationName, params, signature); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a + * handle to the named MBean, + * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo} + * on that {@link DynamicMBean} handle.
+ */ + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.getMBeanInfo(); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will call + * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.{@link MBeanInfo#getClassName getClassName()} to get the + * class name to combine with {@code name} to produce a new + * {@code ObjectInstance}.
+ */ + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + final DynamicMBean mbean = nonNullMBeanFor(name); + final String className = mbean.getMBeanInfo().getClassName(); + return new ObjectInstance(name, className); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first call {@link + * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the + * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code + * isRegistered} will return true. If {@code getDynamicMBeanFor} returns + * null or throws {@link InstanceNotFoundException}, {@code isRegistered} + * will return false.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public boolean isRegistered(ObjectName name) { + try { + final DynamicMBean mbean = getDynamicMBeanFor(name); + return mbean!=null; + } catch (InstanceNotFoundException x) { + if (LOG.isLoggable(Level.FINEST)) + LOG.finest("MBean "+name+" is not registered: "+x); + return false; + } + } + + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #queryNames queryNames} + * to get a list of all matching MBeans, and then, for each returned name, + * call {@link #getObjectInstance getObjectInstance(name)}.
+ */ + public SetThe default implementation of this method calls {@link #getMatchingNames + * getMatchingNames(pattern)} to obtain a list of MBeans matching + * the given name pattern. If the {@code query} parameter is null, + * this will be the result. Otherwise, it will evaluate the + * {@code query} parameter for each of the returned names, exactly + * as an {@code MBeanServer} would. This might result in + * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called + * several times for each returned name.
+ */ + public SetAdds a listener to a registered MBean. A notification emitted by + * the MBean will be forwarded to the listener.
+ * + *This implementation calls + * {@link #getNotificationEmitterFor getNotificationEmitterFor} + * and invokes {@code addNotificationListener} on the + * {@link NotificationEmitter} it returns. + * + * @see #getDynamicMBeanFor getDynamicMBeanFor + * @see #getNotificationEmitterFor getNotificationEmitterFor + */ + public void addNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) throws InstanceNotFoundException { + final NotificationEmitter emitter = + getNonNullNotificationEmitterFor(name); + emitter.addNotificationListener(listener, filter, handback); + } + + /** + * {@inheritDoc} + * + *
This implementation calls + * {@link #getNotificationEmitterFor getNotificationEmitterFor} + * and invokes {@code removeNotificationListener} on the + * {@link NotificationEmitter} it returns. + * @see #getDynamicMBeanFor getDynamicMBeanFor + * @see #getNotificationEmitterFor getNotificationEmitterFor + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + final NotificationEmitter emitter = + getNonNullNotificationEmitterFor(name); + emitter.removeNotificationListener(listener); + } + + /** + * {@inheritDoc} + * + *
This implementation calls + * {@link #getNotificationEmitterFor getNotificationEmitterFor} + * and invokes {@code removeNotificationListener} on the + * {@link NotificationEmitter} it returns. + * @see #getDynamicMBeanFor getDynamicMBeanFor + * @see #getNotificationEmitterFor getNotificationEmitterFor + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationEmitter emitter = + getNonNullNotificationEmitterFor(name); + emitter.removeNotificationListener(listener); + } + + + /** + *
Adds a listener to a registered MBean.
+ * + *The default implementation of this method first calls + * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}. + * If that successfully returns an object, call it {@code + * mbean}, then (a) if {@code mbean} is an instance of {@link + * NotificationListener} then this method calls {@link + * #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) addNotificationListener(name, mbean, filter, + * handback)}, otherwise (b) this method throws an exception as specified + * for this case.
+ * + *This default implementation is not appropriate for Virtual MBeans, + * although that only matters if the object returned by {@code + * getDynamicMBeanFor} can be an instance of + * {@code NotificationListener}.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public void addNotificationListener(ObjectName name, ObjectName listenerName, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException { + NotificationListener listener = getListenerMBean(listenerName); + addNotificationListener(name, listener, filter, handback); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public void removeNotificationListener(ObjectName name, + ObjectName listenerName) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationListener listener = getListenerMBean(listenerName); + removeNotificationListener(name, listener); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public void removeNotificationListener(ObjectName name, + ObjectName listenerName, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationListener listener = getListenerMBean(listenerName); + removeNotificationListener(name, listener, filter, handback); + } + + private NotificationListener getListenerMBean(ObjectName listenerName) + throws InstanceNotFoundException { + Object mbean = getDynamicMBeanFor(listenerName); + if (mbean instanceof NotificationListener) + return (NotificationListener) mbean; + else { + throw newIllegalArgumentException( + "MBean is not a NotificationListener: " + listenerName); + } + } + + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link InstanceNotFoundException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @return the default implementation of this method never returns. + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + final UnsupportedOperationException failed = + new UnsupportedOperationException("getClassLoader"); + final InstanceNotFoundException x = + new InstanceNotFoundException(String.valueOf(loaderName)); + x.initCause(failed); + throw x; + } + + /** + * {@inheritDoc} + * + *The default implementation of this method calls + * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies + * the logic just described to the result.
+ */ + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + final DynamicMBean mbean = nonNullMBeanFor(mbeanName); + if (mbean instanceof DynamicWrapperMBean) + return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); + else + return mbean.getClass().getClassLoader(); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method returns a + * {@link ClassLoaderRepository} containing exactly one loader, + * the {@linkplain Thread#getContextClassLoader() context class loader} + * for the current thread. + * Subclasses can override this method to return a different + * {@code ClassLoaderRepository}.
+ */ + public ClassLoaderRepository getClassLoaderRepository() { + // We return a new ClassLoaderRepository each time this + // method is called. This is by design, because the + // SingletonClassLoaderRepository is a very small object and + // getClassLoaderRepository() will not be called very often + // (the connector server calls it once) - in the context of + // MBeanServerSupport there's a very good chance that this method will + // *never* be called. + ClassLoader ccl = Thread.currentThread().getContextClassLoader(); + return Util.getSingleClassLoaderRepository(ccl); + } + + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + throw newUnsupportedException("registerMBean"); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}. + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + throw newUnsupportedException("unregisterMBean"); + } + + /** + * Calls {@link #createMBean(String, ObjectName, + * ObjectName, Object[], String[], boolean) + * createMBean(className, name, null, params, signature, true)}; + */ + public final ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + return safeCreateMBean(className, name, null, params, signature, true); + } catch (InstanceNotFoundException ex) { + // should not happen! + throw new MBeanException(ex, "Unexpected exception: " + ex); + } + } + + /** + * Calls {@link #createMBean(String, ObjectName, + * ObjectName, Object[], String[], boolean) + * createMBean(className,name, loaderName, params, signature, false)}; + */ + public final ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + return safeCreateMBean(className, name, loaderName, params, signature, false); + } + + /** + * Calls {@link #createMBean(String, ObjectName, + * ObjectName, Object[], String[], boolean) + * createMBean(className, name, null, null, null, true)}; + */ + public final ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + return safeCreateMBean(className, name, null, null, null, true); + } catch (InstanceNotFoundException ex) { + // should not happen! + throw new MBeanException(ex, "Unexpected exception: " + ex); + } + } + + /** + * Calls {@link #createMBean(String, ObjectName, + * ObjectName, Object[], String[], boolean) + * createMBean(className, name, loaderName, null, null, false)}; + */ + public final ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + return safeCreateMBean(className, name, loaderName, null, null, false); + } + + // make sure all exceptions are correctly wrapped in a JMXException + private ObjectInstance safeCreateMBean(String className, + ObjectName name, ObjectName loaderName, Object[] params, + String[] signature, boolean useRepository) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + try { + return createMBean(className, name, loaderName, params, + signature, useRepository); + } catch (ReflectionException x) { throw x; + } catch (InstanceAlreadyExistsException x) { throw x; + } catch (MBeanRegistrationException x) { throw x; + } catch (MBeanException x) { throw x; + } catch (NotCompliantMBeanException x) { throw x; + } catch (InstanceNotFoundException x) { throw x; + } catch (SecurityException x) { throw x; + } catch (JMRuntimeException x) { throw x; + } catch (RuntimeException x) { + throw new RuntimeOperationsException(x, x.toString()); + } catch (Exception x) { + throw new MBeanException(x, x.toString()); + } + } + + + /** + * {@inheritDoc} + * + *
This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public Object instantiate(String className) + throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("Not applicable."); + } + + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException { + throw new UnsupportedOperationException("Not applicable."); + } + + + // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException + // if the returned mbean is null. + // The DynamicMBean returned by this method is thus guaranteed to be + // non null. + // + private DynamicMBean nonNullMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (name == null) + throw newIllegalArgumentException("Null ObjectName"); + if (name.getDomain().equals("")) { + String defaultDomain = getDefaultDomain(); + try { + name = name.withDomain(getDefaultDomain()); + } catch (Exception e) { + throw newIllegalArgumentException( + "Illegal default domain: " + defaultDomain); + } + } + final DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean!=null) return mbean; + throw new InstanceNotFoundException(String.valueOf(name)); + } + + static RuntimeException newUnsupportedException(String operation) { + return new RuntimeOperationsException( + new UnsupportedOperationException( + operation+": Not supported in this namespace")); + } + + static RuntimeException newIllegalArgumentException(String msg) { + return new RuntimeOperationsException( + new IllegalArgumentException(msg)); + } + +} diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/namespace/VirtualEventManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/VirtualEventManager.java Thu Sep 04 14:46:36 2008 +0200 @@ -0,0 +1,378 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import com.sun.jmx.remote.util.ClassLogger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventConsumer; + +/** + *This class maintains a list of subscribers for ObjectName patterns and + * allows a notification to be sent to all subscribers for a given ObjectName. + * It is typically used in conjunction with {@link MBeanServerSupport} + * to implement a namespace with Virtual MBeans that can emit notifications. + * The {@code VirtualEventManager} keeps track of the listeners that have been + * added to each Virtual MBean. When an event occurs that should trigger a + * notification from a Virtual MBean, the {@link #publish publish} method can + * be used to send it to the appropriate listeners.
+ * @since 1.7 + */ +public class VirtualEventManager implements EventConsumer { + /** + *Create a new {@code VirtualEventManager}.
+ */ + public VirtualEventManager() { + } + + public void subscribe( + ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) { + + if (logger.traceOn()) + logger.trace("subscribe", "" + name); + + if (name == null) + throw new IllegalArgumentException("Null MBean name"); + + if (listener == null) + throw new IllegalArgumentException("Null listener"); + + MapUnsubscribes a listener which is listening to an MBean or a set of + * MBeans represented by an {@code ObjectName} pattern.
+ * + *The listener to be removed must have been added by the {@link + * #subscribe subscribe} method with the given {@code name}, {@code filter}, + * and {@code handback}. If the {@code + * name} is a pattern, then the {@code subscribe} must have used the same + * pattern. If the same listener has been subscribed more than once to the + * {@code name} with the same filter and handback, only one listener is + * removed.
+ * + * @param name The name of the MBean or an {@code ObjectName} pattern + * representing a set of MBeans to which the listener was subscribed. + * @param listener A listener that was previously subscribed to the + * MBean(s). + * + * @throws ListenerNotFoundException The given {@code listener} was not + * subscribed to the given {@code name}. + * + * @see #subscribe + */ + public void unsubscribe( + ObjectName name, NotificationListener listener, + NotificationFilter filter, Object handback) + throws ListenerNotFoundException { + + if (logger.traceOn()) + logger.trace("unsubscribe4", "" + name); + + if (name == null) + throw new IllegalArgumentException("Null MBean name"); + + if (listener == null) + throw new ListenerNotFoundException(); + + MapSends a notification to the subscribers for a given MBean.
+ * + *For each listener subscribed with an {@code ObjectName} that either + * is equal to {@code emitterName} or is a pattern that matches {@code + * emitterName}, if the associated filter accepts the notification then it + * is forwarded to the listener.
+ * + * @param emitterName The name of the MBean emitting the notification. + * @param n The notification being sent by the MBean called + * {@code emitterName}. + * + * @throws IllegalArgumentException If the emitterName of the + * notification is null or is an {@code ObjectName} pattern. + */ + public void publish(ObjectName emitterName, Notification n) { + if (logger.traceOn()) + logger.trace("publish", "" + emitterName); + + if (n == null) + throw new IllegalArgumentException("Null notification"); + + if (emitterName == null) { + throw new IllegalArgumentException( + "Null emitter name"); + } else if (emitterName.isPattern()) { + throw new IllegalArgumentException( + "The emitter must not be an ObjectName pattern"); + } + + final ListReturns a {@link NotificationEmitter} object which can be used to + * subscribe or unsubscribe for notifications with the named + * mbean. The returned object implements {@link + * NotificationEmitter#addNotificationListener + * addNotificationListener(listener, filter, handback)} as + * {@link #subscribe this.subscribe(name, listener, filter, handback)} + * and the two {@code removeNotificationListener} methods from {@link + * NotificationEmitter} as the corresponding {@code unsubscribe} methods + * from this class.
+ * + * @param name The name of the MBean whose notifications are being + * subscribed, or unsuscribed. + * + * @return A {@link NotificationEmitter} + * that can be used to subscribe or unsubscribe for + * notifications emitted by the named MBean, or {@code null} if + * the MBean does not emit notifications and should not + * be considered as a {@code NotificationBroadcaster}. This class + * never returns null but a subclass is allowed to. + * + * @throws InstanceNotFoundException if {@code name} does not exist. + * This implementation never throws {@code InstanceNotFoundException} but + * a subclass is allowed to override this method to do so. + */ + public NotificationEmitter + getNotificationEmitterFor(final ObjectName name) + throws InstanceNotFoundException { + final NotificationEmitter emitter = new NotificationEmitter() { + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws IllegalArgumentException { + subscribe(name, listener, filter, handback); + } + + public void removeNotificationListener( + NotificationListener listener) + throws ListenerNotFoundException { + unsubscribe(name, listener); + } + + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + throws ListenerNotFoundException { + unsubscribe(name, listener, filter, handback); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + // Never called. + return null; + } + }; + return emitter; + } + + // --------------------------------- + // private stuff + // --------------------------------- + + private static class ListenerInfo { + public final NotificationListener listener; + public final NotificationFilter filter; + public final Object handback; + + public ListenerInfo(NotificationListener listener, + NotificationFilter filter, + Object handback) { + + if (listener == null) { + throw new IllegalArgumentException("Null listener."); + } + + this.listener = listener; + this.filter = filter; + this.handback = handback; + } + + /* Two ListenerInfo instances are equal if they have the same + * NotificationListener. This means that we can use List.remove + * to implement the two-argument removeNotificationListener. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof ListenerInfo)) { + return false; + } + + return listener.equals(((ListenerInfo)o).listener); + } + + /* Method that compares all four fields, appropriate for the + * four-argument removeNotificationListener. + */ + boolean equals( + NotificationListener listener, + NotificationFilter filter, + Object handback) { + return (this.listener == listener && same(this.filter, filter) + && same(this.handback, handback)); + } + + private static boolean same(Object x, Object y) { + if (x == y) + return true; + if (x == null) + return false; + return x.equals(y); + } + + @Override + public int hashCode() { + return listener.hashCode(); + } + } + + private static void sendNotif(ListThe javax.management.namespace
package makes it possible
+ * to federate MBeanServers into a hierarchical name space.
+ * A name space is like an {@link javax.management.MBeanServer} within + * an {@code MBeanServer}. Just as a file system folder can contain + * another file system folder, an {@code MBeanServer} can contain another + * {@code MBeanServer}. Similarly, just as a remote folder on a remote + * disk can be mounted on a parent folder on a local disk, a remote name + * space in a remote {@code MBeanServer} can be mounted on a name + * space in a local parent {@code MBeanServer}. + *
+ *
+ * The javax.management.namespace
API thus makes it possible to
+ * create a hierarchy of MBean servers federated in a hierarchical name
+ * space inside a single {@code MBeanServer}.
+ *
+ * To create a name space, you only need to register a + * {@link javax.management.namespace.JMXNamespace} MBean in + * an MBean server. We have seen that a namespace is like + * an {@code MBeanServer} within an {@code MBeanServer}, and + * therefore, it is possible to create a namespace that shows the + * content of another {@code MBeanServer}. The simplest case is + * when that {@code MBeanServer} is another {@code MBeanServer} + * created by the {@link javax.management.MBeanServerFactory} as + * shown in the extract below: + *
+ *+ * final MBeanServer server = ....; + * final String namespace = "foo"; + * final ObjectName namespaceName = {@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName + * JMXNamespaces.getNamespaceObjectName(namespace)}; + * server.registerMBean(new JMXNamespace(MBeanServerFactory.newMBeanServer()), + * namespaceName); + *+ *
+ * To navigate in namespaces and view their content, the easiest way is + * to use an instance of {@link javax.management.namespace.JMXNamespaceView}. For instance, given + * the {@code server} above, in which we created a namespace {@code "foo"}, + * it is possible to create a {@code JMXNamespaceView} that will make it + * possible to navigate easily in the namespaces and sub-namespaces of that + * server: + *
+ *+ * // create a namespace view for 'server' + * final JMXNamespaceView view = new JMXNamespaceView(server); + * + * // list all top level namespaces in 'server' + * System.out.println("List of namespaces: " + Arrays.toString({@link javax.management.namespace.JMXNamespaceView#list() view.list()})); + * + * // go down into namespace 'foo': provides a namespace view of 'foo' and its + * // sub namespaces... + * final JMXNamespaceView foo = {@link javax.management.namespace.JMXNamespaceView#down view.down("foo")}; + * + * // list all MBeans contained in namespace 'foo' + * System.out.println({@link javax.management.namespace.JMXNamespaceView#where() foo.where()} + " contains: " + + * {@link javax.management.namespace.JMXNamespaceView#getMBeanServerConnection foo.getMBeanServerConnection()}.queryNames(null,null)); + *+ *
+ * It is also possible to create more complex namespaces, such as namespaces + * that point to MBean servers located in remote JVMs. + *
+ *
+ * For instance, to mount the MBeanServer accessible
+ * at service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi
+ * in a name space {@code "foo"} inside the {@linkplain
+ * java.lang.management.ManagementFactory#getPlatformMBeanServer platform
+ * MBeanServer} you would write the following piece of code:
+ *
+ * final JMXServiceURL sourceURL = + * new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi"); + * final MBeanServer platform = ManagementFactory.getPlatformMBeanServer(); + * final Map<String,Object> options = Collections.emptyMap(); + * final JMXRemoteNamespace mbean = {@link + * javax.management.namespace.JMXRemoteNamespace JMXRemoteNamespace}. + * {@link javax.management.namespace.JMXRemoteNamespace#newJMXRemoteNamespace newJMXRemoteNamespace(sourceURL, options)}; + * final ObjectName name = {@link javax.management.namespace.JMXNamespaces JMXNamespaces}.{@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName(String) getNamespaceObjectName("foo")}; + * final ObjectInstance ref = platform.registerMBean(mbean,name); + * platform.invoke(ref.getObjectName(),"connect",null,null); + *+ * + *
+ * We have seen that {@link javax.management.namespace.JMXNamespaceView} class + * provides an easy way to navigate within namespaces. It is however also + * possible to interact with namespaces directly from the top level + * {@code MBeanServer} in which they have been created. + * From the outside, a name space only appears as a special MBean in + * the MBean server. There's nothing much you can do with this MBean + * directly. + *
+ *
+ * For instance, let's assume you have registered a {@link
+ * javax.management.namespace.JMXRemoteNamespaceMBean
+ * JMXRemoteNamespaceMBean} to manage the name space {@code "foo"}.
+ *
If you query for
+ * platform.queryNames("*//:*",null)
, then you will see
+ * one MBean named {@code "foo//:type=JMXNamespace"}.
+ *
This is the {@link javax.management.namespace.JMXNamespace}
+ * MBean which is in charge of handling the namespace {@code "foo"}.
+ *
+ * In fact, name space handler MBeans are instances of
+ * the class {@link javax.management.namespace.JMXNamespace} - or
+ * instances of a subclass of that class.
+ * They have a special {@link javax.management.ObjectName} defined by
+ * {@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName
+ * JMXNamespaces.getNamespaceObjectName}.
+ * {@link javax.management.namespace.JMXNamespace} instances are able
+ * to return an {@link
+ * javax.management.namespace.JMXNamespace#getSourceServer MBeanServer}
+ * which corresponds to the MBeanServer within (= the name space itself).
+ *
+ * So how does it work? How can you see the MBeans contained in the new + * name space? + *
+ *In order to address scalability issues, MBeans registered in + * namespaces (such as our namespace {@code "foo"} above) can not be + * seen with {@code mbeanServer.queryNames("*:*",null)}. To see the MBeans + * contained in a namespace, you can use one of these methods: + *
+ *
+ * As we have explained above, MBeans contained in name
+ * spaces are not returned by {@code server.queryNames(null,null)} - or
+ * server.queryNames({@link javax.management.ObjectName#WILDCARD ObjectName.WILDCARD},null)
.
+ *
+ * However, these MBeans can still be accessed from the top level
+ * {@code MBeanServer} interface, without using any API specific to the
+ * version 2.0 of the JMX API, simply by using object names with
+ * name space prefixes:
+ *
To list MBeans contained in a namespace {@code "foo"} you can
+ * query for MBeans whose names match {@code "foo//*:*"}, as shown
+ * earlier in this document:
+ *
+ * server.queryNames(new ObjectName("foo//*:*", null); + * // or equivalently: + * server.queryNames(JMXNamespaces.getWildcardFor("foo"), null); + *+ * This will return a list of MBean names whose domain name starts + * with {@code foo//}. + *
+ * Using these names, you can invoke any operation on the corresponding + * MBeans. For instance, to get the {@link javax.management.MBeanInfo + * MBeanInfo} of an MBean + * contained in name space {@code "foo"} (assuming + * the name of the MBean within its name space is domain:type=Thing, + * then simply call: + *
+ * server.getMBeanInfo(new ObjectName("foo//domain:type=Thing")); + *+ * An easier way to access MBeans contained in a name space is to + * cd inside the name space, as shown in the following paragraph. + * + * + *
+ * As we have seen, name spaces are like MBean servers within MBean servers.
+ * Therefore, it is possible to view a name space just as if it were
+ * an other MBean server. This is similar to opening a sub
+ * folder from a parent folder.
+ * This operation is illustrated in the code extract below:
+ *
+ * final MBeanServer foo = + * JMXNamespaces.narrowToNamespace(platform, "foo"); + * final MBeanInfo info = + * foo.getMBeanInfo(new ObjectName("domain:type=Thing")); + *+ * The {@code MBeanServer} returned by {@link + * javax.management.namespace.JMXNamespaces#narrowToNamespace(MBeanServer,String) + * JMXNamespaces.narrowToNamespace} is an {@code MBeanServer} view that + * narrows down into a given namespace. The MBeans contained inside that + * namespace can now be accessed by their regular local name.
+ * Note: If you have a deep hierarchy of namespaces, and if you + * are switching from one namespace to another in the course of your + * application, it might be more convenient to use a + * {@link javax.management.namespace.JMXNamespaceView} + * in order to navigate in your namespaces. + *
+ * + *+ * This API lets you create several types of name spaces: + *
+ * MBean Naming considerations aside, Name Spaces are transparent for + * most {@code MBeanServer} operations. There are however a few + * exceptions: + *
+ *MBeanServer only operations - these are the operations which are + * supported by {@link javax.management.MBeanServer MBeanServer} but + * are not present in {@link + * javax.management.MBeanServerConnection + * MBeanServerConnection}. Since a name space can be a local view of + * a remote {@code MBeanServer}, accessible only through an + * {@code MBeanServerConnection}, these + * kinds of operations are not always supported.
+ *registerMBean:
+ *The {@link javax.management.MBeanServer#registerMBean + * registerMBean} + * operation is not supported by most name spaces. A call + * to + *
+ * MBeanServer server = ....; + * ThingMBean mbean = new Thing(...); + * ObjectName name = new ObjectName("foo//domain:type=Thing"); + * server.registerMBean(mbean, name); + *+ * will usually fail, unless the name space + * {@code "foo"} is a local name + * space. In the case where you attempt to cross + * multiple name spaces, then all name spaces in the + * path must support the {@code registerMBean} operation + * in order for it to succeed.
getClassLoader:
+ * Similarly to registerMBean,
+ * and for the same reasons, {@link
+ * javax.management.MBeanServer#getClassLoader
+ * getClassLoader} will usually fail, unless the
+ * class loader is an MBean registered in a
+ * local name space.
+ *
getClassLoaderFor:
+ *The implementation of {@link + * javax.management.MBeanServer#getClassLoaderFor + * getClassLoaderFor} also depends on which + * type of name space + * handler is used across the namespace path. + *
+ *+ * A local name space will usually + * be able to implement this method just as a real + * {@code MBeanServer} would. A + * remote name space will usually + * return the default class loader configured on the + * internal {@link javax.management.remote.JMXConnector + * JMXConnector} used to connect to the remote server. + * When a {@link + * javax.management.namespace.JMXRemoteNamespace + * JMXRemoteNamespace} is used to connect to a + * remote server that contains MBeans which export + * custom types, the {@link + * javax.management.namespace.JMXRemoteNamespace + * JMXRemoteNamespace} must thus be configured with + * an options map such that the underlying connector + * can obtain a default class loader able + * to handle those types. + *
+ *+ * Other types of name spaces + * may implement this method + * as best as they can. + *
+ *MBean creation
+ *MBean creation through {@link + * javax.management.MBeanServerConnection#createMBean + * createMBean} might not be supported by all + * name spaces: local name spaces and + * remote name spaces will usually + * support it, but virtual name + * spaces and custom name + * spaces might not. + *
+ *+ * In that case, they will throw an {@link + * java.lang.UnsupportedOperationException + * UnsupportedOperationException} usually wrapped into an {@link + * javax.management.MBeanRegistrationException}. + *
+ *Notifications
+ *Some namespaces might not support JMX Notifications. In that + * case, a call to add or remove notification listener for an + * MBean contained in that name space will raise a + * {@link javax.management.RuntimeOperationsException + * RuntimeOperationsException} wrapping an {@link + * java.lang.UnsupportedOperationException + * UnsupportedOperationException} exception. + *
+ *+ * Just as folders can contain other folders, name spaces can contain + * other name spaces. For instance, if an {@code MBeanServer} S1 + * containing a name space {@code "bar"} is mounted in another + * {@code MBeanServer} S2 with name space {@code "foo"}, then + * an MBean M1 named {@code "domain:type=Thing"} in namespace + * {@code "bar"} will appear as {@code "foo//bar//domain:type=Thing"} in + * {@code MBeanServer} S2. + *
+ *+ * When accessing the MBean M1 from server S2, the + * method call will traverse in a cascade {@code MBeanServer} S2, + * then the name space handler for name space {@code "foo"}, then + * {@code MBeanServer} S1, before coming to the name space + * handler for name space {@code "bar"}. Any operation invoked + * on the MBean from a "top-level" name space will therefore need to + * traverse all the name spaces along the name space path until + * it eventually reaches the named MBean. This means that an operation + * like registerMBean for instance, + * can only succeed if all the name spaces along the path support it. + *
+ *+ * Narrowing to a nested name space works just the same as narrowing + * to a top level name space: + *
+ * final MBeanServer S2 = .... ; + * final MBeanServer bar = + * JMXNamespaces.narrowToNamespace(S2, "foo//bar"); + * final MBeanInfo info = + * foo.getMBeanInfo(new ObjectName("domain:type=Thing")); + *+ * + * + *
+ * Operation results, as well as attribute values returned by an MBean
+ * contained in a name space must be interpreted in the context of that
+ * name space.
+ * In other words, if an MBean in name space "foo" has an attribute of
+ * type {@code ObjectName}, then it must be assumed that the
+ * {@code ObjectName} returned by that MBean is relative to
+ * name space "foo".
+ * The same rule aplies for MBean names that can be returned by
+ * operations invoked on such an MBean. If one of the MBean operations
+ * return, say, a {@code Set
+ *
+ * In the usual case, a JMX client will first
+ * narrow to a name space before invoking
+ * any operation on the MBeans it contains. In that case the names
+ * returned by the MBean invoked can be directly fed back to the
+ * narrowed connection.
+ *
+ * If however, the JMX client directly invoked the MBean from a higher
+ * name space, without having narrowed to that name space first, then
+ * the names that might be returned by that MBean will not be directly
+ * usable - the JMX client will need to either
+ * narrow to the name space before using the
+ * returned names, or convert the names to the higher level name space
+ * context.
+ *
+ * The {@link javax.management.namespace.JMXNamespaces JMXNamespaces}
+ * class provides methods that can be used to perform that conversion.
+ *
+ * As already explained, name spaces are very
+ * similar to {@code MBeanServer}s. It is thus possible to get
+ * {@link javax.management.MBeanServerNotification MBeanServerNotifications}
+ * when MBeans are added or removed within a name space, by registering
+ * with the {@link javax.management.MBeanServerDelegate
+ * MBeanServerDelegate} MBean of the corresponding name space.
+ * However, it must be noted that the notifications emitted by a
+ * name space must be interpreted in the context of that name space.
+ * For instance, if an MBean {@code "domain:type=Thing"} contained in
+ * namespace "foo//bar" emits a notification, the source of the
+ * notification will be {@code "domain:type=Thing"}, not
+ * {@code "foo//bar//domain:type=Thing"}.
+ * It is therefore recommended to keep track of the name space
+ * information when registering a listener with an MBean contained in
+ * a name space, especially if the same listener is used to receive
+ * notifications from different name spaces. An easy solution is to
+ * use the handback, as illustrated in the code below.
+ *
+ * final MBeanServer server = ...; + * final NotificationListener listener = new NotificationListener() { + * public void handleNotification(Notification n, Object handback) { + * if (!(n instanceof MBeanServerNotification)) { + * System.err.println("Error: expected MBeanServerNotification"); + * return; + * } + * final MBeanServerNotification mbsn = + * (MBeanServerNotification) n; + * + * // We will pass the namespace path in the handback. + * // + * // The received notification must be interpreted in + * // the context of its source - therefore + * // mbsn.getMBeanName() does not include the name space + * // path... + * // + * final String namespace = (String) handback; + * System.out.println("Received " + mbsn.getType() + + * " for MBean " + mbsn.getMBeanName() + + * " from name space " + namespace); + * } + * }; + * server.addNotificationListener(JMXNamespaces.insertPath("foo//bar", + * MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//bar"); + * server.addNotificationListener(JMXNamespaces.insertPath("foo//joe", + * MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//joe"); + *+ * + *
+ * JMX Connectors may require some configuration in order to be able + * to forward notifications from MBeans located in name spaces. + * The RMI JMX Connector Server + * in the Java SE 7 platform is configured by default to internally + * use the new {@linkplain javax.management.event event service} on + * the server side. + * When the connector server is configured in this way, JMX clients + * which use the old JMX Notifications mechanism (such as clients + * running on prior versions of the JDK) will be able to + * to receive notifications from MBeans located in sub name spaces. + * This is because the connector server will transparently delegate + * their subscriptions to the underlying {@linkplain + * javax.management.event event service}. In summary: + *
+ * These configuration issues apply at each node in the name space path, + * whenever the name space points to a remote server. The + * {@link javax.management.namespace.JMXRemoteNamespace + * JMXRemoteNamespace} can be configured in such a way that it will + * explicitly use an {@link javax.management.event.EventClient EventClient} + * when forwarding subscription to the remote side. Note that this can be + * unnecessary (and a waste of resources) if the underlying JMXConnector + * returned by the JMXConnectorFactory (client side) already uses the + * {@linkplain javax.management.event event service} to register for + * notifications with the server side. + *
+ * + *+ * Access to MBeans exposed through JMX namespaces is controlled by + * {@linkplain javax.management.namespace.JMXNamespacePermission + * jmx namespace permissions}. These permissions are checked by the + * MBeanServer in which the {@link + * javax.management.namespace.JMXNamespace JMXNamespace} MBean is registered. + * This is described in + * details in the {@link + * javax.management.namespace.JMXNamespace JMXNamespace} class. + *
+ *+ * To implement a "firewall-like" access control in a JMX agent you + * can also place an {@link + * javax.management.remote.MBeanServerForwarder} in the JMX Connector + * Server which exposes the top-level MBeanServer of your application. + * This {@code MBeanServerForwarder} will be able to perform + * authorization checks for all MBeans, including those located in + * sub name spaces. + *
+ *+ * For a tighter access control we recommend using a {@link + * java.lang.SecurityManager security manager}. + *
+ * @since 1.7 + * + **/ + +package javax.management.namespace; + diff -r a9a142fcf1b5 -r bbc2d15aaf7a jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java --- a/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java Wed Sep 03 14:31:17 2008 +0200 +++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java Thu Sep 04 14:46:36 2008 +0200 @@ -268,6 +268,14 @@ return conn; } + private staticCreates a connector client for the connector server at the
* given address. The resultant client is not connected until its
@@ -300,16 +308,18 @@
public static JMXConnector newJMXConnector(JMXServiceURL serviceURL,
Map