org.eclipse.jetty.jmx.ObjectMBean Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of testatoo-container-jetty-full Show documentation
Show all versions of testatoo-container-jetty-full Show documentation
Testatoo Jetty Container with JSP support
// ========================================================================
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.jmx;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.modelmbean.ModelMBean;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
/* ------------------------------------------------------------ */
/** ObjectMBean.
* A dynamic MBean that can wrap an arbitary Object instance.
* the attributes and methods exposed by this bean are controlled by
* the merge of property bundles discovered by names related to all
* superclasses and all superinterfaces.
*
* Attributes and methods exported may be "Object" and must exist on the
* wrapped object, or "MBean" and must exist on a subclass of OBjectMBean
* or "MObject" which exists on the wrapped object, but whose values are
* converted to MBean object names.
*
*/
public class ObjectMBean implements DynamicMBean
{
private static Class[] OBJ_ARG = new Class[]{Object.class};
protected Object _managed;
private MBeanInfo _info;
private Map _getters=new HashMap();
private Map _setters=new HashMap();
private Map _methods=new HashMap();
private Set _convert=new HashSet();
private ClassLoader _loader;
private MBeanContainer _mbeanContainer;
private static String OBJECT_NAME_CLASS = ObjectName.class.getName();
private static String OBJECT_NAME_ARRAY_CLASS = ObjectName[].class.getName();
/* ------------------------------------------------------------ */
/**
* Create MBean for Object. Attempts to create an MBean for the object by searching the package
* and class name space. For example an object of the type
*
*
* class com.acme.MyClass extends com.acme.util.BaseClass implements com.acme.Iface
*
*
* Then this method would look for the following classes:
*
* - com.acme.jmx.MyClassMBean
*
- com.acme.util.jmx.BaseClassMBean
*
- org.eclipse.jetty.jmx.ObjectMBean
*
*
* @param o The object
* @return A new instance of an MBean for the object or null.
*/
public static Object mbeanFor(Object o)
{
try
{
Class oClass = o.getClass();
Object mbean = null;
while (mbean == null && oClass != null)
{
String pName = oClass.getPackage().getName();
String cName = oClass.getName().substring(pName.length() + 1);
String mName = pName + ".jmx." + cName + "MBean";
try
{
Class mClass = (Object.class.equals(oClass))?oClass=ObjectMBean.class:Loader.loadClass(oClass,mName,true);
if (Log.isDebugEnabled())
Log.debug("mbeanFor " + o + " mClass=" + mClass);
try
{
Constructor constructor = mClass.getConstructor(OBJ_ARG);
mbean=constructor.newInstance(new Object[]{o});
}
catch(Exception e)
{
Log.ignore(e);
if (ModelMBean.class.isAssignableFrom(mClass))
{
mbean=mClass.newInstance();
((ModelMBean)mbean).setManagedResource(o, "objectReference");
}
}
if (Log.isDebugEnabled())
Log.debug("mbeanFor " + o + " is " + mbean);
return mbean;
}
catch (ClassNotFoundException e)
{
if (e.toString().endsWith("MBean"))
Log.ignore(e);
else
Log.warn(e);
}
catch (Error e)
{
Log.warn(e);
mbean = null;
}
catch (Exception e)
{
Log.warn(e);
mbean = null;
}
oClass = oClass.getSuperclass();
}
}
catch (Exception e)
{
Log.ignore(e);
}
return null;
}
public ObjectMBean(Object managedObject)
{
_managed = managedObject;
_loader = Thread.currentThread().getContextClassLoader();
}
public Object getManagedObject()
{
return _managed;
}
public ObjectName getObjectName()
{
return null;
}
public String getObjectNameBasis()
{
return null;
}
protected void setMBeanContainer(MBeanContainer container)
{
this._mbeanContainer = container;
}
public MBeanContainer getMBeanContainer ()
{
return this._mbeanContainer;
}
public MBeanInfo getMBeanInfo()
{
try
{
if (_info==null)
{
// Start with blank lazy lists attributes etc.
String desc=null;
Object attributes=null;
Object constructors=null;
Object operations=null;
Object notifications=null;
// Find list of classes that can influence the mbean
Class o_class=_managed.getClass();
Object influences = findInfluences(null, _managed.getClass());
// Set to record defined items
Set defined=new HashSet();
// For each influence
for (int i=0;i0)
{
// define an operation
if (!defined.contains(key) && key.indexOf('[')<0)
{
defined.add(key);
operations=LazyList.add(operations,defineOperation(key, value, bundle));
}
}
else
{
// define an attribute
if (!defined.contains(key))
{
defined.add(key);
MBeanAttributeInfo info=defineAttribute(key, value);
if (info!=null)
attributes=LazyList.add(attributes,info);
}
}
}
}
catch(MissingResourceException e)
{
Log.ignore(e);
}
}
_info = new MBeanInfo(o_class.getName(),
desc,
(MBeanAttributeInfo[])LazyList.toArray(attributes, MBeanAttributeInfo.class),
(MBeanConstructorInfo[])LazyList.toArray(constructors, MBeanConstructorInfo.class),
(MBeanOperationInfo[])LazyList.toArray(operations, MBeanOperationInfo.class),
(MBeanNotificationInfo[])LazyList.toArray(notifications, MBeanNotificationInfo.class));
}
}
catch(RuntimeException e)
{
Log.warn(e);
throw e;
}
return _info;
}
/* ------------------------------------------------------------ */
public Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException
{
Method getter = (Method) _getters.get(name);
if (getter == null)
throw new AttributeNotFoundException(name);
try
{
Object o = _managed;
if (getter.getDeclaringClass().isInstance(this))
o = this; // mbean method
// get the attribute
Object r=getter.invoke(o, (java.lang.Object[]) null);
// convert to ObjectName if need be.
if (r!=null && _convert.contains(name))
{
if (r.getClass().isArray())
{
ObjectName[] on = new ObjectName[Array.getLength(r)];
for (int i=0;i0;)
Array.set(na, i, _mbeanContainer.findBean((ObjectName)Array.get(value, i)));
value=na;
}
else
value=_mbeanContainer.findBean((ObjectName)value);
}
// do the setting
setter.invoke(o, new Object[]{ value });
}
catch (IllegalAccessException e)
{
Log.warn(Log.EXCEPTION, e);
throw new AttributeNotFoundException(e.toString());
}
catch (InvocationTargetException e)
{
Log.warn(Log.EXCEPTION, e);
throw new ReflectionException(new Exception(e.getCause()));
}
}
/* ------------------------------------------------------------ */
public AttributeList setAttributes(AttributeList attrs)
{
Log.debug("setAttributes");
AttributeList results = new AttributeList(attrs.size());
Iterator iter = attrs.iterator();
while (iter.hasNext())
{
try
{
Attribute attr = (Attribute) iter.next();
setAttribute(attr);
results.add(new Attribute(attr.getName(), getAttribute(attr.getName())));
}
catch (Exception e)
{
Log.warn(Log.EXCEPTION, e);
}
}
return results;
}
/* ------------------------------------------------------------ */
public Object invoke(String name, Object[] params, String[] signature) throws MBeanException, ReflectionException
{
if (Log.isDebugEnabled())
Log.debug("invoke " + name);
String methodKey = name + "(";
if (signature != null)
for (int i = 0; i < signature.length; i++)
methodKey += (i > 0 ? "," : "") + signature[i];
methodKey += ")";
ClassLoader old_loader=Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(_loader);
Method method = (Method) _methods.get(methodKey);
if (method == null)
throw new NoSuchMethodException(methodKey);
Object o = _managed;
if (method.getDeclaringClass().isInstance(this))
o = this;
return method.invoke(o, params);
}
catch (NoSuchMethodException e)
{
Log.warn(Log.EXCEPTION, e);
throw new ReflectionException(e);
}
catch (IllegalAccessException e)
{
Log.warn(Log.EXCEPTION, e);
throw new MBeanException(e);
}
catch (InvocationTargetException e)
{
Log.warn(Log.EXCEPTION, e);
throw new ReflectionException(new Exception(e.getCause()));
}
finally
{
Thread.currentThread().setContextClassLoader(old_loader);
}
}
private static Object findInfluences(Object influences, Class aClass)
{
if (aClass!=null)
{
// This class is an influence
influences=LazyList.add(influences,aClass);
// So are the super classes
influences=findInfluences(influences,aClass.getSuperclass());
// So are the interfaces
Class[] ifs = aClass.getInterfaces();
for (int i=0;ifs!=null && i
* "Object" The field/method is on the managed object.
* "MBean" The field/method is on the mbean proxy object
* "MObject" The field/method is on the managed object and value should be converted to MBean reference
* "MMBean" The field/method is on the mbean proxy object and value should be converted to MBean reference
*
* the access is either "RW" or "RO".
*/
public MBeanAttributeInfo defineAttribute(String name, String metaData)
{
String description = "";
boolean writable = true;
boolean onMBean = false;
boolean convert = false;
if (metaData!= null)
{
String[] tokens = metaData.split(":", 3);
for (int t=0;t0?",":"(")+args[i];
}
signature+=(i>0?")":"()");
// Build param infos
for (i = 0; i < args.length; i++)
{
String param_desc = bundle.getString(signature + "[" + i + "]");
parts=param_desc.split(" *: *",2);
if (Log.isDebugEnabled())
Log.debug(parts[0]+": "+parts[1]);
pInfo[i] = new MBeanParameterInfo(parts[0].trim(), args[i], parts[1].trim());
}
// build the operation info
Method method = oClass.getMethod(method_name, types);
Class returnClass = method.getReturnType();
_methods.put(signature, method);
if (convert)
_convert.add(signature);
return new MBeanOperationInfo(method_name, description, pInfo, returnClass.isPrimitive() ? TypeUtil.toName(returnClass) : (returnClass.getName()), impact);
}
catch (Exception e)
{
Log.warn("Operation '"+signature+"'", e);
throw new IllegalArgumentException(e.toString());
}
}
}