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

org.jboss.mx.capability.OptimizedMBeanDispatcher Maven / Gradle / Ivy

The newest version!
/*
 * 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.capability;

import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.*;
import org.jboss.mx.metadata.AttributeOperationResolver;
import org.jboss.mx.server.ServerConstants;

import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ReflectionException;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;


/**
 * Byte code optimized dispatcher for Standard MBeans. This dispatcher generates
 * an invoke implementation that handles the operation dispatching without
 * Java reflection.

* * The use of this dispatcher may be controlled by setting a * {@link org.jboss.mx.server.ServerConstants#OPTIMIZE_REFLECTED_DISPATCHER OPTIMIZE_REFLECTED_DISPATCHER} * property to either "true" or "false" string value. * * @see org.jboss.mx.capability.ReflectedMBeanDispatcher * @see org.jboss.mx.capability.DispatchClassLoader * * @author Juha Lindfors. * @version $Revision: 81026 $ * */ public class OptimizedMBeanDispatcher implements ServerConstants { // Constants ----------------------------------------------------- final static Class SUPER_CLASS = ReflectedMBeanDispatcher.class; // Static -------------------------------------------------------- public static ReflectedMBeanDispatcher create(MBeanInfo info, Object resource) { try { // construct class template String className = resource.getClass().getName().replace('.', '_') + "_Dispatcher"; String superClass = SUPER_CLASS.getName(); String fileName = className + ".class"; int modifiers = Constants.ACC_PUBLIC; String[] interfaces = new String[0]; ClassGen clazz = new ClassGen(className, superClass, fileName, modifiers, interfaces); ConstantPoolGen cp = clazz.getConstantPool(); clazz.addMethod(createConstructor(cp, className).getMethod()); clazz.addMethod(createInvoke(cp, info, className, resource.getClass().getName()).getMethod()); clazz.update(); JavaClass c = clazz.getJavaClass(); ByteArrayOutputStream baos = new ByteArrayOutputStream(2000); BufferedOutputStream bos = new BufferedOutputStream(baos); c.dump(bos); // FIXME: what about ctx cl? // FIXME: also I dont know if the parent is right here, have to check later ClassLoader ocl = new DispatchClassLoader(resource.getClass().getClassLoader(), className, baos.toByteArray()); Class dispatcherClass = ocl.loadClass(className); Constructor constr = dispatcherClass.getConstructor( new Class[] { MBeanInfo.class, AttributeOperationResolver.class, Object.class } ); Object o = constr.newInstance(new Object[] { info, new AttributeOperationResolver(info), resource }); return (ReflectedMBeanDispatcher)o; } catch (Exception e) { e.printStackTrace(); throw new Error(); } } /** * Returns the signature of a MBean operation using the grammar required by * the class file format, excluding the method name.

* *

The Java Virtual Machine Specification: 4.3.3 Method Descriptors

* * A method descriptor represents the parameters that the method takes and the value that it returns:
    *
    * MethodDescriptor:
    *    ( ParameterDescriptor* ) ReturnDescriptor
    * 
* * A parameter descriptor represents a parameter passed to a method:
    *
    * ParameterDescriptor:
    *    FieldType
    * 
* * A return descriptor represents the type of the value returned from a method. It is a series of characters generated by the grammar:
    *
    * ReturnDescriptor:
    *    FieldType
    *    V
    * 
* * The character V indicates that the method returns no value (its return type is void).

* * For example, the method descriptor for the method
* *

  Object mymethod(int i, double d, Thread t)  
* * is
* *
  (IDLjava/lang/Thread;)Ljava/lang/Object;  
* * Note that internal forms of the fully qualified names of Thread and Object are used in the method descriptor. */ public static String getMethodDescriptor(MBeanParameterInfo[] signature, String returnType) { StringBuffer sign = new StringBuffer(256); sign.append("("); for (int i = 0; i < signature.length; ++i) sign.append(getDescriptorForType(signature[i].getName())); sign.append(")" + getDescriptorForType(returnType)); return sign.toString(); } /** * Returns a descriptor for a given Java type. See {@link java.lang.Class#getName() Class.getName()} * for details on the grammar for arrays and primitive types. Note that the internal form of the fully * qualified name for class Object is used, so for example, the returned descriptor for * java.lang.Object is * *
Ljava/lang/Object;
* * See JVM spec 4.2 and 4.3 for detailed description of the internal class name format and grammar notation. * * @param name fully qualified name of the Java type * @return descriptor string using the JVM grammar */ public static String getDescriptorForType(String name) { if (name.equals(Byte.TYPE.getName())) return "B"; else if (name.equals(Character.TYPE.getName())) return "C"; else if (name.equals(Double.TYPE.getName())) return "D"; else if (name.equals(Float.TYPE.getName())) return "F"; else if (name.equals(Integer.TYPE.getName())) return "I"; else if (name.equals(Long.TYPE.getName())) return "J"; else if (name.equals(Short.TYPE.getName())) return "S"; else if (name.equals(Boolean.TYPE.getName())) return "Z"; else if (name.equals(Void.TYPE.getName())) return "V"; else if (name.startsWith("[")) return name.replace('.', '/'); else return "L" + name.replace('.', '/') + ";"; } /** * Checks if a given name matches the TYPE name of a primitive wrapper class. * * @see java.lang.Integer#TYPE * * @param name TYPE.getName() * @return true if is a primitive type name; false otherwise */ public static boolean isPrimitive(String name) { if (name.equals(Byte.TYPE.getName()) || name.equals(Character.TYPE.getName()) || name.equals(Double.TYPE.getName()) || name.equals(Float.TYPE.getName()) || name.equals(Integer.TYPE.getName()) || name.equals(Long.TYPE.getName()) || name.equals(Short.TYPE.getName()) || name.equals(Boolean.TYPE.getName())) return true; return false; } // Protected ----------------------------------------------------- /** * creates constructor <init>(MBeanInfo info, AttributeOperationResolver resolver, Object resource) * that calls super(info, resolver, resource) in its implementation * * @param cp constant pool * @param className name of the class being generated */ protected static MethodGen createConstructor(ConstantPoolGen cp, String className) { InstructionList constrInstructions = new InstructionList(); int constrRefIndex = cp.addMethodref( SUPER_CLASS.getName(), "", "(" + getDescriptorForType(MBeanInfo.class.getName()) + getDescriptorForType(AttributeOperationResolver.class.getName()) + getDescriptorForType(Object.class.getName()) + ")V" ); constrInstructions.append(new ALOAD(0)); // Stack: => ..., this constrInstructions.append(new ALOAD(1)); // Stack: => ..., this, arg1 [MBeanInfo] constrInstructions.append(new ALOAD(2)); // Stack: => ..., this, arg1 [MBeanInfo], arg2 [AttributeOperationResolver] constrInstructions.append(new ALOAD(3)); // Stack: => ..., this, arg1 [MBeanInfo], arg2 [AttributeOperationResolver], arg3 [Object] constrInstructions.append(new INVOKESPECIAL(constrRefIndex)); // Stack: => ... constrInstructions.append(new RETURN()); // Stack: => MethodGen constrMethod = new MethodGen( Constants.ACC_PUBLIC, Type.VOID, new Type[] { new ObjectType(MBeanInfo.class.getName()), new ObjectType(AttributeOperationResolver.class.getName()), new ObjectType(Object.class.getName()) }, new String[] { "info", "resolver", "resource" }, "", className, constrInstructions, cp ); constrMethod.setMaxStack(4); return constrMethod; } /** * Creates the implementation of the invoke(String actionName, Object[] args, String[] signature) * method. This implementation currently handles all non overloaded MBean operation invocations. * Overloaded operations still fall back to the default reflected invocations.

* * The Java equivalent of the implementation looks roughly as follows:

    *
    * public void invoke(String actionName, Object[] args, String[] signature)
    * {
    *    if (actionName != null)
    *    {
    *       try
    *       {
    *          if (actionName.equals(<operName1>))
    *             return ((<resource type>)super.getResourceObject()).<operName1>((<arg1 type>)arg1, (<arg2 type>)arg2, ...);
    *          else if (actionName.equals(<operName2>))
    *             return ((<resource type>)super.getResourceObject()).<operName2>((<arg1 type>)arg1, (<arg2 type>)arg2, ...);
    *
    *          ...
    *
    *          else
    *             super.invoke(actionName, args, signature);
    *      }
    *      catch (Throwable t)
    *      {
    *          super.invoke(actionName, args, signature);
    *      }
    *    }
    * }
    * 
* * @param cp constant pool of the class being generated * @param info metadata of the MBean * @param className name of the class being generated * @param resourceClassName name of the resource class being invoked */ protected static MethodGen createInvoke(ConstantPoolGen cp, MBeanInfo info, String className, String resourceClassName) { InstructionList invokeInstructions = new InstructionList(); MethodEntry[] operations = getOperations(info); // load operation name strings and methods to constant pool for (int i = 0; i < operations.length; ++i) { operations[i].nameIndexInCP = cp.addString(operations[i].getName()); operations[i].methodIndexInCP = cp.addMethodref( resourceClassName, operations[i].getName(), operations[i].methodDescriptor ); } int invokeIndex = cp.addMethodref( SUPER_CLASS.getName(), "invoke", "(" + getDescriptorForType(String.class.getName()) + getDescriptorForType(Object[].class.getName()) + getDescriptorForType(String[].class.getName()) + ")" + getDescriptorForType(Object.class.getName()) ); int getResourceObjectIndex = cp.addMethodref( SUPER_CLASS.getName(), "getResourceObject", "()Ljava/lang/Object;" ); int strEqualsIndex = cp.addMethodref( String.class.getName(), "equals", "(Ljava/lang/Object;)Z" ); InstructionHandle beginTryBlock = null; InstructionHandle endTryBlock = null; IFNULL ifOperationEqualsNull = new IFNULL(null); IFEQ operationElseIfBranch = null; if (operations.length > 0) { // // if (actionName != null) // invokeInstructions.append(new ALOAD(1)); // Stack: => ..., arg1 [String] beginTryBlock = invokeInstructions.append(ifOperationEqualsNull); // Stack: => ... for (int i = 0; i < operations.length; ++i) { // // if (actionName.equals(operations[i].getName()); // InstructionHandle jumpToNextElse = invokeInstructions.append(new ALOAD(1)); // Stack: => ..., arg1 [String] invokeInstructions.append(new LDC(operations[i].nameIndexInCP)); // Stack: => ..., opName [String] invokeInstructions.append(new INVOKEVIRTUAL(strEqualsIndex)); // Stack: => ..., 0 | 1 [boolean] // set the jump target for previous else if branch if (operationElseIfBranch != null) operationElseIfBranch.setTarget(jumpToNextElse); operationElseIfBranch = new IFEQ(null); invokeInstructions.append(operationElseIfBranch); // Stack: => ... invokeInstructions.append(new ALOAD(0)); // Stack: => ..., this invokeInstructions.append(new INVOKEVIRTUAL(getResourceObjectIndex)); // Stack: => ..., resource [Object] int x = cp.addClass(resourceClassName); invokeInstructions.append(new CHECKCAST(x)); // Stack: => ..., resource [] // if invocation has args, we need to push them into stack if (operations[i].getSignature().length > 0) { for (int arrayIndex = 0; arrayIndex < operations[i].getSignature().length; ++arrayIndex) { invokeInstructions.append(new ALOAD(2)); // Stack: => ..., resource [], arg2 [Object[]] invokeInstructions.append(new PUSH(cp, arrayIndex)); // Stack: => ..., resource [], arg2 [Object[]], array index [int] invokeInstructions.append(new AALOAD()); // Stack: => ..., resource [], array[index] [Object] // Args come in as objects. If signature has a primitive type // we need to convert the arg before we can invoke the operation String type = operations[i].getSignature() [arrayIndex].getName(); if (isPrimitive(type)) invokeInstructions.append(convertObjectToPrimitive(cp, type)); // Stack: => ..., resource[], value [] else { x = cp.addClass(type); invokeInstructions.append(new CHECKCAST(x)); // Stack: => ..., resource[], value [] } } } // // resource.() // x = operations[i].methodIndexInCP; invokeInstructions.append(new INVOKEVIRTUAL(x)); // Stack: => ..., returnvalue // Wrap primitive return values into their corresponding wrapper objects String type = operations[i].getReturnType(); if (isPrimitive(type)) { invokeInstructions.append(convertPrimitiveToObject(cp, type)); // Stack: => ..., objectref [wrapper] invokeInstructions.append(new ARETURN()); // Stack: => } else if (type.equals(Void.TYPE.getName())) { invokeInstructions.append(new ACONST_NULL()); // Stack: => ..., null invokeInstructions.append(new ARETURN()); // Stack: => } else { invokeInstructions.append(new ARETURN()); // Stack: => } } } // // super.invoke(actionName, args, signature) if no match was found // InstructionHandle jumpToSuperInvoke = invokeInstructions.append(new ALOAD(0)); // Stack: => ..., this invokeInstructions.append(new ALOAD(1)); // Stack: => ..., this, arg1 [String] invokeInstructions.append(new ALOAD(2)); // Stack: => ..., this, arg1 [String], arg2 [Object[]] invokeInstructions.append(new ALOAD(3)); // Stack: => ..., this, arg1 [String], arg2 [Object[]], arg3 [String[]] invokeInstructions.append(new INVOKESPECIAL(invokeIndex)); // Stack: => ..., reference [Object] invokeInstructions.append(new ARETURN()); // Stack: => // set the jump targets ifOperationEqualsNull.setTarget(jumpToSuperInvoke); if (operations.length > 0) { // set the last else branch to call super.invoke if (operationElseIfBranch != null) operationElseIfBranch.setTarget(jumpToSuperInvoke); // set the try catch block limits beginTryBlock = beginTryBlock.getNext(); endTryBlock = jumpToSuperInvoke.getPrev(); } // exception handler (it's a cheap shot -- if there is any exception, re-invoke // on super class and let it handle all exceptions) InstructionHandle exceptionHandlerCode = invokeInstructions.append(new ALOAD(0)); invokeInstructions.append(new ALOAD(1)); invokeInstructions.append(new ALOAD(2)); invokeInstructions.append(new ALOAD(3)); invokeInstructions.append(new INVOKESPECIAL(invokeIndex)); invokeInstructions.append(new ARETURN()); MethodGen invokeMethod = new MethodGen( Constants.ACC_PUBLIC, Type.OBJECT, new Type[] { Type.STRING, new ArrayType(Object.class.getName(), 1), new ArrayType(String.class.getName(), 1) }, new String[] { "operationName", "args", "signature" }, "invoke", className, invokeInstructions, cp ); invokeMethod.setMaxLocals(7); invokeMethod.setMaxStack(calculateMaxStackSize(info)); invokeMethod.addException(ReflectionException.class.getName()); invokeMethod.addException(MBeanException.class.getName()); if (operations.length > 0) { invokeMethod.addExceptionHandler(beginTryBlock, endTryBlock, exceptionHandlerCode, new ObjectType("java.lang.Throwable")); } return invokeMethod; } private static int calculateMaxStackSize(MBeanInfo info) { MBeanOperationInfo[] operations = info.getOperations(); int maxSize = 7; for (int i = 0; i < operations.length; ++i) { if (operations[i].getSignature().length > maxSize + 2) maxSize = operations[i].getSignature().length + 2; } return maxSize; } /** * Converts a reference of a primitve wrapper object into a primite value type. * This method assumes that the wrapper object reference is already loaded at the * top of the operand stack. The stack is modified so that the object reference * to a primitive wrapper is replaced by the corresponding value in the stack. * * @param cp constant pool * @param type class name of the primitive wrapper object to convert * @return an instruction list that replaces an object reference of a primitive * wrapper object to its corresponding value in the operand stack */ protected static InstructionList convertObjectToPrimitive(ConstantPoolGen cp, String type) { InstructionList il = new InstructionList(); int intValueIndex = cp.addMethodref(Integer.class.getName(), "intValue", "()I"); int byteValueIndex = cp.addMethodref(Byte.class.getName(), "byteValue", "()B"); int charValueIndex = cp.addMethodref(Character.class.getName(), "charValue", "()C"); int doubleValueIndex = cp.addMethodref(Double.class.getName(), "doubleValue", "()D"); int floatValueIndex = cp.addMethodref(Float.class.getName(), "floatValue", "()F"); int longValueIndex = cp.addMethodref(Long.class.getName(), "longValue", "()J"); int shortValueIndex = cp.addMethodref(Short.class.getName(), "shortValue", "()S"); int booleanValueIndex = cp.addMethodref(Boolean.class.getName(), "booleanValue", "()Z"); // // Assumes the wrapper object reference is on top of the stack // if (type.equals(Integer.TYPE.getName())) { int x = cp.addClass("java.lang.Integer"); il.append(new CHECKCAST(x)); // Stack: => ..., type [Integer] il.append(new INVOKEVIRTUAL(intValueIndex)); // Stack: => ..., value [int] } else if (type.equals(Byte.TYPE.getName())) { int x = cp.addClass("java.lang.Byte"); il.append(new CHECKCAST(x)); // Stack: => ..., type [Boolean] il.append(new INVOKEVIRTUAL(byteValueIndex)); // Stack: => ..., 0 | 1 [boolean] } else if (type.equals(Character.TYPE.getName())) { int x = cp.addClass("java.lang.Character"); il.append(new CHECKCAST(x)); // Stack: => ..., type [Character] il.append(new INVOKEVIRTUAL(charValueIndex)); // Stack: => ..., value [char] } else if (type.equals(Double.TYPE.getName())) { int x = cp.addClass("java.lang.Double"); il.append(new CHECKCAST(x)); // Stack: => ..., type [Double] il.append(new INVOKEVIRTUAL(doubleValueIndex)); // Stack: => ..., value [double] } else if (type.equals(Float.TYPE.getName())) { int x = cp.addClass("java.lang.Float"); il.append(new CHECKCAST(x)); // Stack: => ..., type [Float] il.append(new INVOKEVIRTUAL(floatValueIndex)); // Stack: => ..., value [float] } else if (type.equals(Long.TYPE.getName())) { int x = cp.addClass("java.lang.Long"); il.append(new CHECKCAST(x)); // Stack: => ..., type [Long] il.append(new INVOKEVIRTUAL(longValueIndex)); // Stack: => ..., value [long] } else if (type.equals(Short.TYPE.getName())) { int x = cp.addClass("java.lang.Short"); il.append(new CHECKCAST(x)); // Stack: => ..., type [Short] il.append(new INVOKEVIRTUAL(shortValueIndex)); // Stack: => ..., value [short] } else if (type.equals(Boolean.TYPE.getName())) { int x = cp.addClass("java.lang.Boolean"); il.append(new CHECKCAST(x)); // Stack: => ..., type [Boolean] il.append(new INVOKEVIRTUAL(booleanValueIndex)); // Stack: => ..., value [boolean] } return il; } /** * Converts a primitive into its corresponding object wrapper reference. * This method assumes the primitve is already pushed to the top of the operand * stack. The stack is modified so that the primitive value is replaced * by a reference to its corresponding wrapper object that has been * initialized to contain the same value. * * @param cp constant pool * @param type type string of the primitive, for example {@link java.lang.Integer#TYPE Integer.TYPE.getName()} * @return an instruction list that replaces the primitive type at the top of * the operand stack with its corresponding, initialized, wrapper object */ protected static InstructionList convertPrimitiveToObject(ConstantPoolGen cp, String type) { InstructionList il = new InstructionList(); if (type.equals(Boolean.TYPE.getName())) { int x = cp.addClass("java.lang.Boolean"); int constrIndex = cp.addMethodref("java.lang.Boolean", "", "(B)V"); il.append(new ISTORE(4)); il.append(new NEW(x)); il.append(new ASTORE(5)); il.append(new ALOAD(5)); il.append(new ILOAD(4)); il.append(new INVOKESPECIAL(constrIndex)); il.append(new ALOAD(5)); } else if (type.equals(Short.TYPE.getName())) { int x = cp.addClass("java.lang.Short"); int constrIndex = cp.addMethodref("java.lang.Short", "", "(S)V"); il.append(new ISTORE(4)); il.append(new NEW(x)); il.append(new ASTORE(5)); il.append(new ALOAD(5)); il.append(new ILOAD(4)); il.append(new INVOKESPECIAL(constrIndex)); il.append(new ALOAD(5)); } else if (type.equals(Long.TYPE.getName())) { int x = cp.addClass("java.lang.Long"); int constrIndex = cp.addMethodref("java.lang.Long", "", "(J)V"); il.append(new LSTORE(4)); il.append(new NEW(x)); il.append(new ASTORE(6)); il.append(new ALOAD(6)); il.append(new LLOAD(4)); il.append(new INVOKESPECIAL(constrIndex)); il.append(new ALOAD(6)); } else if (type.equals(Integer.TYPE.getName())) { int x = cp.addClass("java.lang.Integer"); int constrIndex = cp.addMethodref("java.lang.Integer", "", "(I)V"); il.append(new ISTORE(4)); il.append(new NEW(x)); il.append(new ASTORE(5)); il.append(new ALOAD(5)); il.append(new ILOAD(4)); il.append(new INVOKESPECIAL(constrIndex)); il.append(new ALOAD(5)); } else if (type.equals(Float.TYPE.getName())) { int x = cp.addClass("java.lang.Float"); int constrIndex = cp.addMethodref("java.lang.Float", "", "(F)V"); il.append(new FSTORE(4)); il.append(new NEW(x)); il.append(new ASTORE(5)); il.append(new ALOAD(5)); il.append(new FLOAD(4)); il.append(new INVOKESPECIAL(constrIndex)); il.append(new ALOAD(5)); } else if (type.equals(Double.TYPE.getName())) { int x = cp.addClass("java.lang.Double"); int constrIndex = cp.addMethodref("java.lang.Double", "", "(D)V"); il.append(new DSTORE(4)); il.append(new NEW(x)); il.append(new ASTORE(6)); il.append(new ALOAD(6)); il.append(new DLOAD(4)); il.append(new INVOKESPECIAL(constrIndex)); il.append(new ALOAD(6)); } else if (type.equals(Character.TYPE.getName())) { int x = cp.addClass("java.lang.Character"); int constrIndex = cp.addMethodref("java.lang.Character", "", "(C)V"); il.append(new ISTORE(4)); il.append(new NEW(x)); il.append(new ASTORE(5)); il.append(new ALOAD(5)); il.append(new ILOAD(4)); il.append(new INVOKESPECIAL(constrIndex)); il.append(new ALOAD(5)); } else if (type.equals(Byte.TYPE.getName())) { int x = cp.addClass("java.lang.Byte"); int constrIndex = cp.addMethodref("java.lang.Byte", "", "(B)V"); il.append(new ISTORE(4)); il.append(new NEW(x)); il.append(new ASTORE(5)); il.append(new ALOAD(5)); il.append(new ILOAD(4)); il.append(new INVOKESPECIAL(constrIndex)); il.append(new ALOAD(5)); } return il; } /** * Returns a subset of MBean's operations. Overloaded operations are not supported yet, * so they're left out of the list and their invocations are delegated to the reflection * based super class.

* * Overloaded operations that differ in their arg list length may be able to gain in * performance if implemented directly with byte code. Overloaded operations with * equal arg list length may not show much difference compared to ternary search tree * based resolver. */ protected static MethodEntry[] getOperations(MBeanInfo info) { HashMap operationMap = new HashMap(); ArrayList overloadList = new ArrayList(); MBeanOperationInfo[] operations = info.getOperations(); for (int i = 0; i < operations.length; ++i) { String methodName = operations[i].getName(); if (operationMap.containsKey(methodName)) overloadList.add(methodName); else operationMap.put(methodName, new MethodEntry(operations[i])); } // method overloading not supported yet Iterator it = overloadList.iterator(); while (it.hasNext()) operationMap.remove(it.next()); return (MethodEntry[])operationMap.values().toArray(new MethodEntry[0]); } // Inner classes ------------------------------------------------- private static class MethodEntry extends MBeanOperationInfo { private static final long serialVersionUID = 1792631947840418314L; String methodDescriptor = null; int nameIndexInCP = -1; int methodIndexInCP = -1; public MethodEntry(MBeanOperationInfo info) { super(info.getName(), info.getDescription(), info.getSignature(), info.getReturnType(), info.getImpact()); this.methodDescriptor = getMethodDescriptor(info.getSignature(), info.getReturnType()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy