365 lines · 14.3 KB · Java
RawDownload
/* * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jmx.mbeanserver; import com.sun.jmx.mbeanserver.MBeanIntrospector.MBeanInfoMap;import com.sun.jmx.mbeanserver.MBeanIntrospector.PerInterfaceMap;import java.lang.annotation.Annotation;import java.lang.reflect.GenericArrayType;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import javax.management.Descriptor;import javax.management.ImmutableDescriptor;import javax.management.MBeanAttributeInfo;import javax.management.MBeanException;import javax.management.MBeanOperationInfo;import javax.management.MBeanParameterInfo;import javax.management.NotCompliantMBeanException;import javax.management.openmbean.OpenMBeanAttributeInfoSupport;import javax.management.openmbean.OpenMBeanOperationInfoSupport;import javax.management.openmbean.OpenMBeanParameterInfo;import javax.management.openmbean.OpenMBeanParameterInfoSupport;import javax.management.openmbean.OpenType; /** * Introspector for MXBeans.  There is exactly one instance of this class. * * @since 1.6 */class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {    private static final MXBeanIntrospector instance = new MXBeanIntrospector();     static MXBeanIntrospector getInstance() {        return instance;    }     @Override    PerInterfaceMap<ConvertingMethod> getPerInterfaceMap() {        return perInterfaceMap;    }     @Override    MBeanInfoMap getMBeanInfoMap() {        return mbeanInfoMap;    }     @Override    MBeanAnalyzer<ConvertingMethod> getAnalyzer(Class<?> mbeanInterface)            throws NotCompliantMBeanException {        return MBeanAnalyzer.analyzer(mbeanInterface, this);    }     @Override    boolean isMXBean() {        return true;    }     @Override    ConvertingMethod mFrom(Method m) {        return ConvertingMethod.from(m);    }     @Override    String getName(ConvertingMethod m) {        return m.getName();    }     @Override    Type getGenericReturnType(ConvertingMethod m) {        return m.getGenericReturnType();    }     @Override    Type[] getGenericParameterTypes(ConvertingMethod m) {        return m.getGenericParameterTypes();    }     @Override    String[] getSignature(ConvertingMethod m) {        return m.getOpenSignature();    }     @Override    void checkMethod(ConvertingMethod m) {        m.checkCallFromOpen();    }     @Override    Object invokeM2(ConvertingMethod m, Object target, Object[] args,                    Object cookie)            throws InvocationTargetException, IllegalAccessException,                   MBeanException {        return m.invokeWithOpenReturn((MXBeanLookup) cookie, target, args);    }     @Override    boolean validParameter(ConvertingMethod m, Object value, int paramNo,                           Object cookie) {        if (value == null) {            // Null is a valid value for all OpenTypes, even though            // OpenType.isValue(null) will return false.  It can always be            // matched to the corresponding Java type, except when that            // type is primitive.            Type t = m.getGenericParameterTypes()[paramNo];            return (!(t instanceof Class<?>) || !((Class<?>) t).isPrimitive());        } else {            Object v;            try {                v = m.fromOpenParameter((MXBeanLookup) cookie, value, paramNo);            } catch (Exception e) {                // Ignore the exception and let MBeanIntrospector.invokeSetter()                // throw the initial exception.                return true;            }            return isValidParameter(m.getMethod(), v, paramNo);        }    }     @Override    MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,            ConvertingMethod getter, ConvertingMethod setter) {         final boolean isReadable = (getter != null);        final boolean isWritable = (setter != null);        final boolean isIs = isReadable && getName(getter).startsWith("is");         final String description = attributeName;         final OpenType<?> openType;        final Type originalType;        if (isReadable) {            openType = getter.getOpenReturnType();            originalType = getter.getGenericReturnType();        } else {            openType = setter.getOpenParameterTypes()[0];            originalType = setter.getGenericParameterTypes()[0];        }        Descriptor descriptor = typeDescriptor(openType, originalType);        if (isReadable) {            descriptor = ImmutableDescriptor.union(descriptor,                    getter.getDescriptor());        }        if (isWritable) {            descriptor = ImmutableDescriptor.union(descriptor,                    setter.getDescriptor());        }         final MBeanAttributeInfo ai;        if (canUseOpenInfo(originalType)) {            ai = new OpenMBeanAttributeInfoSupport(attributeName,                                                   description,                                                   openType,                                                   isReadable,                                                   isWritable,                                                   isIs,                                                   descriptor);        } else {            ai = new MBeanAttributeInfo(attributeName,                                        originalTypeString(originalType),                                        description,                                        isReadable,                                        isWritable,                                        isIs,                                        descriptor);        }        // could also consult annotations for defaultValue,        // minValue, maxValue, legalValues         return ai;    }     @Override    MBeanOperationInfo getMBeanOperationInfo(String operationName,            ConvertingMethod operation) {        final Method method = operation.getMethod();        final String description = operationName;        /* Ideally this would be an empty string, but           OMBOperationInfo constructor forbids that.  Also, we           could consult an annotation to get a useful           description.  */         final int impact = MBeanOperationInfo.UNKNOWN;         final OpenType<?> returnType = operation.getOpenReturnType();        final Type originalReturnType = operation.getGenericReturnType();        final OpenType<?>[] paramTypes = operation.getOpenParameterTypes();        final Type[] originalParamTypes = operation.getGenericParameterTypes();        final MBeanParameterInfo[] params =            new MBeanParameterInfo[paramTypes.length];        boolean openReturnType = canUseOpenInfo(originalReturnType);        boolean openParameterTypes = true;        Annotation[][] annots = method.getParameterAnnotations();        for (int i = 0; i < paramTypes.length; i++) {            final String paramName = "p" + i;            final String paramDescription = paramName;            final OpenType<?> openType = paramTypes[i];            final Type originalType = originalParamTypes[i];            Descriptor descriptor =                typeDescriptor(openType, originalType);            descriptor = ImmutableDescriptor.union(descriptor,                    Introspector.descriptorForAnnotations(annots[i]));            final MBeanParameterInfo pi;            if (canUseOpenInfo(originalType)) {                pi = new OpenMBeanParameterInfoSupport(paramName,                                                       paramDescription,                                                       openType,                                                       descriptor);            } else {                openParameterTypes = false;                pi = new MBeanParameterInfo(                    paramName,                    originalTypeString(originalType),                    paramDescription,                    descriptor);            }            params[i] = pi;        }         Descriptor descriptor =            typeDescriptor(returnType, originalReturnType);        descriptor = ImmutableDescriptor.union(descriptor,                Introspector.descriptorForElement(method));        final MBeanOperationInfo oi;        if (openReturnType && openParameterTypes) {            /* If the return value and all the parameters can be faithfully             * represented as OpenType then we return an OpenMBeanOperationInfo.             * If any of them is a primitive type, we can't.  Compatibility             * with JSR 174 means that we must return an MBean*Info where             * the getType() is the primitive type, not its wrapped type as             * we would get with an OpenMBean*Info.  The OpenType is available             * in the Descriptor in either case.             */            final OpenMBeanParameterInfo[] oparams =                new OpenMBeanParameterInfo[params.length];            System.arraycopy(params, 0, oparams, 0, params.length);            oi = new OpenMBeanOperationInfoSupport(operationName,                                                   description,                                                   oparams,                                                   returnType,                                                   impact,                                                   descriptor);        } else {            oi = new MBeanOperationInfo(operationName,                                        description,                                        params,                                        openReturnType ?                                        returnType.getClassName() :                                        originalTypeString(originalReturnType),                                        impact,                                        descriptor);        }         return oi;    }     @Override    Descriptor getBasicMBeanDescriptor() {        return new ImmutableDescriptor("mxbean=true",                                       "immutableInfo=true");    }     @Override    Descriptor getMBeanDescriptor(Class<?> resourceClass) {        /* We already have immutableInfo=true in the Descriptor         * included in the MBeanInfo for the MXBean interface.  This         * method is being called for the MXBean *class* to add any         * new items beyond those in the interface Descriptor, which         * currently it does not.         */        return ImmutableDescriptor.EMPTY_DESCRIPTOR;    }     private static Descriptor typeDescriptor(OpenType<?> openType,                                             Type originalType) {        return new ImmutableDescriptor(            new String[] {"openType",                          "originalType"},            new Object[] {openType,                          originalTypeString(originalType)});    }     /**     * <p>True if this type can be faithfully represented in an     * OpenMBean*Info.</p>     *     * <p>Compatibility with JSR 174 means that primitive types must be     * represented by an MBean*Info whose getType() is the primitive type     * string, e.g. "int".  If we used an OpenMBean*Info then this string     * would be the wrapped type, e.g. "java.lang.Integer".</p>     *     * <p>Compatibility with JMX 1.2 (including J2SE 5.0) means that arrays     * of primitive types cannot use an ArrayType representing an array of     * primitives, because that didn't exist in JMX 1.2.</p>     */    private static boolean canUseOpenInfo(Type type) {        if (type instanceof GenericArrayType) {            return canUseOpenInfo(                ((GenericArrayType) type).getGenericComponentType());        } else if (type instanceof Class<?> && ((Class<?>) type).isArray()) {            return canUseOpenInfo(                ((Class<?>) type).getComponentType());        }        return (!(type instanceof Class<?> && ((Class<?>) type).isPrimitive()));    }     private static String originalTypeString(Type type) {        if (type instanceof Class<?>)            return ((Class<?>) type).getName();        else            return typeName(type);    }     static String typeName(Type type) {        if (type instanceof Class<?>) {            Class<?> c = (Class<?>) type;            if (c.isArray())                return typeName(c.getComponentType()) + "[]";            else                return c.getName();        } else if (type instanceof GenericArrayType) {            GenericArrayType gat = (GenericArrayType) type;            return typeName(gat.getGenericComponentType()) + "[]";        } else if (type instanceof ParameterizedType) {            ParameterizedType pt = (ParameterizedType) type;            StringBuilder sb = new StringBuilder();            sb.append(typeName(pt.getRawType())).append("<");            String sep = "";            for (Type t : pt.getActualTypeArguments()) {                sb.append(sep).append(typeName(t));                sep = ", ";            }            return sb.append(">").toString();        } else            return "???";    }     private final PerInterfaceMap<ConvertingMethod>        perInterfaceMap = new PerInterfaceMap<ConvertingMethod>();     private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();}