001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.capability;
023:
024: import org.apache.bcel.Constants;
025: import org.apache.bcel.classfile.JavaClass;
026: import org.apache.bcel.generic.*;
027: import org.jboss.mx.metadata.AttributeOperationResolver;
028: import org.jboss.mx.server.ServerConstants;
029:
030: import javax.management.MBeanException;
031: import javax.management.MBeanInfo;
032: import javax.management.MBeanOperationInfo;
033: import javax.management.MBeanParameterInfo;
034: import javax.management.ReflectionException;
035: import java.io.BufferedOutputStream;
036: import java.io.ByteArrayOutputStream;
037: import java.lang.reflect.Constructor;
038: import java.util.ArrayList;
039: import java.util.HashMap;
040: import java.util.Iterator;
041:
042: /**
043: * Byte code optimized dispatcher for Standard MBeans. This dispatcher generates
044: * an invoke implementation that handles the operation dispatching without
045: * Java reflection.<p>
046: *
047: * The use of this dispatcher may be controlled by setting a
048: * {@link org.jboss.mx.server.ServerConstants#OPTIMIZE_REFLECTED_DISPATCHER OPTIMIZE_REFLECTED_DISPATCHER}
049: * property to either <tt>"true"</tt> or <tt>"false"</tt> string value.
050: *
051: * @see org.jboss.mx.capability.ReflectedMBeanDispatcher
052: * @see org.jboss.mx.capability.DispatchClassLoader
053: *
054: * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
055: * @version $Revision: 57200 $
056: *
057: */
058: public class OptimizedMBeanDispatcher implements ServerConstants {
059: // Constants -----------------------------------------------------
060: final static Class SUPER_CLASS = ReflectedMBeanDispatcher.class;
061:
062: // Static --------------------------------------------------------
063: public static ReflectedMBeanDispatcher create(MBeanInfo info,
064: Object resource) {
065: try {
066: // construct class template
067: String className = resource.getClass().getName().replace(
068: '.', '_')
069: + "_Dispatcher";
070: String super Class = SUPER_CLASS.getName();
071: String fileName = className + ".class";
072: int modifiers = Constants.ACC_PUBLIC;
073: String[] interfaces = new String[0];
074:
075: ClassGen clazz = new ClassGen(className, super Class,
076: fileName, modifiers, interfaces);
077: ConstantPoolGen cp = clazz.getConstantPool();
078:
079: clazz.addMethod(createConstructor(cp, className)
080: .getMethod());
081: clazz.addMethod(createInvoke(cp, info, className,
082: resource.getClass().getName()).getMethod());
083: clazz.update();
084:
085: JavaClass c = clazz.getJavaClass();
086:
087: ByteArrayOutputStream baos = new ByteArrayOutputStream(2000);
088: BufferedOutputStream bos = new BufferedOutputStream(baos);
089: c.dump(bos);
090:
091: // FIXME: what about ctx cl?
092: // FIXME: also I dont know if the parent is right here, have to check later
093: ClassLoader ocl = new DispatchClassLoader(resource
094: .getClass().getClassLoader(), className, baos
095: .toByteArray());
096:
097: Class dispatcherClass = ocl.loadClass(className);
098: Constructor constr = dispatcherClass
099: .getConstructor(new Class[] { MBeanInfo.class,
100: AttributeOperationResolver.class,
101: Object.class });
102:
103: Object o = constr.newInstance(new Object[] { info,
104: new AttributeOperationResolver(info), resource });
105:
106: return (ReflectedMBeanDispatcher) o;
107: } catch (Exception e) {
108: e.printStackTrace();
109: throw new Error();
110: }
111: }
112:
113: /**
114: * Returns the signature of a MBean operation using the grammar required by
115: * the class file format, excluding the method name. <p>
116: *
117: * <h4>The Java Virtual Machine Specification: 4.3.3 Method Descriptors</h4>
118: *
119: * A method descriptor represents the parameters that the method takes and the value that it returns: <br><i><pre>
120: *
121: * MethodDescriptor:
122: * ( ParameterDescriptor* ) ReturnDescriptor
123: * </pre></i>
124: *
125: * A parameter descriptor represents a parameter passed to a method: <br><i><pre>
126: *
127: * ParameterDescriptor:
128: * FieldType
129: * </pre></i>
130: *
131: * A return descriptor represents the type of the value returned from a method. It is a series of characters generated by the grammar: <br><i><pre>
132: *
133: * ReturnDescriptor:
134: * FieldType
135: * V
136: * </pre></i>
137: *
138: * The character V indicates that the method returns no value (its return type is void). <p>
139: *
140: * For example, the method descriptor for the method <br>
141: *
142: * <pre> Object mymethod(int i, double d, Thread t) </pre>
143: *
144: * is <br>
145: *
146: * <b><pre> (IDLjava/lang/Thread;)Ljava/lang/Object; </pre></b>
147: *
148: * Note that internal forms of the fully qualified names of Thread and Object are used in the method descriptor.
149: */
150: public static String getMethodDescriptor(
151: MBeanParameterInfo[] signature, String returnType) {
152:
153: StringBuffer sign = new StringBuffer(256);
154: sign.append("(");
155:
156: for (int i = 0; i < signature.length; ++i)
157: sign.append(getDescriptorForType(signature[i].getName()));
158:
159: sign.append(")" + getDescriptorForType(returnType));
160:
161: return sign.toString();
162: }
163:
164: /**
165: * Returns a descriptor for a given Java type. See {@link java.lang.Class#getName() Class.getName()}
166: * for details on the grammar for arrays and primitive types. Note that the internal form of the fully
167: * qualified name for class Object is used, so for example, the returned descriptor for
168: * <tt>java.lang.Object</tt> is
169: *
170: * <b><pre>Ljava/lang/Object;</pre></b>
171: *
172: * See JVM spec �4.2 and �4.3 for detailed description of the internal class name format and grammar notation.
173: *
174: * @param name fully qualified name of the Java type
175: * @return descriptor string using the JVM grammar
176: */
177: public static String getDescriptorForType(String name) {
178: if (name.equals(Byte.TYPE.getName()))
179: return "B";
180: else if (name.equals(Character.TYPE.getName()))
181: return "C";
182: else if (name.equals(Double.TYPE.getName()))
183: return "D";
184: else if (name.equals(Float.TYPE.getName()))
185: return "F";
186: else if (name.equals(Integer.TYPE.getName()))
187: return "I";
188: else if (name.equals(Long.TYPE.getName()))
189: return "J";
190: else if (name.equals(Short.TYPE.getName()))
191: return "S";
192: else if (name.equals(Boolean.TYPE.getName()))
193: return "Z";
194: else if (name.equals(Void.TYPE.getName()))
195: return "V";
196: else if (name.startsWith("["))
197: return name.replace('.', '/');
198: else
199: return "L" + name.replace('.', '/') + ";";
200: }
201:
202: /**
203: * Checks if a given name matches the <tt>TYPE</tt> name of a primitive wrapper class.
204: *
205: * @see java.lang.Integer#TYPE
206: *
207: * @param name TYPE.getName()
208: * @return true if is a primitive type name; false otherwise
209: */
210: public static boolean isPrimitive(String name) {
211: if (name.equals(Byte.TYPE.getName())
212: || name.equals(Character.TYPE.getName())
213: || name.equals(Double.TYPE.getName())
214: || name.equals(Float.TYPE.getName())
215: || name.equals(Integer.TYPE.getName())
216: || name.equals(Long.TYPE.getName())
217: || name.equals(Short.TYPE.getName())
218: || name.equals(Boolean.TYPE.getName()))
219:
220: return true;
221:
222: return false;
223: }
224:
225: // Protected -----------------------------------------------------
226:
227: /**
228: * creates constructor <tt><init>(MBeanInfo info, AttributeOperationResolver resolver, Object resource)</tt>
229: * that calls <tt>super(info, resolver, resource)</tt> in its implementation
230: *
231: * @param cp constant pool
232: * @param className name of the class being generated
233: */
234: protected static MethodGen createConstructor(ConstantPoolGen cp,
235: String className) {
236: InstructionList constrInstructions = new InstructionList();
237:
238: int constrRefIndex = cp
239: .addMethodref(
240: SUPER_CLASS.getName(),
241: "<init>",
242: "("
243: + getDescriptorForType(MBeanInfo.class
244: .getName())
245: + getDescriptorForType(AttributeOperationResolver.class
246: .getName())
247: + getDescriptorForType(Object.class
248: .getName()) + ")V");
249:
250: constrInstructions.append(new ALOAD(0)); // Stack: => ..., this
251: constrInstructions.append(new ALOAD(1)); // Stack: => ..., this, arg1 [MBeanInfo]
252: constrInstructions.append(new ALOAD(2)); // Stack: => ..., this, arg1 [MBeanInfo], arg2 [AttributeOperationResolver]
253: constrInstructions.append(new ALOAD(3)); // Stack: => ..., this, arg1 [MBeanInfo], arg2 [AttributeOperationResolver], arg3 [Object]
254: constrInstructions.append(new INVOKESPECIAL(constrRefIndex)); // Stack: => ...
255: constrInstructions.append(new RETURN()); // Stack: => <empty>
256:
257: MethodGen constrMethod = new MethodGen(Constants.ACC_PUBLIC,
258: Type.VOID, new Type[] {
259: new ObjectType(MBeanInfo.class.getName()),
260: new ObjectType(AttributeOperationResolver.class
261: .getName()),
262: new ObjectType(Object.class.getName()) },
263: new String[] { "info", "resolver", "resource" },
264: "<init>", className, constrInstructions, cp);
265: constrMethod.setMaxStack(4);
266:
267: return constrMethod;
268: }
269:
270: /**
271: * Creates the implementation of the <tt>invoke(String actionName, Object[] args, String[] signature)</tt>
272: * method. This implementation currently handles all non overloaded MBean operation invocations.
273: * Overloaded operations still fall back to the default reflected invocations. <p>
274: *
275: * The Java equivalent of the implementation looks roughly as follows:<br><pre>
276: *
277: * public void invoke(String actionName, Object[] args, String[] signature)
278: * {
279: * if (actionName != null)
280: * {
281: * try
282: * {
283: * if (actionName.equals(<operName1>))
284: * return ((<resource type>)super.getResourceObject()).<operName1>((<arg1 type>)arg1, (<arg2 type>)arg2, ...);
285: * else if (actionName.equals(<operName2>))
286: * return ((<resource type>)super.getResourceObject()).<operName2>((<arg1 type>)arg1, (<arg2 type>)arg2, ...);
287: *
288: * ...
289: *
290: * else
291: * super.invoke(actionName, args, signature);
292: * }
293: * catch (Throwable t)
294: * {
295: * super.invoke(actionName, args, signature);
296: * }
297: * }
298: * }
299: * </pre>
300: *
301: * @param cp constant pool of the class being generated
302: * @param info metadata of the MBean
303: * @param className name of the class being generated
304: * @param resourceClassName name of the resource class being invoked
305: */
306: protected static MethodGen createInvoke(ConstantPoolGen cp,
307: MBeanInfo info, String className, String resourceClassName) {
308: InstructionList invokeInstructions = new InstructionList();
309: MethodEntry[] operations = getOperations(info);
310:
311: // load operation name strings and methods to constant pool
312: for (int i = 0; i < operations.length; ++i) {
313: operations[i].nameIndexInCP = cp.addString(operations[i]
314: .getName());
315: operations[i].methodIndexInCP = cp.addMethodref(
316: resourceClassName, operations[i].getName(),
317: operations[i].methodDescriptor);
318: }
319:
320: int invokeIndex = cp
321: .addMethodref(SUPER_CLASS.getName(), "invoke",
322: "("
323: + getDescriptorForType(String.class
324: .getName())
325: + getDescriptorForType(Object[].class
326: .getName())
327: + getDescriptorForType(String[].class
328: .getName())
329: + ")"
330: + getDescriptorForType(Object.class
331: .getName()));
332:
333: int getResourceObjectIndex = cp
334: .addMethodref(SUPER_CLASS.getName(),
335: "getResourceObject", "()Ljava/lang/Object;");
336:
337: int strEqualsIndex = cp.addMethodref(String.class.getName(),
338: "equals", "(Ljava/lang/Object;)Z");
339:
340: InstructionHandle beginTryBlock = null;
341: InstructionHandle endTryBlock = null;
342:
343: IFNULL ifOperationEqualsNull = new IFNULL(null);
344: IFEQ operationElseIfBranch = null;
345:
346: if (operations.length > 0) {
347: //
348: // if (actionName != null)
349: //
350: invokeInstructions.append(new ALOAD(1)); // Stack: => ..., arg1 [String]
351:
352: beginTryBlock = invokeInstructions
353: .append(ifOperationEqualsNull); // Stack: => ...
354:
355: for (int i = 0; i < operations.length; ++i) {
356: //
357: // if (actionName.equals(operations[i].getName());
358: //
359: InstructionHandle jumpToNextElse = invokeInstructions
360: .append(new ALOAD(1)); // Stack: => ..., arg1 [String]
361: invokeInstructions.append(new LDC(
362: operations[i].nameIndexInCP)); // Stack: => ..., opName [String]
363: invokeInstructions.append(new INVOKEVIRTUAL(
364: strEqualsIndex)); // Stack: => ..., 0 | 1 [boolean]
365:
366: // set the jump target for previous else if branch
367: if (operationElseIfBranch != null)
368: operationElseIfBranch.setTarget(jumpToNextElse);
369:
370: operationElseIfBranch = new IFEQ(null);
371: invokeInstructions.append(operationElseIfBranch); // Stack: => ...
372:
373: invokeInstructions.append(new ALOAD(0)); // Stack: => ..., this
374: invokeInstructions.append(new INVOKEVIRTUAL(
375: getResourceObjectIndex)); // Stack: => ..., resource [Object]
376:
377: int x = cp.addClass(resourceClassName);
378: invokeInstructions.append(new CHECKCAST(x)); // Stack: => ..., resource [<resource object type>]
379:
380: // if invocation has args, we need to push them into stack
381: if (operations[i].getSignature().length > 0) {
382:
383: for (int arrayIndex = 0; arrayIndex < operations[i]
384: .getSignature().length; ++arrayIndex) {
385: invokeInstructions.append(new ALOAD(2)); // Stack: => ..., resource [<type>], arg2 [Object[]]
386: invokeInstructions.append(new PUSH(cp,
387: arrayIndex)); // Stack: => ..., resource [<type>], arg2 [Object[]], array index [int]
388: invokeInstructions.append(new AALOAD()); // Stack: => ..., resource [<type>], array[index] [Object]
389:
390: // Args come in as objects. If signature has a primitive type
391: // we need to convert the arg before we can invoke the operation
392: String type = operations[i].getSignature()[arrayIndex]
393: .getName();
394:
395: if (isPrimitive(type))
396: invokeInstructions
397: .append(convertObjectToPrimitive(
398: cp, type)); // Stack: => ..., resource[<type>], value [<primitive>]
399:
400: else {
401: x = cp.addClass(type);
402: invokeInstructions.append(new CHECKCAST(x)); // Stack: => ..., resource[<type>], value [<reference>]
403: }
404: }
405: }
406:
407: //
408: // resource.<operation>(<arg 1, ... arg n>)
409: //
410: x = operations[i].methodIndexInCP;
411: invokeInstructions.append(new INVOKEVIRTUAL(x)); // Stack: => ..., returnvalue
412:
413: // Wrap primitive return values into their corresponding wrapper objects
414: String type = operations[i].getReturnType();
415:
416: if (isPrimitive(type)) {
417: invokeInstructions.append(convertPrimitiveToObject(
418: cp, type)); // Stack: => ..., objectref [wrapper]
419: invokeInstructions.append(new ARETURN()); // Stack: => <empty>
420: } else if (type.equals(Void.TYPE.getName())) {
421: invokeInstructions.append(new ACONST_NULL()); // Stack: => ..., null
422: invokeInstructions.append(new ARETURN()); // Stack: => <empty>
423: } else {
424: invokeInstructions.append(new ARETURN()); // Stack: => <empty>
425: }
426: }
427: }
428:
429: //
430: // super.invoke(actionName, args, signature) if no match was found
431: //
432: InstructionHandle jumpToSuperInvoke = invokeInstructions
433: .append(new ALOAD(0)); // Stack: => ..., this
434: invokeInstructions.append(new ALOAD(1)); // Stack: => ..., this, arg1 [String]
435: invokeInstructions.append(new ALOAD(2)); // Stack: => ..., this, arg1 [String], arg2 [Object[]]
436: invokeInstructions.append(new ALOAD(3)); // Stack: => ..., this, arg1 [String], arg2 [Object[]], arg3 [String[]]
437: invokeInstructions.append(new INVOKESPECIAL(invokeIndex)); // Stack: => ..., reference [Object]
438: invokeInstructions.append(new ARETURN()); // Stack: => <empty>
439:
440: // set the jump targets
441: ifOperationEqualsNull.setTarget(jumpToSuperInvoke);
442:
443: if (operations.length > 0) {
444: // set the last else branch to call super.invoke
445: if (operationElseIfBranch != null)
446: operationElseIfBranch.setTarget(jumpToSuperInvoke);
447:
448: // set the try catch block limits
449: beginTryBlock = beginTryBlock.getNext();
450: endTryBlock = jumpToSuperInvoke.getPrev();
451: }
452:
453: // exception handler (it's a cheap shot -- if there is any exception, re-invoke
454: // on super class and let it handle all exceptions)
455: InstructionHandle exceptionHandlerCode = invokeInstructions
456: .append(new ALOAD(0));
457: invokeInstructions.append(new ALOAD(1));
458: invokeInstructions.append(new ALOAD(2));
459: invokeInstructions.append(new ALOAD(3));
460: invokeInstructions.append(new INVOKESPECIAL(invokeIndex));
461: invokeInstructions.append(new ARETURN());
462:
463: MethodGen invokeMethod = new MethodGen(Constants.ACC_PUBLIC,
464: Type.OBJECT, new Type[] { Type.STRING,
465: new ArrayType(Object.class.getName(), 1),
466: new ArrayType(String.class.getName(), 1) },
467: new String[] { "operationName", "args", "signature" },
468: "invoke", className, invokeInstructions, cp);
469: invokeMethod.setMaxLocals(7);
470: invokeMethod.setMaxStack(calculateMaxStackSize(info));
471:
472: invokeMethod.addException(ReflectionException.class.getName());
473: invokeMethod.addException(MBeanException.class.getName());
474:
475: if (operations.length > 0) {
476: invokeMethod.addExceptionHandler(beginTryBlock,
477: endTryBlock, exceptionHandlerCode, new ObjectType(
478: "java.lang.Throwable"));
479: }
480:
481: return invokeMethod;
482: }
483:
484: private static int calculateMaxStackSize(MBeanInfo info) {
485: MBeanOperationInfo[] operations = info.getOperations();
486: int maxSize = 7;
487:
488: for (int i = 0; i < operations.length; ++i) {
489: if (operations[i].getSignature().length > maxSize + 2)
490: maxSize = operations[i].getSignature().length + 2;
491: }
492:
493: return maxSize;
494: }
495:
496: /**
497: * Converts a reference of a primitve wrapper object into a primite value type.
498: * This method assumes that the wrapper object reference is already loaded at the
499: * top of the operand stack. The stack is modified so that the object reference
500: * to a primitive wrapper is replaced by the corresponding value in the stack.
501: *
502: * @param cp constant pool
503: * @param type class name of the primitive wrapper object to convert
504: * @return an instruction list that replaces an object reference of a primitive
505: * wrapper object to its corresponding value in the operand stack
506: */
507: protected static InstructionList convertObjectToPrimitive(
508: ConstantPoolGen cp, String type) {
509: InstructionList il = new InstructionList();
510:
511: int intValueIndex = cp.addMethodref(Integer.class.getName(),
512: "intValue", "()I");
513: int byteValueIndex = cp.addMethodref(Byte.class.getName(),
514: "byteValue", "()B");
515: int charValueIndex = cp.addMethodref(Character.class.getName(),
516: "charValue", "()C");
517: int doubleValueIndex = cp.addMethodref(Double.class.getName(),
518: "doubleValue", "()D");
519: int floatValueIndex = cp.addMethodref(Float.class.getName(),
520: "floatValue", "()F");
521: int longValueIndex = cp.addMethodref(Long.class.getName(),
522: "longValue", "()J");
523: int shortValueIndex = cp.addMethodref(Short.class.getName(),
524: "shortValue", "()S");
525: int booleanValueIndex = cp.addMethodref(
526: Boolean.class.getName(), "booleanValue", "()Z");
527:
528: //
529: // Assumes the wrapper object reference is on top of the stack
530: //
531:
532: if (type.equals(Integer.TYPE.getName())) {
533: int x = cp.addClass("java.lang.Integer");
534: il.append(new CHECKCAST(x)); // Stack: => ..., type [Integer]
535: il.append(new INVOKEVIRTUAL(intValueIndex)); // Stack: => ..., value [int]
536: }
537:
538: else if (type.equals(Byte.TYPE.getName())) {
539: int x = cp.addClass("java.lang.Byte");
540: il.append(new CHECKCAST(x)); // Stack: => ..., type [Boolean]
541: il.append(new INVOKEVIRTUAL(byteValueIndex)); // Stack: => ..., 0 | 1 [boolean]
542: }
543:
544: else if (type.equals(Character.TYPE.getName())) {
545: int x = cp.addClass("java.lang.Character");
546: il.append(new CHECKCAST(x)); // Stack: => ..., type [Character]
547: il.append(new INVOKEVIRTUAL(charValueIndex)); // Stack: => ..., value [char]
548: }
549:
550: else if (type.equals(Double.TYPE.getName())) {
551: int x = cp.addClass("java.lang.Double");
552: il.append(new CHECKCAST(x)); // Stack: => ..., type [Double]
553: il.append(new INVOKEVIRTUAL(doubleValueIndex)); // Stack: => ..., value [double]
554: }
555:
556: else if (type.equals(Float.TYPE.getName())) {
557: int x = cp.addClass("java.lang.Float");
558: il.append(new CHECKCAST(x)); // Stack: => ..., type [Float]
559: il.append(new INVOKEVIRTUAL(floatValueIndex)); // Stack: => ..., value [float]
560: }
561:
562: else if (type.equals(Long.TYPE.getName())) {
563: int x = cp.addClass("java.lang.Long");
564: il.append(new CHECKCAST(x)); // Stack: => ..., type [Long]
565: il.append(new INVOKEVIRTUAL(longValueIndex)); // Stack: => ..., value [long]
566: }
567:
568: else if (type.equals(Short.TYPE.getName())) {
569: int x = cp.addClass("java.lang.Short");
570: il.append(new CHECKCAST(x)); // Stack: => ..., type [Short]
571: il.append(new INVOKEVIRTUAL(shortValueIndex)); // Stack: => ..., value [short]
572: }
573:
574: else if (type.equals(Boolean.TYPE.getName())) {
575: int x = cp.addClass("java.lang.Boolean");
576: il.append(new CHECKCAST(x)); // Stack: => ..., type [Boolean]
577: il.append(new INVOKEVIRTUAL(booleanValueIndex)); // Stack: => ..., value [boolean]
578: }
579:
580: return il;
581: }
582:
583: /**
584: * Converts a primitive into its corresponding object wrapper reference.
585: * This method assumes the primitve is already pushed to the top of the operand
586: * stack. The stack is modified so that the primitive value is replaced
587: * by a reference to its corresponding wrapper object that has been
588: * initialized to contain the same value.
589: *
590: * @param cp constant pool
591: * @param type type string of the primitive, for example {@link java.lang.Integer#TYPE Integer.TYPE.getName()}
592: * @return an instruction list that replaces the primitive type at the top of
593: * the operand stack with its corresponding, initialized, wrapper object
594: */
595: protected static InstructionList convertPrimitiveToObject(
596: ConstantPoolGen cp, String type) {
597: InstructionList il = new InstructionList();
598:
599: if (type.equals(Boolean.TYPE.getName())) {
600: int x = cp.addClass("java.lang.Boolean");
601: int constrIndex = cp.addMethodref("java.lang.Boolean",
602: "<init>", "(B)V");
603:
604: il.append(new ISTORE(4));
605: il.append(new NEW(x));
606: il.append(new ASTORE(5));
607: il.append(new ALOAD(5));
608: il.append(new ILOAD(4));
609: il.append(new INVOKESPECIAL(constrIndex));
610: il.append(new ALOAD(5));
611: }
612:
613: else if (type.equals(Short.TYPE.getName())) {
614: int x = cp.addClass("java.lang.Short");
615: int constrIndex = cp.addMethodref("java.lang.Short",
616: "<init>", "(S)V");
617:
618: il.append(new ISTORE(4));
619: il.append(new NEW(x));
620: il.append(new ASTORE(5));
621: il.append(new ALOAD(5));
622: il.append(new ILOAD(4));
623: il.append(new INVOKESPECIAL(constrIndex));
624: il.append(new ALOAD(5));
625: }
626:
627: else if (type.equals(Long.TYPE.getName())) {
628: int x = cp.addClass("java.lang.Long");
629: int constrIndex = cp.addMethodref("java.lang.Long",
630: "<init>", "(J)V");
631:
632: il.append(new LSTORE(4));
633: il.append(new NEW(x));
634: il.append(new ASTORE(6));
635: il.append(new ALOAD(6));
636: il.append(new LLOAD(4));
637: il.append(new INVOKESPECIAL(constrIndex));
638: il.append(new ALOAD(6));
639: }
640:
641: else if (type.equals(Integer.TYPE.getName())) {
642: int x = cp.addClass("java.lang.Integer");
643: int constrIndex = cp.addMethodref("java.lang.Integer",
644: "<init>", "(I)V");
645:
646: il.append(new ISTORE(4));
647: il.append(new NEW(x));
648: il.append(new ASTORE(5));
649: il.append(new ALOAD(5));
650: il.append(new ILOAD(4));
651: il.append(new INVOKESPECIAL(constrIndex));
652: il.append(new ALOAD(5));
653: }
654:
655: else if (type.equals(Float.TYPE.getName())) {
656: int x = cp.addClass("java.lang.Float");
657: int constrIndex = cp.addMethodref("java.lang.Float",
658: "<init>", "(F)V");
659:
660: il.append(new FSTORE(4));
661: il.append(new NEW(x));
662: il.append(new ASTORE(5));
663: il.append(new ALOAD(5));
664: il.append(new FLOAD(4));
665: il.append(new INVOKESPECIAL(constrIndex));
666: il.append(new ALOAD(5));
667: }
668:
669: else if (type.equals(Double.TYPE.getName())) {
670: int x = cp.addClass("java.lang.Double");
671: int constrIndex = cp.addMethodref("java.lang.Double",
672: "<init>", "(D)V");
673:
674: il.append(new DSTORE(4));
675: il.append(new NEW(x));
676: il.append(new ASTORE(6));
677: il.append(new ALOAD(6));
678: il.append(new DLOAD(4));
679: il.append(new INVOKESPECIAL(constrIndex));
680: il.append(new ALOAD(6));
681: }
682:
683: else if (type.equals(Character.TYPE.getName())) {
684: int x = cp.addClass("java.lang.Character");
685: int constrIndex = cp.addMethodref("java.lang.Character",
686: "<init>", "(C)V");
687:
688: il.append(new ISTORE(4));
689: il.append(new NEW(x));
690: il.append(new ASTORE(5));
691: il.append(new ALOAD(5));
692: il.append(new ILOAD(4));
693: il.append(new INVOKESPECIAL(constrIndex));
694: il.append(new ALOAD(5));
695: }
696:
697: else if (type.equals(Byte.TYPE.getName())) {
698: int x = cp.addClass("java.lang.Byte");
699: int constrIndex = cp.addMethodref("java.lang.Byte",
700: "<init>", "(B)V");
701:
702: il.append(new ISTORE(4));
703: il.append(new NEW(x));
704: il.append(new ASTORE(5));
705: il.append(new ALOAD(5));
706: il.append(new ILOAD(4));
707: il.append(new INVOKESPECIAL(constrIndex));
708: il.append(new ALOAD(5));
709: }
710:
711: return il;
712: }
713:
714: /**
715: * Returns a subset of MBean's operations. Overloaded operations are not supported yet,
716: * so they're left out of the list and their invocations are delegated to the reflection
717: * based super class. <p>
718: *
719: * Overloaded operations that differ in their arg list length may be able to gain in
720: * performance if implemented directly with byte code. Overloaded operations with
721: * equal arg list length may not show much difference compared to ternary search tree
722: * based resolver.
723: */
724: protected static MethodEntry[] getOperations(MBeanInfo info) {
725: HashMap operationMap = new HashMap();
726: ArrayList overloadList = new ArrayList();
727: MBeanOperationInfo[] operations = info.getOperations();
728:
729: for (int i = 0; i < operations.length; ++i) {
730: String methodName = operations[i].getName();
731:
732: if (operationMap.containsKey(methodName))
733: overloadList.add(methodName);
734: else
735: operationMap.put(methodName, new MethodEntry(
736: operations[i]));
737: }
738:
739: // method overloading not supported yet
740: Iterator it = overloadList.iterator();
741: while (it.hasNext())
742: operationMap.remove(it.next());
743:
744: return (MethodEntry[]) operationMap.values().toArray(
745: new MethodEntry[0]);
746: }
747:
748: // Inner classes -------------------------------------------------
749: private static class MethodEntry extends MBeanOperationInfo {
750:
751: /** Not really serialized */
752: private static final long serialVersionUID = 1792631947840418314L;
753:
754: String methodDescriptor = null;
755: int nameIndexInCP = -1;
756: int methodIndexInCP = -1;
757:
758: public MethodEntry(MBeanOperationInfo info) {
759: super(info.getName(), info.getDescription(), info
760: .getSignature(), info.getReturnType(), info
761: .getImpact());
762:
763: this.methodDescriptor = getMethodDescriptor(info
764: .getSignature(), info.getReturnType());
765: }
766: }
767:
768: }
|