/*
* 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.standardmbean;
import java.lang.reflect.Method;
import java.util.Iterator;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.ReflectionException;
import org.jboss.logging.Logger;
import org.jboss.mx.loading.LoaderRepository;
import org.jboss.mx.metadata.StandardMetaData;
import org.jboss.mx.server.ExceptionHandler;
/**
* A helper class to allow standard mbeans greater control over their
* management interface.<p>
*
* Extending this class actually makes the mbean a dynamic mbean, but
* with the convenience of a standard mbean.
*
* @todo make this more dynamic, somehow delegate to an XMBean?
*
* @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
* @author <a href="mailto:thomas.diesler@jboss.com">Thomas Diesler</a>.
* @version $Revision: 81022 $
*/
public class StandardMBeanImpl implements StandardMBeanDelegate
{
private static final Logger log = Logger.getLogger(StandardMBeanImpl.class);
/**
* The implementation object
*/
private Object implementation;
/**
* The management interface
*/
private Class mbeanInterface;
/**
* The cached mbeaninfo
*/
private MBeanInfo cachedMBeanInfo;
// Static -----------------------------------------------------
// Constructors ------------------------------------------------
/**
* Construct a DynamicMBean from the given implementation object
* and the passed management interface class.
*
* @param implementation the object implementing the mbean
* @param mbeanInterface the management interface of the mbean
* @exception IllegalArgumentException for a null implementation
* @exception NotCompliantMBeanException if the management interface
* does not follow the JMX design patterns or the implementation
* does not implement the interface
*/
public StandardMBeanImpl(Object implementation, Class mbeanInterface)
throws NotCompliantMBeanException
{
this.implementation = implementation;
this.mbeanInterface = mbeanInterface;
}
/**
* Construct a DynamicMBean from this object
* and the passed management interface class.<p>
*
* Used in subclassing
*
* @param mbeanInterface the management interface of the mbean
* @exception NotCompliantMBeanException if the management interface
* does not follow the JMX design patterns or this
* does not implement the interface
*/
protected StandardMBeanImpl(Class mbeanInterface)
throws NotCompliantMBeanException
{
this.implementation = this;
this.mbeanInterface = mbeanInterface;
}
/**
* Retrieve the implementation object
*
* @return the implementation
*/
public Object getImplementation()
{
return implementation;
}
/**
* Replace the implementation object
*
* @todo make this work after the mbean is registered
* @param implementation the new implementation
* @exception IllegalArgumentException for a null parameter
* @exception NotCompliantMBeanException if the new implementation
* does not implement the interface supplied at
* construction
*/
public void setImplementation(Object implementation)
throws NotCompliantMBeanException
{
if (implementation == null)
throw new IllegalArgumentException("Null implementation");
this.implementation = implementation;
}
/**
* Retrieve the implementation class
*
* @return the class of the implementation
*/
public Class getImplementationClass()
{
return implementation.getClass();
}
/**
* Retrieve the management interface
*
* @return the management interface
*/
public final Class getMBeanInterface()
{
return mbeanInterface;
}
public Object getAttribute(String attribute)
throws AttributeNotFoundException, MBeanException, ReflectionException
{
try
{
Method method = implementation.getClass().getMethod("get" + attribute, null);
return method.invoke(implementation, new Object[0]);
}
catch (Exception e)
{
JMException result = ExceptionHandler.handleException(e);
if (result instanceof AttributeNotFoundException)
throw (AttributeNotFoundException)result;
if (result instanceof MBeanException)
throw (MBeanException)result;
if (result instanceof ReflectionException)
throw (ReflectionException)result;
throw new MBeanException(e, "Cannot get attribute: " + attribute);
}
}
public void setAttribute(Attribute attribute)
throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException
{
try
{
Class[] clArr = null;
if (attribute.getValue() != null)
{
clArr = new Class[]{attribute.getValue().getClass()};
}
Method method = implementation.getClass().getMethod("set" + attribute.getName(), clArr);
method.invoke(implementation, new Object[]{attribute.getValue()});
}
catch (Exception e)
{
JMException result = ExceptionHandler.handleException(e);
if (result instanceof AttributeNotFoundException)
throw (AttributeNotFoundException)result;
if (result instanceof InvalidAttributeValueException)
throw (InvalidAttributeValueException)result;
if (result instanceof MBeanException)
throw (MBeanException)result;
if (result instanceof ReflectionException)
throw (ReflectionException)result;
throw new MBeanException(e, "Cannot set attribute: " + attribute);
}
}
public AttributeList getAttributes(String[] attributes)
{
try
{
AttributeList attrList = new AttributeList(attributes.length);
for (int i = 0; i < attributes.length; i++)
{
String name = attributes[i];
Object value = getAttribute(name);
attrList.add(new Attribute(name, value));
}
return attrList;
}
catch (Exception e)
{
JMException result = ExceptionHandler.handleException(e);
// Why is this not throwing the same exceptions as getAttribute(String)
throw new RuntimeException("Cannot get attributes", result);
}
}
public AttributeList setAttributes(AttributeList attributes)
{
try
{
AttributeList attrList = new AttributeList(attributes.size());
Iterator it = attributes.iterator();
while (it.hasNext())
{
Attribute attr = (Attribute) it.next();
setAttribute(attr);
String name = attr.getName();
Object value = getAttribute(name);
attrList.add(new Attribute(name, value));
}
return attrList;
}
catch (Exception e)
{
JMException result = ExceptionHandler.handleException(e);
// Why is this not throwing the same exceptions as setAttribute(Attribute)
throw new RuntimeException("Cannot set attributes", result);
}
}
public Object invoke(String actionName, Object[] params, String[] signature)
throws MBeanException, ReflectionException
{
try
{
Class[] sigcl = new Class[signature.length];
for (int i = 0; i < signature.length; i++)
{
sigcl[i] = loadClass(signature[i]);
}
Method method = implementation.getClass().getMethod(actionName, sigcl);
return method.invoke(implementation, params);
}
catch (Exception e)
{
JMException result = ExceptionHandler.handleException(e);
if (result instanceof MBeanException)
throw (MBeanException)result;
if (result instanceof ReflectionException)
throw (ReflectionException)result;
throw new MBeanException(e, "Cannot invoke: " + actionName);
}
}
/**
* Load a class from the classloader that loaded this MBean
*/
private Class loadClass(String className) throws ClassNotFoundException
{
Class clazz = LoaderRepository.getNativeClassForName(className);
if (clazz == null) {
ClassLoader cl = getClass().getClassLoader();
clazz = cl.loadClass(className);
}
return clazz;
}
public MBeanInfo getMBeanInfo()
{
MBeanInfo info = getCachedMBeanInfo();
if (info == null)
{
try
{
info = buildMBeanInfo();
cacheMBeanInfo(info);
}
catch (NotCompliantMBeanException e)
{
log.error("Unexcepted exception", e);
throw new IllegalStateException("Unexcepted exception " + e.toString());
}
}
return info;
}
/**
* Retrieve the cached mbean info
*
* @return the cached mbean info
*/
public MBeanInfo getCachedMBeanInfo()
{
return cachedMBeanInfo;
}
/**
* Sets the cached mbean info
*
* @todo make this work after the mbean is registered
* @param info the mbeaninfo to cache, can be null to erase the cache
*/
public void cacheMBeanInfo(MBeanInfo info)
{
cachedMBeanInfo = info;
}
/**
* Builds a default MBeanInfo for this MBean, using the Management Interface specified for this MBean.
*
* While building the MBeanInfo, this method calls the customization hooks that make it possible for subclasses to
* supply their custom descriptions, parameter names, etc...
*/
public MBeanInfo buildMBeanInfo()
throws NotCompliantMBeanException
{
if (implementation == null)
throw new IllegalArgumentException("Null implementation");
StandardMetaData metaData = new StandardMetaData(implementation, mbeanInterface);
this.mbeanInterface = metaData.getMBeanInterface();
return metaData.build();
}
// Inner Classes -----------------------------------------------
}