/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.mx.remoting.rmi; import java.io.IOException; import java.io.NotSerializableException; import java.rmi.MarshalledObject; 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.MBeanServerConnection; import javax.management.NotCompliantMBeanException; 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.rmi.RMIConnection; import javax.security.auth.Subject; /** * This is the class that is passed to the client and is called * on by the client to make the remote MBeanServer calls. This * is really just a delegate to the rmi connection. * * @author <a href="mailto:tom.elrod@jboss.com">Tom Elrod</a> */ public class ClientMBeanServerConnection implements MBeanServerConnection { private RMIConnection connection = null; private Subject subject = null; private transient ClassLoader defaultClassLoader = null; private ClientNotifier clientNotifier = null; public ClientMBeanServerConnection(RMIConnection rmiConnection, ClientNotifier clientNotifier, ClassLoader classLoader, Subject subject) { this.connection = rmiConnection; this.clientNotifier = clientNotifier; this.defaultClassLoader = classLoader; this.subject = subject; } private ClassLoader activateDefaultClassLoader() { final ClassLoader current = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(defaultClassLoader); return current; } private void deActivateDefaultClassLoader(ClassLoader previousClassLoader) { Thread.currentThread().setContextClassLoader(previousClassLoader); } /** * Create an MBean registered using the given object name.<p> * <p/> * Uses the default contructor. * * @param className the class name of the mbean * @param name the object name for registration, can be null * @return an ObjectInstance describing the registration * @throws javax.management.ReflectionException * for class not found or an exception * invoking the contructor * @throws javax.management.InstanceAlreadyExistsException * for an MBean already registered * with the passed or generated ObjectName * @throws javax.management.MBeanRegistrationException * for any exception thrown by the * MBean's preRegister * @throws javax.management.MBeanException * for any exception thrown by the MBean's constructor * @throws javax.management.NotCompliantMBeanException * if the class name does not correspond to * a valid MBean * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null class name, the ObjectName could not be determined or it is a pattern * @throws java.io.IOException for a communication problem during this operation */ public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.createMBean(className, name, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Create an MBean registered using the given object name.<p> * <p/> * The MBean is loaded using the passed classloader. Uses the default contructor. * * @param className the class name of the mbean * @param loaderName an MBean that implements a classloader * @param name the object name for registration, can be null * @return an ObjectInstance describing the registration * @throws javax.management.ReflectionException * for class not found or an exception * invoking the contructor * @throws javax.management.InstanceAlreadyExistsException * for an MBean already registered * with the passed or generated ObjectName * @throws javax.management.MBeanRegistrationException * for any exception thrown by the * MBean's preRegister * @throws javax.management.MBeanException * for any exception thrown by the MBean's constructor * @throws javax.management.InstanceNotFoundException * if the loaderName is not a classloader registered * in the MBeanServer * @throws javax.management.NotCompliantMBeanException * if the class name does not correspond to * a valid MBean * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null class name, the ObjectName could not be determined or it is a pattern * @throws java.io.IOException for a communication problem during this operation */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException, IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.createMBean(className, name, loaderName, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Create an MBean registered using the given object name.<p> * <p/> * Uses the specified constructor. * * @param className the class name of the mbean * @param name the object name for registration, can be null * @param params the parameters for the constructor * @param signature the signature of the constructor * @return an ObjectInstance describing the registration * @throws javax.management.ReflectionException * for class not found or an exception * invoking the contructor * @throws javax.management.InstanceAlreadyExistsException * for an MBean already registered * with the passed or generated ObjectName * @throws javax.management.MBeanRegistrationException * for any exception thrown by the * MBean's preRegister * @throws javax.management.MBeanException * for any exception thrown by the MBean's constructor * @throws javax.management.NotCompliantMBeanException * if the class name does not correspond to * a valid MBean * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null class name, the ObjectName could not be determined or it is a pattern * @throws java.io.IOException for a communication problem during this operation */ public ObjectInstance createMBean(String className, ObjectName name, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, IOException { MarshalledObject args = new MarshalledObject(params); final ClassLoader current = activateDefaultClassLoader(); try { return connection.createMBean(className, name, args, signature, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Create an MBean registered using the given object name.<p> * <p/> * The MBean is loaded using the passed classloader. Uses the specified constructor. * * @param className the class name of the mbean * @param loaderName an MBean that implements a classloader * @param name the object name for registration, can be null * @param params the parameters for the constructor * @param signature the signature of the constructor * @return an ObjectInstance describing the registration * @throws javax.management.ReflectionException * for class not found or an exception * invoking the contructor * @throws javax.management.InstanceAlreadyExistsException * for an MBean already registered * with the passed or generated ObjectName * @throws javax.management.MBeanRegistrationException * for any exception thrown by the * MBean's preRegister * @throws javax.management.MBeanException * for any exception thrown by the MBean's constructor * @throws javax.management.InstanceNotFoundException * if the loaderName is not a classloader registered * in the MBeanServer * @throws javax.management.NotCompliantMBeanException * if the class name does not correspond to * a valid MBean * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null class name, the ObjectName could not be determined or it is a pattern * @throws java.io.IOException for a communication problem during this operation */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException, IOException { MarshalledObject args = new MarshalledObject(params); final ClassLoader current = activateDefaultClassLoader(); try { return connection.createMBean(className, name, loaderName, args, signature, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Unregisters an mbean. * * @param name the object name of the mbean to unregister * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * in the MBeanServer * @throws javax.management.MBeanRegistrationException * for any exception thrown by the * MBean's preDeregister * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null name, or trying to unregister a JMX implementation MBean * @throws java.io.IOException for a communication problem during this operation */ public void unregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException, IOException { final ClassLoader current = activateDefaultClassLoader(); try { connection.unregisterMBean(name, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Retrieve an MBean's registration information. * * @param name the object name of the mbean * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * in the MBeanServer * @throws java.io.IOException for a communication problem during this operation */ public ObjectInstance getObjectInstance(ObjectName name) throws InstanceNotFoundException, IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.getObjectInstance(name, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Retrieve a set of Object instances * * @param name an ObjectName pattern, can be null for all mbeans * @param query a query expression to further filter the mbeans, can be null * for no query * @throws java.io.IOException for a communication problem during this operation */ public Set queryMBeans(ObjectName name, QueryExp query) throws IOException { MarshalledObject args = new MarshalledObject(query); final ClassLoader current = activateDefaultClassLoader(); try { return connection.queryMBeans(name, args, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Retrieve a set of Object names * * @param name an ObjectName pattern, can be null for all mbeans * @param query a query expression to further filter the mbeans, can be null * for no query * @throws java.io.IOException for a communication problem during this operation */ public Set queryNames(ObjectName name, QueryExp query) throws IOException { MarshalledObject args = new MarshalledObject(query); final ClassLoader current = activateDefaultClassLoader(); try { return connection.queryNames(name, args, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Test whether an mbean is registered. * * @param name the object name of the mbean * @return true when the mbean is registered, false otherwise * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null name * @throws java.io.IOException for a communication problem during this operation */ public boolean isRegistered(ObjectName name) throws IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.isRegistered(name, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Retrieve the number of mbeans registered in the server. * * @return true the number of registered mbeans * @throws java.io.IOException for a communication problem during this operation */ public Integer getMBeanCount() throws IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.getMBeanCount(subject); } finally { deActivateDefaultClassLoader(current); } } /** * Retrieve a value from an MBean. * * @param name the object name of the mbean * @param attribute the attribute name of the value to retrieve * @return the value * @throws javax.management.ReflectionException * for an exception invoking the mbean * @throws javax.management.MBeanException * for any exception thrown by the mbean * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * @throws javax.management.AttributeNotFoundException * if the mbean has no such attribute * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null name or attribute * @throws java.io.IOException for a communication problem during this operation */ public Object getAttribute(ObjectName name, String attribute) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.getAttribute(name, attribute, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Retrieve a list of values from an MBean. * * @param name the object name of the mbean * @param attributes the attribute names of the values to retrieve * @return the list of values, attributes with errors are ignored * @throws javax.management.ReflectionException * for an exception invoking the mbean * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null name or attributes * @throws java.io.IOException for a communication problem during this operation */ public AttributeList getAttributes(ObjectName name, String[] attributes) throws InstanceNotFoundException, ReflectionException, IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.getAttributes(name, attributes, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Set a value for an MBean. * * @param name the object name of the mbean * @param attribute the attribute name and value to set * @throws javax.management.ReflectionException * for an exception invoking the mbean * @throws javax.management.MBeanException * for any exception thrown by the mbean * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * @throws javax.management.AttributeNotFoundException * if the mbean has no such attribute * @throws javax.management.InvalidAttributeValueException * if the new value has an incorrect type * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null name or attribute * @throws java.io.IOException for a communication problem during this operation */ public void setAttribute(ObjectName name, Attribute attribute) throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException, IOException { MarshalledObject args = new MarshalledObject(attribute); final ClassLoader current = activateDefaultClassLoader(); try { connection.setAttribute(name, args, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Set a list of values for an MBean. * * @param name the object name of the mbean * @param attributes the attribute names and values to set * @return the list of values, attributes with errors are ignored * @throws javax.management.ReflectionException * for an exception invoking the mbean * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null name or attributes * @throws java.io.IOException for a communication problem during this operation */ public AttributeList setAttributes(ObjectName name, AttributeList attributes) throws InstanceNotFoundException, ReflectionException, IOException { MarshalledObject args = new MarshalledObject(attributes); final ClassLoader current = activateDefaultClassLoader(); try { return connection.setAttributes(name, args, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Invokes an operation on an mbean. * * @param name the object name of the mbean * @param operationName the operation to perform * @param params the parameters * @param signature the signature of the operation * @return any result of the operation * @throws javax.management.ReflectionException * for an exception invoking the mbean * @throws javax.management.MBeanException * for any exception thrown by the mbean * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * @throws java.io.IOException for a communication problem during this operation */ public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature) throws InstanceNotFoundException, MBeanException, ReflectionException, IOException { MarshalledObject args = new MarshalledObject(params); final ClassLoader current = activateDefaultClassLoader(); try { return connection.invoke(name, operationName, args, signature, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Retrieve the default domain of the mbeanserver. * * @return the default domain * @throws java.io.IOException for a communication problem during this operation */ public String getDefaultDomain() throws IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.getDefaultDomain(subject); } finally { deActivateDefaultClassLoader(current); } } /** * Retrieve the domains of the mbeanserver. * * @return the domains * @throws java.io.IOException for a communication problem during this operation */ public String[] getDomains() throws IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.getDomains(subject); } finally { deActivateDefaultClassLoader(current); } } /** * Add a notification listener to an MBean. * * @param name the name of the MBean broadcasting notifications * @param listener the listener to add * @param filter a filter to preprocess notifications * @param handback a object to add to any notifications * @throws javax.management.InstanceNotFoundException * if the broadcaster is not registered * @throws java.io.IOException for a communication problem during this operation */ public void addNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException, IOException { ClientListenerHolder holder = new ClientListenerHolder(name, listener, filter, handback); // if this listener already exists within the ClientNotifier, then assume has already been // properly registered as a listener and can ignore call if(clientNotifier.exists(holder)) { return; } else { MarshalledObject marshalledFilter = null; if(filter != null) { try { marshalledFilter = new MarshalledObject(filter); } catch(IOException e) { holder.setFilterOnClient(true); } } Integer[] listenerIDs = connection.addNotificationListeners(new ObjectName[] {name}, new MarshalledObject[]{marshalledFilter}, new Subject[]{subject}); clientNotifier.addNotificationListener(listenerIDs[0], holder); } } /** * Add a notification listener to an MBean. * * @param name the name of the MBean broadcasting notifications * @param listener the object name listener to add * @param filter a filter to preprocess notifications * @param handback a object to add to any notifications * @throws javax.management.InstanceNotFoundException * if the broadcaster or listener is not registered * @throws javax.management.RuntimeOperationsException * wrapping an IllegalArgumentException for a * null listener or the listener does not implement the Notification Listener interface * @throws java.io.IOException for a communication problem during this operation */ public void addNotificationListener(ObjectName name, ObjectName listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException, IOException { MarshalledObject marshalledFilter = filter != null ? new MarshalledObject(filter) : null; MarshalledObject marshalledHandback = handback != null ? new MarshalledObject(handback) : null; connection.addNotificationListener(name, listener, marshalledFilter, marshalledHandback, subject); } /** * Removes a listener from an mbean.<p> * <p/> * All registrations of the listener are removed. * * @param name the name of the MBean broadcasting notifications * @param listener the object name of the listener to remove * @throws javax.management.InstanceNotFoundException * if the broadcaster or listener is not registered * @throws javax.management.ListenerNotFoundException * if the listener is not registered against the broadcaster * @throws java.io.IOException for a communication problem during this operation */ public void removeNotificationListener(ObjectName name, ObjectName listener) throws InstanceNotFoundException, ListenerNotFoundException, IOException { connection.removeNotificationListener(name, listener, subject); } /** * Removes a listener from an mbean.<p> * <p/> * Only the listener that was registered with the same filter and handback is removed. * * @param name the name of the MBean broadcasting notifications * @param listener the object name of listener to remove * @param filter the filter of the listener to remove * @throws javax.management.InstanceNotFoundException * if the broadcaster or listener is not registered * @throws javax.management.ListenerNotFoundException * if the listener, filter, handback * is not registered against the broadcaster * @throws java.io.IOException for a communication problem during this operation */ public void removeNotificationListener(ObjectName name, ObjectName listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException, ListenerNotFoundException, IOException { MarshalledObject marshalledFilter = filter != null ? new MarshalledObject(filter) : null; MarshalledObject marshalledHandback = handback != null ? new MarshalledObject(handback) : null; connection.removeNotificationListener(name, listener, marshalledFilter, marshalledHandback, subject); } /** * Removes a listener from an mbean.<p> * <p/> * All registrations of the listener are removed. * * @param name the name of the MBean broadcasting notifications * @param listener the listener to remove * @throws javax.management.InstanceNotFoundException * if the broadcaster is not registered * @throws javax.management.ListenerNotFoundException * if the listener is not registered against the broadcaster * @throws java.io.IOException for a communication problem during this operation */ public void removeNotificationListener(ObjectName name, NotificationListener listener) throws InstanceNotFoundException, ListenerNotFoundException, IOException { Integer[] ids = clientNotifier.getListeners(name, listener); if(ids == null || ids.length == 0) { throw new ListenerNotFoundException("Listener (" + listener + ") not found as a registered listener."); } connection.removeNotificationListeners(name, ids, subject); clientNotifier.removeListeners(ids); } /** * Removes a listener from an mbean.<p> * <p/> * Only the listener that was registered with the same filter and handback is removed. * * @param name the name of the MBean broadcasting notifications * @param listener the listener to remove * @param filter the filter of the listener to remove * @throws javax.management.InstanceNotFoundException * if the broadcaster is not registered * @throws javax.management.ListenerNotFoundException * if the listener, filter, handback * is not registered against the broadcaster * @throws java.io.IOException for a communication problem during this operation */ public void removeNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException, ListenerNotFoundException, IOException { Integer id = clientNotifier.getListener(new ClientListenerHolder(name, listener, filter, handback)); if(id == null) { throw new ListenerNotFoundException("Listener (" + listener + ") could not be found as registered listener."); } Integer[] ids = new Integer[]{id}; connection.removeNotificationListeners(name, ids, subject); clientNotifier.removeListeners(ids); } /** * Retrieves the jmx metadata for an mbean * * @param name the name of the mbean * @return the metadata * @throws javax.management.IntrospectionException * for any error during instrospection * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * @throws javax.management.ReflectionException * for any error trying to invoke the operation on the mbean * @throws java.io.IOException for a communication problem during this operation */ public MBeanInfo getMBeanInfo(ObjectName name) throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.getMBeanInfo(name, subject); } finally { deActivateDefaultClassLoader(current); } } /** * Tests whether an mbean can be cast to the given type * * @param name the name of the mbean * @param className the class name to check * @return true when it is of that type, false otherwise * @throws javax.management.InstanceNotFoundException * if the mbean is not registered * @throws java.io.IOException for a communication problem during this operation */ public boolean isInstanceOf(ObjectName name, String className) throws InstanceNotFoundException, IOException { final ClassLoader current = activateDefaultClassLoader(); try { return connection.isInstanceOf(name, className, subject); } finally { deActivateDefaultClassLoader(current); } } }