diff --git a/jdk/make/docs/CORE_PKGS.gmk b/jdk/make/docs/CORE_PKGS.gmk
index c768e7023db..dfedc7e1237 100644
--- a/jdk/make/docs/CORE_PKGS.gmk
+++ b/jdk/make/docs/CORE_PKGS.gmk
@@ -155,6 +155,7 @@ CORE_PKGS = \
javax.lang.model.type \
javax.lang.model.util \
javax.management \
+ javax.management.event \
javax.management.loading \
javax.management.monitor \
javax.management.relation \
diff --git a/jdk/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java b/jdk/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java
new file mode 100644
index 00000000000..85377d4d36b
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2007 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.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class DaemonThreadFactory implements ThreadFactory {
+ public DaemonThreadFactory(String nameTemplate) {
+ this(nameTemplate, null);
+ }
+
+ // nameTemplate should be a format with %d in it, which will be replaced
+ // by a sequence number of threads created by this factory.
+ public DaemonThreadFactory(String nameTemplate, ThreadGroup threadGroup) {
+ if (logger.debugOn()) {
+ logger.debug("DaemonThreadFactory",
+ "Construct a new daemon factory: "+nameTemplate);
+ }
+
+ if (threadGroup == null) {
+ SecurityManager s = System.getSecurityManager();
+ threadGroup = (s != null) ? s.getThreadGroup() :
+ Thread.currentThread().getThreadGroup();
+ }
+
+ this.nameTemplate = nameTemplate;
+ this.threadGroup = threadGroup;
+ }
+
+ public Thread newThread(Runnable r) {
+ final String name =
+ String.format(nameTemplate, threadNumber.getAndIncrement());
+ Thread t = new Thread(threadGroup, r, name, 0);
+ t.setDaemon(true);
+ if (t.getPriority() != Thread.NORM_PRIORITY)
+ t.setPriority(Thread.NORM_PRIORITY);
+
+ if (logger.debugOn()) {
+ logger.debug("newThread",
+ "Create a new daemon thread with the name "+t.getName());
+ }
+
+ return t;
+ }
+
+ private final String nameTemplate;
+ private final ThreadGroup threadGroup;
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+
+ private static final ClassLogger logger =
+ new ClassLogger("com.sun.jmx.event", "DaemonThreadFactory");
+}
diff --git a/jdk/src/share/classes/com/sun/jmx/event/EventBuffer.java b/jdk/src/share/classes/com/sun/jmx/event/EventBuffer.java
new file mode 100644
index 00000000000..bfdabdbb457
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/jmx/event/EventBuffer.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2007 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.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.TargetedNotification;
+
+public class EventBuffer {
+
+ public EventBuffer() {
+ this(Integer.MAX_VALUE, null);
+ }
+
+ public EventBuffer(int capacity) {
+ this(capacity, new ArrayList Manage a renewable lease. The lease can be renewed indefinitely
+ * but if the lease runs to its current expiry date without being renewed
+ * then the expiry callback is invoked. If the lease has already expired
+ * when renewal is attempted then the lease method returns zero. Renew the lease for the given time. The new time can be shorter
+ * than the previous one, in which case the lease will expire earlier
+ * than it would have. Calling this method after the lease has expired will return zero
+ * immediately and have no other effect. Cancel the lease without calling the expiry callback. A task that is repeatedly run by an Executor. The task will be
+ * repeated as long as the {@link #isSuspended()} method returns true. Once
+ * that method returns false, the task is no longer executed until someone
+ * calls {@link #resume()}. 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.
+ *
+ *
+ * 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 --git a/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java b/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java new file mode 100644 index 00000000000..ec53998f51a --- /dev/null +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java @@ -0,0 +1,414 @@ +/* + * 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.mbeanserver.Util; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +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.NotCompliantMBeanException; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.remote.IdentityMBeanServerForwarder; + +public class SingleMBeanForwarder extends IdentityMBeanServerForwarder { + + private final ObjectName mbeanName; + private DynamicMBean mbean; + + private MBeanServer mbeanMBS = new MBeanServerSupport() { + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (mbeanName.equals(name)) { + return mbean; + } else { + throw new InstanceNotFoundException(name.toString()); + } + } + + @Override + protected Set+ This API is a Sun internal API and is subject to changes without notice. +