1 8 9 package mx4j.server; 10 11 import java.lang.reflect.Method ; 12 import java.security.AccessController ; 13 import java.security.PrivilegedActionException ; 14 import java.security.PrivilegedExceptionAction ; 15 import java.security.SecureClassLoader ; 16 import java.util.ArrayList ; 17 import java.util.Arrays ; 18 import java.util.List ; 19 20 import mx4j.log.Log; 21 import mx4j.log.Logger; 22 import org.apache.bcel.Constants; 23 import org.apache.bcel.generic.ARRAYLENGTH; 24 import org.apache.bcel.generic.ArrayType; 25 import org.apache.bcel.generic.BranchInstruction; 26 import org.apache.bcel.generic.ClassGen; 27 import org.apache.bcel.generic.InstructionConstants; 28 import org.apache.bcel.generic.InstructionFactory; 29 import org.apache.bcel.generic.InstructionHandle; 30 import org.apache.bcel.generic.InstructionList; 31 import org.apache.bcel.generic.LocalVariableGen; 32 import org.apache.bcel.generic.MethodGen; 33 import org.apache.bcel.generic.ObjectType; 34 import org.apache.bcel.generic.PUSH; 35 import org.apache.bcel.generic.ReferenceType; 36 import org.apache.bcel.generic.Type; 37 38 86 public class BCELMBeanInvoker extends CachingReflectionMBeanInvoker 87 { 88 private static final String LOGGER_CATEGORY = BCELMBeanInvoker.class.getName(); 89 113 protected BCELMBeanInvoker() 114 { 115 } 116 117 122 public synchronized static MBeanInvoker create(final MBeanMetaData metadata) 123 { 124 String parentName = BCELMBeanInvoker.class.getName(); 125 final String name = parentName + "Generated"; 126 ClassGen classGen = new ClassGen(name, parentName, "<generated-on-the-fly>", Constants.ACC_PUBLIC | Constants.ACC_FINAL | Constants.ACC_SUPER, null); 132 classGen.addEmptyConstructor(Constants.ACC_PUBLIC); 133 classGen.addMethod(createInvokeImpl(metadata, classGen, name)); 134 135 138 final byte[] bytes = classGen.getJavaClass().getBytes(); 139 140 try 141 { 142 return (BCELMBeanInvoker)AccessController.doPrivileged(new PrivilegedExceptionAction () 144 { 145 public Object run() throws Exception  146 { 147 Class cls = new BCELClassLoader(metadata.getClassLoader(), bytes).loadClass(name); 148 return cls.newInstance(); 149 } 150 }); 151 } 152 catch (Throwable x) 153 { 154 Logger logger = Log.getLogger(LOGGER_CATEGORY); 155 if (logger.isEnabledFor(Logger.INFO)) logger.info("Cannot create on-the-fly MBeanInvoker class, going with reflection MBeanInvoker", x); 156 return new CachingReflectionMBeanInvoker(); 157 } 158 } 159 160 private static org.apache.bcel.classfile.Method createInvokeImpl(MBeanMetaData metadata, ClassGen classGen, String clsName) 161 { 162 InstructionList implementation = new InstructionList(); 163 164 ObjectType metadataType = new ObjectType(MBeanMetaData.class.getName()); 165 Type[] signature = new Type[]{metadataType, Type.STRING, new ArrayType(Type.STRING, 1), new ArrayType(Type.OBJECT, 1)}; 166 167 MethodGen mthd = new MethodGen(Constants.ACC_PROTECTED, Type.OBJECT, signature, new String []{"metadata", "method", "params", "args"}, "invokeImpl", clsName, implementation, classGen.getConstantPool()); mthd.addException("java.lang.Throwable"); 177 178 InstructionFactory factory = new InstructionFactory(classGen); 180 181 Method [] methods = metadata.getMBeanInterface().getMethods(); 182 List tests = new ArrayList (); 183 List catches = new ArrayList (); 184 for (int i = 0; i < methods.length; ++i) 185 { 186 Method method = methods[i]; 187 catches.addAll(generateDirectInvokeBranch(classGen, mthd, implementation, factory, metadata.getMBeanInterface().getName(), method, tests)); 188 } 189 190 InstructionHandle invokeSuper = implementation.append(factory.createThis()); 192 for (int i = 0; i < tests.size(); ++i) 193 { 194 BranchInstruction branch = (BranchInstruction)tests.get(i); 195 branch.setTarget(invokeSuper); 196 } 197 tests.clear(); 198 for (int i = 0; i < catches.size(); ++i) 199 { 200 BranchInstruction branch = (BranchInstruction)catches.get(i); 201 branch.setTarget(invokeSuper); 202 } 203 catches.clear(); 204 205 implementation.append(factory.createLoad(metadataType, 1)); 212 implementation.append(factory.createLoad(Type.STRING, 2)); 213 implementation.append(factory.createLoad(new ArrayType(Type.STRING, 1), 3)); 214 implementation.append(factory.createLoad(new ArrayType(Type.OBJECT, 1), 4)); 215 implementation.append(factory.createInvoke(BCELMBeanInvoker.class.getName(), "invokeImpl", Type.OBJECT, signature, Constants.INVOKESPECIAL)); 216 implementation.append(factory.createReturn(Type.OBJECT)); 217 218 mthd.setMaxStack(); 219 220 org.apache.bcel.classfile.Method method = mthd.getMethod(); 221 222 implementation.dispose(); 224 225 return method; 226 } 227 228 private static List generateDirectInvokeBranch(ClassGen classGen, MethodGen methodGen, InstructionList implementation, InstructionFactory factory, String management, Method method, List tests) 229 { 230 ArrayList catches = new ArrayList (); 231 232 InstructionHandle startTest = implementation.append(factory.createLoad(Type.STRING, 2)); 237 238 for (int i = 0; i < tests.size(); ++i) 240 { 241 BranchInstruction branch = (BranchInstruction)tests.get(i); 242 branch.setTarget(startTest); 244 } 245 tests.clear(); 246 247 implementation.append(new PUSH(classGen.getConstantPool(), method.getName())); 248 implementation.append(factory.createInvoke(String .class.getName(), "equals", Type.BOOLEAN, new Type[]{Type.OBJECT}, Constants.INVOKEVIRTUAL)); 249 BranchInstruction test1 = factory.createBranchInstruction(Constants.IFEQ, null); 251 tests.add(test1); 252 implementation.append(test1); 253 254 implementation.append(factory.createLoad(new ArrayType(Type.OBJECT, 1), 4)); 255 implementation.append(new ARRAYLENGTH()); 256 implementation.append(new PUSH(classGen.getConstantPool(), method.getParameterTypes().length)); 257 BranchInstruction test2 = factory.createBranchInstruction(Constants.IF_ICMPNE, null); 260 tests.add(test2); 261 implementation.append(test2); 262 263 267 InstructionHandle tryStart = implementation.append(factory.createLoad(new ObjectType(MBeanMetaData.class.getName()), 1)); 271 implementation.append(factory.createInvoke(MBeanMetaData.class.getName(), "getMBean", Type.OBJECT, new Type[0], Constants.INVOKEVIRTUAL)); 272 implementation.append(factory.createCheckCast(new ObjectType(management))); 274 275 Class [] signature = method.getParameterTypes(); 277 Type[] invokeSignature = new Type[signature.length]; 278 for (int i = 0; i < signature.length; ++i) 279 { 280 Class param = signature[i]; 281 282 implementation.append(factory.createLoad(new ArrayType(Type.OBJECT, 1), 4)); 284 implementation.append(new PUSH(classGen.getConstantPool(), i)); 286 implementation.append(factory.createArrayLoad(Type.OBJECT)); 288 289 invokeSignature[i] = convertClassToType(param); 291 292 if (param.isPrimitive()) 293 { 294 replaceObjectWithPrimitive(param, implementation, factory); 296 } 297 else if (param.isArray()) 298 { 299 implementation.append(factory.createCheckCast((ReferenceType)invokeSignature[i])); 301 } 302 else 303 { 304 implementation.append(factory.createCheckCast((ReferenceType)invokeSignature[i])); 306 } 307 } 308 309 Class returnClass = method.getReturnType(); 310 Type returnType = convertClassToType(returnClass); 311 312 implementation.append(factory.createInvoke(management, method.getName(), returnType, invokeSignature, Constants.INVOKEINTERFACE)); 314 315 if (returnClass == Void.TYPE) 316 { 317 implementation.append(InstructionConstants.ACONST_NULL); 318 } 319 else if (returnClass.isArray()) 320 { 321 } 323 else if (returnClass.isPrimitive()) 324 { 325 replacePrimitiveWithObject(returnClass, methodGen, implementation, factory); 326 } 327 328 InstructionHandle tryEnd = implementation.append(factory.createReturn(Type.OBJECT)); 329 330 ObjectType exceptionTypeCCE = new ObjectType("java.lang.ClassCastException"); 334 LocalVariableGen x = methodGen.addLocalVariable("x", exceptionTypeCCE, null, null); 335 InstructionHandle handler = implementation.append(factory.createStore(exceptionTypeCCE, x.getIndex())); 336 x.setStart(handler); 337 x.setEnd(handler); 338 methodGen.addExceptionHandler(tryStart, tryEnd, handler, exceptionTypeCCE); 339 BranchInstruction skip = factory.createBranchInstruction(Constants.GOTO, null); 341 catches.add(skip); 342 implementation.append(skip); 343 344 ObjectType errorTypeIAE = new ObjectType("java.lang.IllegalAccessError"); 348 x = methodGen.addLocalVariable("x", errorTypeIAE, null, null); 349 handler = implementation.append(factory.createStore(errorTypeIAE, x.getIndex())); 350 x.setStart(handler); 351 x.setEnd(handler); 352 methodGen.addExceptionHandler(tryStart, tryEnd, handler, errorTypeIAE); 353 skip = factory.createBranchInstruction(Constants.GOTO, null); 355 catches.add(skip); 356 implementation.append(skip); 357 358 return catches; 359 } 360 361 private static Type convertClassToType(Class cls) 362 { 363 if (cls == void.class) return Type.VOID; 364 if (cls == boolean.class) return Type.BOOLEAN; 365 if (cls == byte.class) return Type.BYTE; 366 if (cls == char.class) return Type.CHAR; 367 if (cls == short.class) return Type.SHORT; 368 if (cls == int.class) return Type.INT; 369 if (cls == long.class) return Type.LONG; 370 if (cls == float.class) return Type.FLOAT; 371 if (cls == double.class) return Type.DOUBLE; 372 if (cls == Object .class) return Type.OBJECT; 373 if (cls == String .class) return Type.STRING; 374 if (cls.isArray()) 375 { 376 int dimensions = 0; 377 Class c = null; 378 while ((c = cls.getComponentType()) != null) 379 { 380 ++dimensions; 381 cls = c; 382 } 383 Type t = convertClassToType(cls); 384 return new ArrayType(t, dimensions); 385 } 386 return new ObjectType(cls.getName()); 387 } 388 389 private static void replaceObjectWithPrimitive(Class type, InstructionList implementation, InstructionFactory factory) 390 { 391 if (type == int.class) 393 { 394 implementation.append(factory.createCheckCast(new ObjectType(Integer .class.getName()))); 396 implementation.append(factory.createInvoke(Integer .class.getName(), "intValue", Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 397 } 398 else if (type == boolean.class) 399 { 400 implementation.append(factory.createCheckCast(new ObjectType(Boolean .class.getName()))); 402 implementation.append(factory.createInvoke(Boolean .class.getName(), "booleanValue", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 403 } 404 else if (type == long.class) 405 { 406 implementation.append(factory.createCheckCast(new ObjectType(Long .class.getName()))); 408 implementation.append(factory.createInvoke(Long .class.getName(), "longValue", Type.LONG, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 409 } 410 else if (type == byte.class) 411 { 412 implementation.append(factory.createCheckCast(new ObjectType(Byte .class.getName()))); 414 implementation.append(factory.createInvoke(Byte .class.getName(), "byteValue", Type.BYTE, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 415 } 416 else if (type == char.class) 417 { 418 implementation.append(factory.createCheckCast(new ObjectType(Character .class.getName()))); 420 implementation.append(factory.createInvoke(Character .class.getName(), "charValue", Type.CHAR, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 421 } 422 else if (type == short.class) 423 { 424 implementation.append(factory.createCheckCast(new ObjectType(Short .class.getName()))); 426 implementation.append(factory.createInvoke(Short .class.getName(), "shortValue", Type.SHORT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 427 } 428 else if (type == float.class) 429 { 430 implementation.append(factory.createCheckCast(new ObjectType(Float .class.getName()))); 432 implementation.append(factory.createInvoke(Float .class.getName(), "floatValue", Type.FLOAT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 433 } 434 else 435 { 436 implementation.append(factory.createCheckCast(new ObjectType(Double .class.getName()))); 438 implementation.append(factory.createInvoke(Double .class.getName(), "doubleValue", Type.DOUBLE, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 439 } 440 } 441 442 private static void replacePrimitiveWithObject(Class type, MethodGen methodGen, InstructionList implementation, InstructionFactory factory) 443 { 444 if (type == int.class) 446 { 447 LocalVariableGen i = methodGen.addLocalVariable("i", Type.INT, null, null); 449 i.setStart(implementation.append(factory.createStore(Type.INT, i.getIndex()))); 450 implementation.append(factory.createNew(new ObjectType(Integer .class.getName()))); 451 implementation.append(InstructionConstants.DUP); 452 implementation.append(factory.createLoad(Type.INT, i.getIndex())); 453 i.setEnd(implementation.append(factory.createInvoke(Integer .class.getName(), "<init>", Type.VOID, new Type[]{Type.INT}, Constants.INVOKESPECIAL))); 454 } 455 else if (type == boolean.class) 456 { 457 LocalVariableGen b = methodGen.addLocalVariable("b", Type.BOOLEAN, null, null); 459 b.setStart(implementation.append(factory.createStore(Type.BOOLEAN, b.getIndex()))); 460 implementation.append(factory.createNew(new ObjectType(Boolean .class.getName()))); 461 implementation.append(InstructionConstants.DUP); 462 implementation.append(factory.createLoad(Type.BOOLEAN, b.getIndex())); 463 b.setEnd(implementation.append(factory.createInvoke(Boolean .class.getName(), "<init>", Type.VOID, new Type[]{Type.BOOLEAN}, Constants.INVOKESPECIAL))); 464 } 465 else if (type == long.class) 466 { 467 LocalVariableGen l = methodGen.addLocalVariable("l", Type.LONG, null, null); 469 l.setStart(implementation.append(factory.createStore(Type.LONG, l.getIndex()))); 470 implementation.append(factory.createNew(new ObjectType(Long .class.getName()))); 471 implementation.append(InstructionConstants.DUP); 472 implementation.append(factory.createLoad(Type.LONG, l.getIndex())); 473 l.setEnd(implementation.append(factory.createInvoke(Long .class.getName(), "<init>", Type.VOID, new Type[]{Type.LONG}, Constants.INVOKESPECIAL))); 474 } 475 else if (type == byte.class) 476 { 477 LocalVariableGen b = methodGen.addLocalVariable("b", Type.BYTE, null, null); 479 b.setStart(implementation.append(factory.createStore(Type.BYTE, b.getIndex()))); 480 implementation.append(factory.createNew(new ObjectType(Byte .class.getName()))); 481 implementation.append(InstructionConstants.DUP); 482 implementation.append(factory.createLoad(Type.BYTE, b.getIndex())); 483 b.setEnd(implementation.append(factory.createInvoke(Byte .class.getName(), "<init>", Type.VOID, new Type[]{Type.BYTE}, Constants.INVOKESPECIAL))); 484 } 485 else if (type == char.class) 486 { 487 LocalVariableGen c = methodGen.addLocalVariable("c", Type.CHAR, null, null); 489 c.setStart(implementation.append(factory.createStore(Type.CHAR, c.getIndex()))); 490 implementation.append(factory.createNew(new ObjectType(Character .class.getName()))); 491 implementation.append(InstructionConstants.DUP); 492 implementation.append(factory.createLoad(Type.CHAR, c.getIndex())); 493 c.setEnd(implementation.append(factory.createInvoke(Character .class.getName(), "<init>", Type.VOID, new Type[]{Type.CHAR}, Constants.INVOKESPECIAL))); 494 } 495 else if (type == short.class) 496 { 497 LocalVariableGen s = methodGen.addLocalVariable("s", Type.SHORT, null, null); 499 s.setStart(implementation.append(factory.createStore(Type.SHORT, s.getIndex()))); 500 implementation.append(factory.createNew(new ObjectType(Short .class.getName()))); 501 implementation.append(InstructionConstants.DUP); 502 implementation.append(factory.createLoad(Type.SHORT, s.getIndex())); 503 s.setEnd(implementation.append(factory.createInvoke(Short .class.getName(), "<init>", Type.VOID, new Type[]{Type.SHORT}, Constants.INVOKESPECIAL))); 504 } 505 else if (type == float.class) 506 { 507 LocalVariableGen f = methodGen.addLocalVariable("f", Type.FLOAT, null, null); 509 f.setStart(implementation.append(factory.createStore(Type.FLOAT, f.getIndex()))); 510 implementation.append(factory.createNew(new ObjectType(Float .class.getName()))); 511 implementation.append(InstructionConstants.DUP); 512 implementation.append(factory.createLoad(Type.FLOAT, f.getIndex())); 513 f.setEnd(implementation.append(factory.createInvoke(Float .class.getName(), "<init>", Type.VOID, new Type[]{Type.FLOAT}, Constants.INVOKESPECIAL))); 514 } 515 else 516 { 517 LocalVariableGen d = methodGen.addLocalVariable("d", Type.DOUBLE, null, null); 519 d.setStart(implementation.append(factory.createStore(Type.DOUBLE, d.getIndex()))); 520 implementation.append(factory.createNew(new ObjectType(Double .class.getName()))); 521 implementation.append(InstructionConstants.DUP); 522 implementation.append(factory.createLoad(Type.DOUBLE, d.getIndex())); 523 d.setEnd(implementation.append(factory.createInvoke(Double .class.getName(), "<init>", Type.VOID, new Type[]{Type.DOUBLE}, Constants.INVOKESPECIAL))); 524 } 525 } 526 527 private Logger getLogger() 528 { 529 return Log.getLogger(LOGGER_CATEGORY); 530 } 531 532 protected Object invokeImpl(MBeanMetaData metadata, String method, String [] signature, Object [] args) throws Throwable  533 { 534 Logger logger = getLogger(); 535 if (logger.isEnabledFor(Logger.INFO)) 536 { 537 logger.info("BCEL invocation failed for method " + method + "" + Arrays.asList(signature) + ", using reflection"); 538 } 539 return super.invokeImpl(metadata, method, signature, args); 540 } 541 542 private static class BCELClassLoader extends SecureClassLoader  543 { 544 private byte[] m_bytes; 545 546 private BCELClassLoader(ClassLoader parent, byte[] bytecode) 547 { 548 super(parent); 549 m_bytes = bytecode; 550 } 551 552 protected Class findClass(final String name) throws ClassNotFoundException  553 { 554 try 555 { 556 return (Class )AccessController.doPrivileged(new PrivilegedExceptionAction () 557 { 558 public Object run() throws ClassNotFoundException  559 { 560 try 561 { 562 return defineClass(name, m_bytes, 0, m_bytes.length, BCELClassLoader.this.getClass().getProtectionDomain()); 563 } 564 catch (ClassFormatError x) 565 { 566 throw new ClassNotFoundException ("Class Format Error", x); 567 } 568 } 569 }, null); 570 } 571 catch (PrivilegedActionException x) 572 { 573 throw (ClassNotFoundException )x.getException(); 574 } 575 } 576 } 577 } 578 | Popular Tags |