001: /*
002: * Copyright (C) The MX4J Contributors.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the MX4J License version 1.0.
006: * See the terms of the MX4J License in the documentation provided with this software.
007: */
008:
009: package mx4j.server;
010:
011: import java.lang.reflect.Method;
012: import java.security.AccessController;
013: import java.security.PrivilegedActionException;
014: import java.security.PrivilegedExceptionAction;
015: import java.security.SecureClassLoader;
016: import java.util.ArrayList;
017: import java.util.Arrays;
018: import java.util.List;
019:
020: import mx4j.log.Log;
021: import mx4j.log.Logger;
022: import org.apache.bcel.Constants;
023: import org.apache.bcel.generic.ARRAYLENGTH;
024: import org.apache.bcel.generic.ArrayType;
025: import org.apache.bcel.generic.BranchInstruction;
026: import org.apache.bcel.generic.ClassGen;
027: import org.apache.bcel.generic.InstructionConstants;
028: import org.apache.bcel.generic.InstructionFactory;
029: import org.apache.bcel.generic.InstructionHandle;
030: import org.apache.bcel.generic.InstructionList;
031: import org.apache.bcel.generic.LocalVariableGen;
032: import org.apache.bcel.generic.MethodGen;
033: import org.apache.bcel.generic.ObjectType;
034: import org.apache.bcel.generic.PUSH;
035: import org.apache.bcel.generic.ReferenceType;
036: import org.apache.bcel.generic.Type;
037:
038: /**
039: * MBeanInvoker that generates on-the-fly implementations to call standard MBeans directly, instead of using reflection.
040: * <br />
041: * It uses the <a href="http://jakarta.apache.org/bcel">BCEL</a> to generate the required bytecode on-the-fly.
042: * The generated class is named "mx4j.server.BCELMBeanInvokerGenerated", and it's loaded into the JVM by a different
043: * classloader for each MBean. This classloader has the MBean classloader as parent. <br>
044: * Below is an example of the generated code; beware that the management interface and all parameter's classes must be
045: * public, otherwise an IllegalAccessError is thrown and the invocation falls back to use reflection (but with a significant
046: * overhead - throwing an exception is expensive).
047: * <pre>
048: * public interface ServiceMBean
049: * {
050: * public void start();
051: * public Collection getServices(ServiceSelector selector);
052: * }
053: * <p/>
054: * public class BCELMBeanInvokerGenerated extends BCELMBeanInvoker
055: * {
056: * protected Object invokeImpl(MBeanMetaData metadata, String method, String[] signature, Object[] args)
057: * throws Throwable
058: * {
059: * if (method.equals("start") && args.length == 0)
060: * {
061: * try
062: * {
063: * ((ServiceMBean)metadata.mbean).start();
064: * return null;
065: * }
066: * catch (ClassCastException x) {}
067: * catch (IllegalAccessError x) {}
068: * }
069: * else if (method.equals("getServices") && args.length == 1)
070: * {
071: * try
072: * {
073: * return ((ServiceMBean)metadata.mbean).getServices((ServiceSelector)args[0]);
074: * }
075: * catch (ClassCastException x) {}
076: * catch (IllegalAccessError x) {}
077: * }
078: * return super.invokeImpl(metadata, method, signature, args);
079: * }
080: * }
081: * </pre>
082: *
083: * @version $Revision: 1.14 $
084: */
085: public class BCELMBeanInvoker extends CachingReflectionMBeanInvoker {
086: private static final String LOGGER_CATEGORY = BCELMBeanInvoker.class
087: .getName();
088:
089: /*
090: public static void main(String[] args) throws Exception
091: {
092: MBeanMetaData metadata = new MBeanMetaData();
093: metadata.classloader = ClassLoader.getSystemClassLoader();
094: metadata.management = Object.class;
095: Object generated = create(metadata);
096: System.out.println("generated = " + generated);
097: }
098:
099: private static void dump(ClassGen classGen)
100: {
101: try
102: {
103: java.io.FileOutputStream fos = new java.io.FileOutputStream(new java.io.File("C:\\Simon\\OpenSource\\mx4j\\mx4j\\classes\\core\\mx4j\\server\\BCELMBeanInvokerGenerated.class"));
104: classGen.getJavaClass().dump(fos);
105: fos.close();
106: }
107: catch (java.io.IOException x)
108: {
109: x.printStackTrace();
110: }
111: }
112: */
113: protected BCELMBeanInvoker() {
114: }
115:
116: /**
117: * Creates a new MBeanInvoker created on-the-fly by using BCEL.
118: * It must be synchronized since BCEL is not thread safe, and uses static variables
119: * (refer to org.apache.bcel.generic.Type.getArgumentTypes(...) for further details)
120: */
121: public synchronized static MBeanInvoker create(
122: final MBeanMetaData metadata) {
123: String parentName = BCELMBeanInvoker.class.getName();
124: final String name = parentName + "Generated";
125: ClassGen classGen = new ClassGen(name, // Qualified class name
126: parentName, // Qualified superclass name
127: "<generated-on-the-fly>", // File name
128: Constants.ACC_PUBLIC | Constants.ACC_FINAL
129: | Constants.ACC_SUPER, // Modifiers
130: null); // Implemented interfaces
131:
132: classGen.addEmptyConstructor(Constants.ACC_PUBLIC);
133: classGen.addMethod(createInvokeImpl(metadata, classGen, name));
134:
135: // For debug purposes only
136: // dump(classGen);
137:
138: final byte[] bytes = classGen.getJavaClass().getBytes();
139:
140: try {
141: // Must shield clients, since creating a new classloader requires a permission
142: return (BCELMBeanInvoker) AccessController
143: .doPrivileged(new PrivilegedExceptionAction() {
144: public Object run() throws Exception {
145: Class cls = new BCELClassLoader(metadata
146: .getClassLoader(), bytes)
147: .loadClass(name);
148: return cls.newInstance();
149: }
150: });
151: } catch (Throwable x) {
152: Logger logger = Log.getLogger(LOGGER_CATEGORY);
153: if (logger.isEnabledFor(Logger.INFO))
154: logger
155: .info(
156: "Cannot create on-the-fly MBeanInvoker class, going with reflection MBeanInvoker",
157: x);
158: return new CachingReflectionMBeanInvoker();
159: }
160: }
161:
162: private static org.apache.bcel.classfile.Method createInvokeImpl(
163: MBeanMetaData metadata, ClassGen classGen, String clsName) {
164: InstructionList implementation = new InstructionList();
165:
166: ObjectType metadataType = new ObjectType(MBeanMetaData.class
167: .getName());
168: Type[] signature = new Type[] { metadataType, Type.STRING,
169: new ArrayType(Type.STRING, 1),
170: new ArrayType(Type.OBJECT, 1) };
171:
172: // Method definition
173: MethodGen mthd = new MethodGen(
174: Constants.ACC_PROTECTED, // Modifiers
175: Type.OBJECT, // Return type
176: signature, // Signature
177: new String[] { "metadata", "method", "params", "args" }, // Parameter names
178: "invokeImpl", // Method name
179: clsName, // Class name
180: implementation, // Implementation
181: classGen.getConstantPool()); // Pool
182: mthd.addException("java.lang.Throwable");
183:
184: // Now I should create the implementation
185: InstructionFactory factory = new InstructionFactory(classGen);
186:
187: Method[] methods = metadata.getMBeanInterface().getMethods();
188: List tests = new ArrayList();
189: List catches = new ArrayList();
190: for (int i = 0; i < methods.length; ++i) {
191: Method method = methods[i];
192: catches.addAll(generateDirectInvokeBranch(classGen, mthd,
193: implementation, factory, metadata
194: .getMBeanInterface().getName(), method,
195: tests));
196: }
197:
198: // To close the last branch, I must jump to super.invokeImpl(), so I need its first instruction here
199: InstructionHandle invokeSuper = implementation.append(factory
200: .createThis());
201: for (int i = 0; i < tests.size(); ++i) {
202: BranchInstruction branch = (BranchInstruction) tests.get(i);
203: branch.setTarget(invokeSuper);
204: }
205: tests.clear();
206: for (int i = 0; i < catches.size(); ++i) {
207: BranchInstruction branch = (BranchInstruction) catches
208: .get(i);
209: branch.setTarget(invokeSuper);
210: }
211: catches.clear();
212:
213: //
214: // return super.invokeImpl(metadata, method, params, args);
215: //
216: // Again, it's invokeImpl(super, args) instead of super.invokeImpl(args)
217: // Use 'this' as first argument, and invokespecial instead of invokevirtual to call super
218: // 'this' is created above, to close the last branch
219: implementation.append(factory.createLoad(metadataType, 1));
220: implementation.append(factory.createLoad(Type.STRING, 2));
221: implementation.append(factory.createLoad(new ArrayType(
222: Type.STRING, 1), 3));
223: implementation.append(factory.createLoad(new ArrayType(
224: Type.OBJECT, 1), 4));
225: implementation.append(factory.createInvoke(
226: BCELMBeanInvoker.class.getName(), "invokeImpl",
227: Type.OBJECT, signature, Constants.INVOKESPECIAL));
228: implementation.append(factory.createReturn(Type.OBJECT));
229:
230: mthd.setMaxStack();
231:
232: org.apache.bcel.classfile.Method method = mthd.getMethod();
233:
234: // Reuse instruction handles
235: implementation.dispose();
236:
237: return method;
238: }
239:
240: private static List generateDirectInvokeBranch(ClassGen classGen,
241: MethodGen methodGen, InstructionList implementation,
242: InstructionFactory factory, String management,
243: Method method, List tests) {
244: ArrayList catches = new ArrayList();
245:
246: //
247: // if (method.equals("<operation>") && args.length == <num>)
248: //
249: // The first instruction, will be where I should go if the previous branch fails
250: InstructionHandle startTest = implementation.append(factory
251: .createLoad(Type.STRING, 2));
252:
253: // The first time it will be empty, the second time will be the first time's uninitialized jump instructions
254: for (int i = 0; i < tests.size(); ++i) {
255: BranchInstruction branch = (BranchInstruction) tests.get(i);
256: // Initialize previous jump instruction to jump to the next branch
257: branch.setTarget(startTest);
258: }
259: tests.clear();
260:
261: implementation.append(new PUSH(classGen.getConstantPool(),
262: method.getName()));
263: implementation.append(factory.createInvoke(String.class
264: .getName(), "equals", Type.BOOLEAN,
265: new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
266: // IFEQ compares the stack with 0, which means "if the previous comparison is false, ..."
267: BranchInstruction test1 = factory.createBranchInstruction(
268: Constants.IFEQ, null);
269: tests.add(test1);
270: implementation.append(test1);
271:
272: implementation.append(factory.createLoad(new ArrayType(
273: Type.OBJECT, 1), 4));
274: implementation.append(new ARRAYLENGTH());
275: implementation.append(new PUSH(classGen.getConstantPool(),
276: method.getParameterTypes().length));
277: // Here I should test if args.length == <num>, if not equal then go to the next branch
278: // Create branch instructions with no offset, since it cannot be handled now, see above
279: BranchInstruction test2 = factory.createBranchInstruction(
280: Constants.IF_ICMPNE, null);
281: tests.add(test2);
282: implementation.append(test2);
283:
284: // Here I am on the right method, unless someone created 2 methods with same names and same number of
285: // parameters but of different type. In this last case if we're lucky it's the right method and we go
286: // via direct call, otherwise we will have a class cast exception and go via reflection
287:
288: // Cast and invoke
289: // Put the metadata on the stack, to access its 'mbean' field, that will be put on the stack
290: // It's also the start of the try block
291: InstructionHandle tryStart = implementation.append(factory
292: .createLoad(new ObjectType(MBeanMetaData.class
293: .getName()), 1));
294: implementation.append(factory.createInvoke(MBeanMetaData.class
295: .getName(), "getMBean", Type.OBJECT, new Type[0],
296: Constants.INVOKEVIRTUAL));
297: // Cast the 'mbean' field to the proper type, the stack will contain the casted mbean
298: implementation.append(factory.createCheckCast(new ObjectType(
299: management)));
300:
301: // Now add all the arguments to the stack
302: Class[] signature = method.getParameterTypes();
303: Type[] invokeSignature = new Type[signature.length];
304: for (int i = 0; i < signature.length; ++i) {
305: Class param = signature[i];
306:
307: // Load all args on the stack
308: implementation.append(factory.createLoad(new ArrayType(
309: Type.OBJECT, 1), 4));
310: // I want index 'i'
311: implementation.append(new PUSH(classGen.getConstantPool(),
312: i));
313: // Now on the stack there is args[i]
314: implementation.append(factory.createArrayLoad(Type.OBJECT));
315:
316: // Save the signature for the invocation
317: invokeSignature[i] = convertClassToType(param);
318:
319: if (param.isPrimitive()) {
320: // On the stack I have the wrapper object, I have to convert them to primitive
321: replaceObjectWithPrimitive(param, implementation,
322: factory);
323: } else if (param.isArray()) {
324: // Cast args[i] to the proper class
325: implementation
326: .append(factory
327: .createCheckCast((ReferenceType) invokeSignature[i]));
328: } else {
329: // Cast args[i] to the proper class
330: implementation
331: .append(factory
332: .createCheckCast((ReferenceType) invokeSignature[i]));
333: }
334: }
335:
336: Class returnClass = method.getReturnType();
337: Type returnType = convertClassToType(returnClass);
338:
339: // On the stack we now have the casted mbean and all the casted arguments, invoke
340: implementation.append(factory.createInvoke(management, method
341: .getName(), returnType, invokeSignature,
342: Constants.INVOKEINTERFACE));
343:
344: if (returnClass == Void.TYPE) {
345: implementation.append(InstructionConstants.ACONST_NULL);
346: } else if (returnClass.isArray()) {
347: // Thanks to the fact that we can assign any array to Object, we do nothing here
348: } else if (returnClass.isPrimitive()) {
349: replacePrimitiveWithObject(returnClass, methodGen,
350: implementation, factory);
351: }
352:
353: InstructionHandle tryEnd = implementation.append(factory
354: .createReturn(Type.OBJECT));
355:
356: // In case of class cast exception, eat the exception and call super (hence using reflection)
357: // catch (ClassCastException x) {/* do nothing */}
358: // On the stack there is the exception, we assign it to local variable 'x'
359: ObjectType exceptionTypeCCE = new ObjectType(
360: "java.lang.ClassCastException");
361: LocalVariableGen x = methodGen.addLocalVariable("x",
362: exceptionTypeCCE, null, null);
363: InstructionHandle handler = implementation.append(factory
364: .createStore(exceptionTypeCCE, x.getIndex()));
365: x.setStart(handler);
366: x.setEnd(handler);
367: methodGen.addExceptionHandler(tryStart, tryEnd, handler,
368: exceptionTypeCCE);
369: // This catch block is followed by another one, and I don't exit with a throw or a return
370: BranchInstruction skip = factory.createBranchInstruction(
371: Constants.GOTO, null);
372: catches.add(skip);
373: implementation.append(skip);
374:
375: // An IllegalAccessError is thrown if the MBean interface or a parameter class is not public
376: // We eat it and fall back to call super (hence using reflection)
377: // catch (IllegalAccessError x) {/* do nothing */}
378: ObjectType errorTypeIAE = new ObjectType(
379: "java.lang.IllegalAccessError");
380: x = methodGen.addLocalVariable("x", errorTypeIAE, null, null);
381: handler = implementation.append(factory.createStore(
382: errorTypeIAE, x.getIndex()));
383: x.setStart(handler);
384: x.setEnd(handler);
385: methodGen.addExceptionHandler(tryStart, tryEnd, handler,
386: errorTypeIAE);
387: // This catch block is followed by another one, and I don't exit with a throw or a return,
388: skip = factory.createBranchInstruction(Constants.GOTO, null);
389: catches.add(skip);
390: implementation.append(skip);
391:
392: return catches;
393: }
394:
395: private static Type convertClassToType(Class cls) {
396: if (cls == void.class)
397: return Type.VOID;
398: if (cls == boolean.class)
399: return Type.BOOLEAN;
400: if (cls == byte.class)
401: return Type.BYTE;
402: if (cls == char.class)
403: return Type.CHAR;
404: if (cls == short.class)
405: return Type.SHORT;
406: if (cls == int.class)
407: return Type.INT;
408: if (cls == long.class)
409: return Type.LONG;
410: if (cls == float.class)
411: return Type.FLOAT;
412: if (cls == double.class)
413: return Type.DOUBLE;
414: if (cls == Object.class)
415: return Type.OBJECT;
416: if (cls == String.class)
417: return Type.STRING;
418: if (cls.isArray()) {
419: int dimensions = 0;
420: Class c = null;
421: while ((c = cls.getComponentType()) != null) {
422: ++dimensions;
423: cls = c;
424: }
425: Type t = convertClassToType(cls);
426: return new ArrayType(t, dimensions);
427: }
428: return new ObjectType(cls.getName());
429: }
430:
431: private static void replaceObjectWithPrimitive(Class type,
432: InstructionList implementation, InstructionFactory factory) {
433: // Put as first the most common ones
434: if (type == int.class) {
435: // Cast the operand in the stack and get the value
436: implementation.append(factory
437: .createCheckCast(new ObjectType(Integer.class
438: .getName())));
439: implementation.append(factory.createInvoke(Integer.class
440: .getName(), "intValue", Type.INT, Type.NO_ARGS,
441: Constants.INVOKEVIRTUAL));
442: } else if (type == boolean.class) {
443: // Cast the operand in the stack and get the value
444: implementation.append(factory
445: .createCheckCast(new ObjectType(Boolean.class
446: .getName())));
447: implementation.append(factory.createInvoke(Boolean.class
448: .getName(), "booleanValue", Type.BOOLEAN,
449: Type.NO_ARGS, Constants.INVOKEVIRTUAL));
450: } else if (type == long.class) {
451: // Cast the operand in the stack and get the value
452: implementation.append(factory
453: .createCheckCast(new ObjectType(Long.class
454: .getName())));
455: implementation.append(factory.createInvoke(Long.class
456: .getName(), "longValue", Type.LONG, Type.NO_ARGS,
457: Constants.INVOKEVIRTUAL));
458: } else if (type == byte.class) {
459: // Cast the operand in the stack and get the value
460: implementation.append(factory
461: .createCheckCast(new ObjectType(Byte.class
462: .getName())));
463: implementation.append(factory.createInvoke(Byte.class
464: .getName(), "byteValue", Type.BYTE, Type.NO_ARGS,
465: Constants.INVOKEVIRTUAL));
466: } else if (type == char.class) {
467: // Cast the operand in the stack and get the value
468: implementation.append(factory
469: .createCheckCast(new ObjectType(Character.class
470: .getName())));
471: implementation.append(factory.createInvoke(Character.class
472: .getName(), "charValue", Type.CHAR, Type.NO_ARGS,
473: Constants.INVOKEVIRTUAL));
474: } else if (type == short.class) {
475: // Cast the operand in the stack and get the value
476: implementation.append(factory
477: .createCheckCast(new ObjectType(Short.class
478: .getName())));
479: implementation.append(factory.createInvoke(Short.class
480: .getName(), "shortValue", Type.SHORT, Type.NO_ARGS,
481: Constants.INVOKEVIRTUAL));
482: } else if (type == float.class) {
483: // Cast the operand in the stack and get the value
484: implementation.append(factory
485: .createCheckCast(new ObjectType(Float.class
486: .getName())));
487: implementation.append(factory.createInvoke(Float.class
488: .getName(), "floatValue", Type.FLOAT, Type.NO_ARGS,
489: Constants.INVOKEVIRTUAL));
490: } else {
491: // Cast the operand in the stack and get the value
492: implementation.append(factory
493: .createCheckCast(new ObjectType(Double.class
494: .getName())));
495: implementation.append(factory.createInvoke(Double.class
496: .getName(), "doubleValue", Type.DOUBLE,
497: Type.NO_ARGS, Constants.INVOKEVIRTUAL));
498: }
499: }
500:
501: private static void replacePrimitiveWithObject(Class type,
502: MethodGen methodGen, InstructionList implementation,
503: InstructionFactory factory) {
504: // Put as first the most common ones
505: if (type == int.class) {
506: // Create a new instance of the wrapper
507: LocalVariableGen i = methodGen.addLocalVariable("i",
508: Type.INT, null, null);
509: i.setStart(implementation.append(factory.createStore(
510: Type.INT, i.getIndex())));
511: implementation.append(factory.createNew(new ObjectType(
512: Integer.class.getName())));
513: implementation.append(InstructionConstants.DUP);
514: implementation.append(factory.createLoad(Type.INT, i
515: .getIndex()));
516: i.setEnd(implementation.append(factory.createInvoke(
517: Integer.class.getName(), "<init>", Type.VOID,
518: new Type[] { Type.INT }, Constants.INVOKESPECIAL)));
519: } else if (type == boolean.class) {
520: // Create a new instance of the wrapper
521: LocalVariableGen b = methodGen.addLocalVariable("b",
522: Type.BOOLEAN, null, null);
523: b.setStart(implementation.append(factory.createStore(
524: Type.BOOLEAN, b.getIndex())));
525: implementation.append(factory.createNew(new ObjectType(
526: Boolean.class.getName())));
527: implementation.append(InstructionConstants.DUP);
528: implementation.append(factory.createLoad(Type.BOOLEAN, b
529: .getIndex()));
530: b.setEnd(implementation.append(factory.createInvoke(
531: Boolean.class.getName(), "<init>", Type.VOID,
532: new Type[] { Type.BOOLEAN },
533: Constants.INVOKESPECIAL)));
534: } else if (type == long.class) {
535: // Create a new instance of the wrapper
536: LocalVariableGen l = methodGen.addLocalVariable("l",
537: Type.LONG, null, null);
538: l.setStart(implementation.append(factory.createStore(
539: Type.LONG, l.getIndex())));
540: implementation.append(factory.createNew(new ObjectType(
541: Long.class.getName())));
542: implementation.append(InstructionConstants.DUP);
543: implementation.append(factory.createLoad(Type.LONG, l
544: .getIndex()));
545: l
546: .setEnd(implementation.append(factory.createInvoke(
547: Long.class.getName(), "<init>", Type.VOID,
548: new Type[] { Type.LONG },
549: Constants.INVOKESPECIAL)));
550: } else if (type == byte.class) {
551: // Create a new instance of the wrapper
552: LocalVariableGen b = methodGen.addLocalVariable("b",
553: Type.BYTE, null, null);
554: b.setStart(implementation.append(factory.createStore(
555: Type.BYTE, b.getIndex())));
556: implementation.append(factory.createNew(new ObjectType(
557: Byte.class.getName())));
558: implementation.append(InstructionConstants.DUP);
559: implementation.append(factory.createLoad(Type.BYTE, b
560: .getIndex()));
561: b
562: .setEnd(implementation.append(factory.createInvoke(
563: Byte.class.getName(), "<init>", Type.VOID,
564: new Type[] { Type.BYTE },
565: Constants.INVOKESPECIAL)));
566: } else if (type == char.class) {
567: // Create a new instance of the wrapper
568: LocalVariableGen c = methodGen.addLocalVariable("c",
569: Type.CHAR, null, null);
570: c.setStart(implementation.append(factory.createStore(
571: Type.CHAR, c.getIndex())));
572: implementation.append(factory.createNew(new ObjectType(
573: Character.class.getName())));
574: implementation.append(InstructionConstants.DUP);
575: implementation.append(factory.createLoad(Type.CHAR, c
576: .getIndex()));
577: c
578: .setEnd(implementation.append(factory.createInvoke(
579: Character.class.getName(), "<init>",
580: Type.VOID, new Type[] { Type.CHAR },
581: Constants.INVOKESPECIAL)));
582: } else if (type == short.class) {
583: // Create a new instance of the wrapper
584: LocalVariableGen s = methodGen.addLocalVariable("s",
585: Type.SHORT, null, null);
586: s.setStart(implementation.append(factory.createStore(
587: Type.SHORT, s.getIndex())));
588: implementation.append(factory.createNew(new ObjectType(
589: Short.class.getName())));
590: implementation.append(InstructionConstants.DUP);
591: implementation.append(factory.createLoad(Type.SHORT, s
592: .getIndex()));
593: s.setEnd(implementation
594: .append(factory.createInvoke(Short.class.getName(),
595: "<init>", Type.VOID,
596: new Type[] { Type.SHORT },
597: Constants.INVOKESPECIAL)));
598: } else if (type == float.class) {
599: // Create a new instance of the wrapper
600: LocalVariableGen f = methodGen.addLocalVariable("f",
601: Type.FLOAT, null, null);
602: f.setStart(implementation.append(factory.createStore(
603: Type.FLOAT, f.getIndex())));
604: implementation.append(factory.createNew(new ObjectType(
605: Float.class.getName())));
606: implementation.append(InstructionConstants.DUP);
607: implementation.append(factory.createLoad(Type.FLOAT, f
608: .getIndex()));
609: f.setEnd(implementation
610: .append(factory.createInvoke(Float.class.getName(),
611: "<init>", Type.VOID,
612: new Type[] { Type.FLOAT },
613: Constants.INVOKESPECIAL)));
614: } else {
615: // Create a new instance of the wrapper
616: LocalVariableGen d = methodGen.addLocalVariable("d",
617: Type.DOUBLE, null, null);
618: d.setStart(implementation.append(factory.createStore(
619: Type.DOUBLE, d.getIndex())));
620: implementation.append(factory.createNew(new ObjectType(
621: Double.class.getName())));
622: implementation.append(InstructionConstants.DUP);
623: implementation.append(factory.createLoad(Type.DOUBLE, d
624: .getIndex()));
625: d.setEnd(implementation.append(factory
626: .createInvoke(Double.class.getName(), "<init>",
627: Type.VOID, new Type[] { Type.DOUBLE },
628: Constants.INVOKESPECIAL)));
629: }
630: }
631:
632: private Logger getLogger() {
633: return Log.getLogger(LOGGER_CATEGORY);
634: }
635:
636: protected Object invokeImpl(MBeanMetaData metadata, String method,
637: String[] signature, Object[] args) throws Throwable {
638: Logger logger = getLogger();
639: if (logger.isEnabledFor(Logger.INFO)) {
640: logger.info("BCEL invocation failed for method " + method
641: + "" + Arrays.asList(signature)
642: + ", using reflection");
643: }
644: return super .invokeImpl(metadata, method, signature, args);
645: }
646:
647: private static class BCELClassLoader extends SecureClassLoader {
648: private byte[] m_bytes;
649:
650: private BCELClassLoader(ClassLoader parent, byte[] bytecode) {
651: super (parent);
652: m_bytes = bytecode;
653: }
654:
655: protected Class findClass(final String name)
656: throws ClassNotFoundException {
657: try {
658: return (Class) AccessController.doPrivileged(
659: new PrivilegedExceptionAction() {
660: public Object run()
661: throws ClassNotFoundException {
662: try {
663: return defineClass(
664: name,
665: m_bytes,
666: 0,
667: m_bytes.length,
668: BCELClassLoader.this
669: .getClass()
670: .getProtectionDomain());
671: } catch (ClassFormatError x) {
672: throw new ClassNotFoundException(
673: "Class Format Error", x);
674: }
675: }
676: }, null);
677: } catch (PrivilegedActionException x) {
678: throw (ClassNotFoundException) x.getException();
679: }
680: }
681: }
682: }
|