diff options
author | dims <dims@13f79535-47bb-0310-9956-ffa450edef68> | 2008-06-17 00:23:01 +0000 |
---|---|---|
committer | dims <dims@13f79535-47bb-0310-9956-ffa450edef68> | 2008-06-17 00:23:01 +0000 |
commit | bdd0a41aed7edf21ec2a65cfa17a86af2ef8c48a (patch) | |
tree | 38a92061c0793434c4be189f1d70c3458b6bc41d /sandbox/old/contrib/jmx/src/main/java/org/apache/tuscany/service/management/jmx/instrument/ReflectedDynamicMBean.java |
Move Tuscany from Incubator to top level.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@668359 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sandbox/old/contrib/jmx/src/main/java/org/apache/tuscany/service/management/jmx/instrument/ReflectedDynamicMBean.java')
-rw-r--r-- | sandbox/old/contrib/jmx/src/main/java/org/apache/tuscany/service/management/jmx/instrument/ReflectedDynamicMBean.java | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/sandbox/old/contrib/jmx/src/main/java/org/apache/tuscany/service/management/jmx/instrument/ReflectedDynamicMBean.java b/sandbox/old/contrib/jmx/src/main/java/org/apache/tuscany/service/management/jmx/instrument/ReflectedDynamicMBean.java new file mode 100644 index 0000000000..b07787208c --- /dev/null +++ b/sandbox/old/contrib/jmx/src/main/java/org/apache/tuscany/service/management/jmx/instrument/ReflectedDynamicMBean.java @@ -0,0 +1,353 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.service.management.jmx.instrument; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.MethodDescriptor; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +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.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.ReflectionException; + +/** + * Uses JMX dynamic MBean to expose management information of a delegate instance using reflection. Currently + * constructor and notification metadata are not supported. Any attribute or operation that needs to be excluded from + * the management information can be specified optionally in the factory method. + * <p/> + * All the methods and properties on <code>java.lang.Object</code> are excluded by default. Also only public and + * non-static members are made available for management. + * <p/> + * TODO Find a homw other than server.start for this class. TODO Tidy up, unit tests + * + * @version $Revsion$ $Date$ + */ +public class ReflectedDynamicMBean implements DynamicMBean { + + /** + * Excluded methods. + */ + private static final List<String> DEFAULT_EXCLUDED_METHODS = + Arrays.asList(new String[]{"wait", "toString", "hashCode", "notify", "equals", "notifyAll", "getClass"}); + + /** + * Excluded properties. + */ + private static final List<String> DEFAULT_EXCLUDED_PROPERTIES = Arrays.asList(new String[]{"class"}); + + /** + * Proxied object that is managed. + */ + private Object delegate; + + /** + * Runtime type of the managed object. + */ + private Class delegateClass; + + /** + * Delegate class name. + */ + private String delegateClassName; + + /** + * Cache of property write methods. + */ + private Map<String, Method> propertyWriteMethods = new HashMap<String, Method>(); + + /** + * Cache of property read methods. + */ + private Map<String, Method> propertyReadMethods = new HashMap<String, Method>(); + + /** + * Managed operation cache. + */ + private Map<String, Method> methods = new HashMap<String, Method>(); + + /** + * Property descriptor cache. + */ + private Map<String, PropertyDescriptor> properties = new HashMap<String, PropertyDescriptor>(); + + /** + * Excluded methods. + */ + private final List<String> excludedMethods = new ArrayList<String>(); + + /** + * Excluded properties. + */ + private final List<String> excludedProperties = new ArrayList<String>(); + + /** + * Introspects the bean and populate meta information. + * + * @param delegate Proxied managed instance. + */ + private ReflectedDynamicMBean(Object delegate) { + this(delegate, new ArrayList<String>(), new ArrayList<String>()); + } + + /** + * Introspects the bean and populate meta information. + * + * @param delegate Proxied managed instance. + * @param excludedMethods Operations excluded from managed view. + * @param excludedProperties Properties excluded from managed view. + */ + private ReflectedDynamicMBean(Object delegate, List<String> excludedMethods, List<String> excludedProperties) { + + this.delegate = delegate; + this.delegateClass = delegate.getClass(); + this.delegateClassName = delegateClass.getName(); + + this.excludedMethods.addAll(excludedMethods); + this.excludedMethods.addAll(DEFAULT_EXCLUDED_METHODS); + this.excludedProperties.addAll(excludedProperties); + this.excludedProperties.addAll(DEFAULT_EXCLUDED_PROPERTIES); + + BeanInfo beanInfo; + try { + beanInfo = Introspector.getBeanInfo(delegateClass); + } catch (IntrospectionException ex) { + throw new InstrumentationException(ex); + } + + cacheProperties(beanInfo); + + cacheMethods(beanInfo); + } + + /** + * Factory method for creating the management view. + * + * @param delegate Proxied managed instance. + * @param excludedMethods Operations excluded from managed view. + * @param excludedProperties Properties excluded from managed view. + * @return Proxy for the managed instance. + */ + public static ReflectedDynamicMBean newInstance(Object delegate, List<String> excludedMethods, + List<String> excludedProperties) { + return new ReflectedDynamicMBean(delegate, excludedMethods, excludedProperties); + } + + /** + * Factory method for creating the management view. + * + * @param delegate Proxied managed instance. + * @return Proxy for the managed instance. + */ + public static ReflectedDynamicMBean newInstance(Object delegate) { + return new ReflectedDynamicMBean(delegate); + } + + /** + * @see javax.management.DynamicMBean#getAttribute(java.lang.String) + */ + public Object getAttribute(String attribute) + throws AttributeNotFoundException, MBeanException, ReflectionException { + + Method readMethod = propertyReadMethods.get(attribute); + if (readMethod == null) { + throw new AttributeNotFoundException(attribute + " not found"); + } + try { + return readMethod.invoke(delegate); + } catch (IllegalAccessException ex) { + throw new ReflectionException(ex); + } catch (InvocationTargetException ex) { + throw new ReflectionException(ex); + } + + } + + /** + * @see javax.management.DynamicMBean#getAttributes(java.lang.String[]) + */ + public AttributeList getAttributes(String[] attributes) { + + AttributeList list = new AttributeList(); + for (String attribute : attributes) { + try { + list.add(new Attribute(attribute, getAttribute(attribute))); + } catch (AttributeNotFoundException ex) { + throw new InstrumentationException(ex); + } catch (MBeanException ex) { + throw new InstrumentationException(ex); + } catch (ReflectionException ex) { + throw new InstrumentationException(ex); + } + } + return list; + + } + + /** + * @see javax.management.DynamicMBean#getMBeanInfo() + */ + public MBeanInfo getMBeanInfo() { + + try { + + MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[properties.keySet().size()]; + int count = 0; + for (String property : properties.keySet()) { + Method readMethod = propertyReadMethods.get(property); + Method writeMethod = propertyWriteMethods.get(property); + attrs[count++] = new MBeanAttributeInfo(property, "", readMethod, writeMethod); + } + + MBeanOperationInfo[] ops = new MBeanOperationInfo[methods.keySet().size()]; + count = 0; + for (Method method : methods.values()) { + ops[count++] = new MBeanOperationInfo("", method); + } + + MBeanInfo mBeanInfo = new MBeanInfo(delegateClassName, "", attrs, null, ops, null); + return mBeanInfo; + + } catch (javax.management.IntrospectionException ex) { + throw new InstrumentationException(ex); + } + + } + + /** + * @see javax.management.DynamicMBean#invoke(java.lang.String,java.lang.Object[],java.lang.String[]) + */ + public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, + ReflectionException { + + Method method = methods.get(actionName); + if (method == null) { + throw new InstrumentationException("Operation not found: " + actionName); + } + try { + return method.invoke(delegate, params); + } catch (IllegalAccessException ex) { + throw new ReflectionException(ex); + } catch (InvocationTargetException ex) { + throw new ReflectionException(ex); + } + + } + + /** + * @see javax.management.DynamicMBean#setAttribute(javax.management.Attribute) + */ + public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, + MBeanException, ReflectionException { + + Method writeMethod = propertyWriteMethods.get(attribute.getName()); + if (writeMethod == null) { + throw new AttributeNotFoundException(attribute + " not found"); + } + try { + writeMethod.invoke(delegate, attribute.getValue()); + } catch (IllegalAccessException ex) { + throw new ReflectionException(ex); + } catch (InvocationTargetException ex) { + throw new ReflectionException(ex); + } + + } + + /** + * @see javax.management.DynamicMBean#setAttributes(javax.management.AttributeList) + */ + public AttributeList setAttributes(AttributeList attributes) { + throw new UnsupportedOperationException(); + } + + /** + * Caches managed operations. + * + * @param beanInfo Bean info for the managed instance. + */ + private void cacheMethods(BeanInfo beanInfo) { + + for (MethodDescriptor methodDescriptor : beanInfo.getMethodDescriptors()) { + + Method method = methodDescriptor.getMethod(); + String name = method.getName(); + + if (excludedMethods.contains(name)) { + continue; + } + int modifiers = method.getModifiers(); + if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)) { + continue; + } + if (propertyReadMethods.values().contains(method) || propertyWriteMethods.values().contains(method)) { + continue; + } + + // TODO Add support for overloaded methods + methods.put(name, method); + + } + + } + + /** + * Caches managed properties. + * + * @param beanInfo Bean info for the managed instance. + */ + private void cacheProperties(BeanInfo beanInfo) { + for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) { + + String name = propertyDescriptor.getName(); + + if (excludedProperties.contains(name)) { + continue; + } + properties.put(name, propertyDescriptor); + + Method readMethod = propertyDescriptor.getReadMethod(); + if (readMethod != null && Modifier.isPublic(readMethod.getModifiers())) { + propertyReadMethods.put(name, readMethod); + } + + Method writeMethod = propertyDescriptor.getWriteMethod(); + if (writeMethod != null && Modifier.isPublic(writeMethod.getModifiers())) { + propertyWriteMethods.put(name, writeMethod); + } + + } + } + +} |