All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.granite.jmx.OpenMBean Maven / Gradle / Ivy

There is a newer version: 3.0.0.M3
Show newest version
/*
  GRANITE DATA SERVICES
  Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.

  This file is part of Granite Data Services.

  Granite Data Services is free software; you can redistribute it and/or modify
  it under the terms of the GNU Library General Public License as published by
  the Free Software Foundation; either version 2 of the License, or (at your
  option) any later version.

  Granite Data Services 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 Library General Public License
  for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; if not, see .
*/

package org.granite.jmx;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
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.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenMBeanAttributeInfo;
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
import javax.management.openmbean.OpenMBeanConstructorInfo;
import javax.management.openmbean.OpenMBeanInfoSupport;
import javax.management.openmbean.OpenMBeanOperationInfo;
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
import javax.management.openmbean.OpenMBeanParameterInfo;
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;

/**
 * The OpenMBean class wraps an instance of any bean and introspects its properties and methods
 * for MBeanAttributes and MBeanOperations. It implements all functionalities required by a
 * {@link DynamicMBean} and returns an OpenMBeanInfo object.
 * 
*
* Limitations: *
    *
  • only attributes and operations are supported (no contructor and no notification),
  • *
  • only {@link SimpleType} and {@link ArrayType} are supported (no composite type).
  • *
* * @author Franck WOLFF */ @SuppressWarnings({ "unchecked", "rawtypes" }) public class OpenMBean implements DynamicMBean { /////////////////////////////////////////////////////////////////////////// // Fields. private static final Map, SimpleType> SIMPLE_TYPES = new HashMap, SimpleType>(); static { SIMPLE_TYPES.put(Void.class, SimpleType.VOID); SIMPLE_TYPES.put(Void.TYPE, SimpleType.VOID); SIMPLE_TYPES.put(Boolean.class, SimpleType.BOOLEAN); SIMPLE_TYPES.put(Boolean.TYPE, SimpleType.BOOLEAN); SIMPLE_TYPES.put(Character.class, SimpleType.CHARACTER); SIMPLE_TYPES.put(Character.TYPE, SimpleType.CHARACTER); SIMPLE_TYPES.put(Byte.class, SimpleType.BYTE); SIMPLE_TYPES.put(Byte.TYPE, SimpleType.BYTE); SIMPLE_TYPES.put(Short.class, SimpleType.SHORT); SIMPLE_TYPES.put(Short.TYPE, SimpleType.SHORT); SIMPLE_TYPES.put(Integer.class, SimpleType.INTEGER); SIMPLE_TYPES.put(Integer.TYPE, SimpleType.INTEGER); SIMPLE_TYPES.put(Long.class, SimpleType.LONG); SIMPLE_TYPES.put(Long.TYPE, SimpleType.LONG); SIMPLE_TYPES.put(Float.class, SimpleType.FLOAT); SIMPLE_TYPES.put(Float.TYPE, SimpleType.FLOAT); SIMPLE_TYPES.put(Double.class, SimpleType.DOUBLE); SIMPLE_TYPES.put(Double.TYPE, SimpleType.DOUBLE); SIMPLE_TYPES.put(String.class, SimpleType.STRING); SIMPLE_TYPES.put(BigDecimal.class, SimpleType.BIGDECIMAL); SIMPLE_TYPES.put(BigInteger.class, SimpleType.BIGINTEGER); SIMPLE_TYPES.put(Date.class, SimpleType.DATE); SIMPLE_TYPES.put(ObjectName.class, SimpleType.OBJECTNAME); } private final MBeanInfo info; private final Object instance; private final Map attributesMap = new HashMap(); private final Map operationsMap = new HashMap(); /////////////////////////////////////////////////////////////////////////// // Constructors. /** * Creates a new OpenMBean instance and instrospects its child class for attributes * and operations. */ protected OpenMBean() { this.info = init(getClass(), OpenMBean.class, attributesMap, operationsMap); this.instance = this; } private OpenMBean(Class beanClass, Class stopClass, Object instance) { this.info = init(beanClass, stopClass, attributesMap, operationsMap); this.instance = instance; } /////////////////////////////////////////////////////////////////////////// // Static OpenMBean creators. /** * Creates a new OpenMBean by introspecting and wrapping the instance parameter. * This method search for an interface named instance.getClass().getSimpleName() + "MBean" * and, if it finds it, uses it for introspection. Otherwise, the class of the instance * object is used instead. * * @param instance an instance of a bean to introspect. * @return a new OpenMBean instance that wraps the instance bean. */ public static OpenMBean createMBean(Object instance) { Class beanClass = null; Class instanceClass = instance.getClass(); while (instanceClass != null) { String interMBeanName = instanceClass.getSimpleName() + "MBean"; for (Class inter : instanceClass.getInterfaces()) { if (interMBeanName.equals(inter.getSimpleName())) { beanClass = inter; break; } } if (beanClass != null) break; instanceClass = instanceClass.getSuperclass(); } if (beanClass == null) beanClass = instance.getClass(); Class stopClass = null; if (!beanClass.isInterface()) { stopClass = beanClass.getSuperclass(); if (stopClass == null) stopClass = Object.class; } return new OpenMBean(beanClass, stopClass, instance); } /** * Creates a new OpenMBean by introspecting the beanClass parameter and wrapping * the instance parameter. * * @param beanClass a class (or interface) used for introspection. * @param instance the bean to encapsulate. * @return a new OpenMBean instance that wraps the instance bean. * @throws IllegalArgumentException if instance is not an instance of beanClass. */ public static OpenMBean createMBean(Class beanClass, Object instance) { if (!beanClass.isAssignableFrom(instance.getClass())) throw new IllegalArgumentException("Instance " + instance + " should be an instance of " + beanClass); Class stopClass = null; if (!beanClass.isInterface()) { stopClass = beanClass.getSuperclass(); if (stopClass == null) stopClass = Object.class; } return new OpenMBean(beanClass, stopClass, instance); } /////////////////////////////////////////////////////////////////////////// // Static initialization methods. private static MBeanInfo init( Class beanClass, Class stopClass, Map attributesMap, Map operationsMap) { MBean mb = beanClass.getAnnotation(MBean.class); String description = null; if (mb != null) description = mb.description(); if (description == null) description = beanClass.getSimpleName() + " MBean"; List attributes = new ArrayList(); List operations = new ArrayList(); try { BeanInfo beanInfo = ( stopClass == null ? Introspector.getBeanInfo(beanClass) : Introspector.getBeanInfo(beanClass, stopClass) ); Set attributeMethods = new HashSet(); // Attributes. for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) { MBeanAttribute mba = null; if (property.getReadMethod() != null) mba = property.getReadMethod().getAnnotation(MBeanAttribute.class); if (mba == null && property.getWriteMethod() != null) mba = property.getWriteMethod().getAnnotation(MBeanAttribute.class); if (mba == null) continue; String name = property.getName(); String desc = mba.description(); if (desc == null) desc = name.substring(0, 1).toUpperCase() + name.substring(1) + " Attribute"; OpenType type = getOpenType(property.getPropertyType()); attributes.add(new OpenMBeanAttributeInfoSupport( name, desc, type, property.getReadMethod() != null, property.getWriteMethod() != null, property.getReadMethod() != null && property.getReadMethod().getName().startsWith("is") )); attributesMap.put(property.getName(), property); if (property.getReadMethod() != null) attributeMethods.add(property.getReadMethod()); if (property.getWriteMethod() != null) attributeMethods.add(property.getWriteMethod()); } // Operations for (MethodDescriptor method : beanInfo.getMethodDescriptors()) { if (attributeMethods.contains(method.getMethod())) continue; MBeanOperation mbo = method.getMethod().getAnnotation(MBeanOperation.class); if (mbo == null) continue; String name = method.getName(); String desc = mbo.description(); if (desc == null) desc = name.substring(0, 1).toUpperCase() + name.substring(1) + " Operation"; List parameters = new ArrayList(); Annotation[][] annotations = method.getMethod().getParameterAnnotations(); int i = 0; for (Class parameter : method.getMethod().getParameterTypes()) { String paramName = getParameterName(annotations, i); String paramDesc = getParameterDescription(annotations, i); OpenType paramType = getOpenType(parameter); parameters.add(new OpenMBeanParameterInfoSupport(paramName, paramDesc, paramType)); i++; } OpenType returnedType = getOpenType(method.getMethod().getReturnType()); int impact = MBeanOperationInfo.UNKNOWN; if (mbo.impact() != null) { switch (mbo.impact()) { case ACTION: impact = MBeanOperationInfo.ACTION; break; case ACTION_INFO: impact = MBeanOperationInfo.ACTION_INFO; break; case INFO: impact = MBeanOperationInfo.INFO; break; } } operations.add(new OpenMBeanOperationInfoSupport( name, desc, parameters.toArray(new OpenMBeanParameterInfo[parameters.size()]), returnedType, impact )); String[] paramClasses = new String[parameters.size()]; for (i = 0; i < parameters.size(); i++) paramClasses[i] = parameters.get(i).getOpenType().getTypeName().toString(); String qName = name + Arrays.toString(paramClasses); operationsMap.put(qName, method); } } catch (Exception e) { throw new RuntimeException("Could not introspect MBean class: " + beanClass, e); } return new OpenMBeanInfoSupport( beanClass.getName(), description, attributes.toArray(new OpenMBeanAttributeInfo[attributes.size()]), new OpenMBeanConstructorInfo[0], operations.toArray(new OpenMBeanOperationInfo[operations.size()]), new MBeanNotificationInfo[0] ); } private static String getParameterName(Annotation[][] paramAnnotations, int index) { String name = null; if (paramAnnotations != null && paramAnnotations.length > index) { for (Annotation annot : paramAnnotations[index]) { if (MBeanParameter.class.equals(annot.annotationType())) { name = ((MBeanParameter)annot).name(); break; } } } return (name != null ? name : "arg" + (index + 1)); } private static String getParameterDescription(Annotation[][] paramAnnotations, int index) { String description = null; if (paramAnnotations != null && paramAnnotations.length > index) { for (Annotation annot : paramAnnotations[index]) { if (MBeanParameter.class.equals(annot.annotationType())) { description = ((MBeanParameter)annot).description(); break; } } } return (description != null ? description : "Operation Parameter " + (index + 1)); } private static OpenType getOpenType(Class clazz) throws OpenDataException { if (SIMPLE_TYPES.containsKey(clazz)) return SIMPLE_TYPES.get(clazz); if (clazz.isArray()) { int dimension = 1; Class componentType = clazz.getComponentType(); while (componentType.isArray()) { dimension++; componentType = componentType.getComponentType(); } return new ArrayType(dimension, getOpenType(componentType)); } throw new OpenDataException("Unsupported type: " + clazz); } /////////////////////////////////////////////////////////////////////////// // DynamicMBean implementation. /** * {@inheritDoc} */ public synchronized Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { PropertyDescriptor property = attributesMap.get(attribute); if (property != null && property.getReadMethod() != null) { try { return property.getReadMethod().invoke(instance); } catch (Exception e) { throw new ReflectionException(e, "Could not get attribute value: " + attribute); } } throw new AttributeNotFoundException("Attribute " + attribute + " not found"); } /** * {@inheritDoc} */ public synchronized AttributeList getAttributes(String[] names) { AttributeList attributes = new AttributeList(); for (String name : names) { try { attributes.add(new Attribute(name, getAttribute(name))); } catch (Exception e) { // ignore... } } return attributes; } /** * {@inheritDoc} */ public synchronized MBeanInfo getMBeanInfo() { return info; } /** * {@inheritDoc} */ public synchronized Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { if (signature == null) signature = new String[0]; String qName = actionName + Arrays.toString(signature); MethodDescriptor method = operationsMap.get(qName); if (method == null) throw new RuntimeException("Method not found: " + qName); try { return method.getMethod().invoke(instance, params); } catch (Exception e) { throw new ReflectionException(e, "Could not invoke operation: " + qName); } } /** * {@inheritDoc} */ public synchronized void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { PropertyDescriptor property = attributesMap.get(attribute.getName()); if (property != null && property.getWriteMethod() != null) { try { property.getWriteMethod().invoke(instance, attribute.getValue()); } catch (Exception e) { throw new ReflectionException(e, "Could not set attribute value: " + attribute.getName() + "=" + attribute.getValue()); } } else throw new AttributeNotFoundException("Attribute " + attribute.getName() + " not found"); } /** * {@inheritDoc} */ public synchronized AttributeList setAttributes(AttributeList attributes) { AttributeList returnedAttributes = new AttributeList(); for (Object a : attributes) { Attribute attribute = (Attribute)a; try { setAttribute(attribute); returnedAttributes.add(new Attribute(attribute.getName(), getAttribute(attribute.getName()))); } catch (Exception e) { // Ignore... } } return returnedAttributes; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy