1 22 package org.jboss.mx.capability; 23 24 import org.apache.bcel.Constants; 25 import org.apache.bcel.classfile.JavaClass; 26 import org.apache.bcel.generic.*; 27 import org.jboss.mx.metadata.AttributeOperationResolver; 28 import org.jboss.mx.server.ServerConstants; 29 30 import javax.management.MBeanException ; 31 import javax.management.MBeanInfo ; 32 import javax.management.MBeanOperationInfo ; 33 import javax.management.MBeanParameterInfo ; 34 import javax.management.ReflectionException ; 35 import java.io.BufferedOutputStream ; 36 import java.io.ByteArrayOutputStream ; 37 import java.lang.reflect.Constructor ; 38 import java.util.ArrayList ; 39 import java.util.HashMap ; 40 import java.util.Iterator ; 41 42 43 59 public class OptimizedMBeanDispatcher implements ServerConstants 60 { 61 final static Class SUPER_CLASS = ReflectedMBeanDispatcher.class; 63 64 65 public static ReflectedMBeanDispatcher create(MBeanInfo info, Object resource) 67 { 68 try 69 { 70 String className = resource.getClass().getName().replace('.', '_') + "_Dispatcher"; 72 String superClass = SUPER_CLASS.getName(); 73 String fileName = className + ".class"; 74 int modifiers = Constants.ACC_PUBLIC; 75 String [] interfaces = new String [0]; 76 77 ClassGen clazz = new ClassGen(className, superClass, fileName, modifiers, interfaces); 78 ConstantPoolGen cp = clazz.getConstantPool(); 79 80 clazz.addMethod(createConstructor(cp, className).getMethod()); 81 clazz.addMethod(createInvoke(cp, info, className, resource.getClass().getName()).getMethod()); 82 clazz.update(); 83 84 JavaClass c = clazz.getJavaClass(); 85 86 ByteArrayOutputStream baos = new ByteArrayOutputStream (2000); 87 BufferedOutputStream bos = new BufferedOutputStream (baos); 88 c.dump(bos); 89 90 ClassLoader ocl = new DispatchClassLoader(resource.getClass().getClassLoader(), className, baos.toByteArray()); 93 94 Class dispatcherClass = ocl.loadClass(className); 95 Constructor constr = dispatcherClass.getConstructor( 96 new Class [] { MBeanInfo .class, AttributeOperationResolver.class, Object .class } 97 ); 98 99 Object o = constr.newInstance(new Object [] { info, new AttributeOperationResolver(info), resource }); 100 101 return (ReflectedMBeanDispatcher)o; 102 } 103 catch (Exception e) 104 { 105 e.printStackTrace(); 106 throw new Error (); 107 } 108 } 109 110 147 public static String getMethodDescriptor(MBeanParameterInfo [] signature, String returnType) 148 { 149 150 StringBuffer sign = new StringBuffer (256); 151 sign.append("("); 152 153 for (int i = 0; i < signature.length; ++i) 154 sign.append(getDescriptorForType(signature[i].getName())); 155 156 sign.append(")" + getDescriptorForType(returnType)); 157 158 return sign.toString(); 159 } 160 161 174 public static String getDescriptorForType(String name) 175 { 176 if (name.equals(Byte.TYPE.getName())) return "B"; 177 else if (name.equals(Character.TYPE.getName())) return "C"; 178 else if (name.equals(Double.TYPE.getName())) return "D"; 179 else if (name.equals(Float.TYPE.getName())) return "F"; 180 else if (name.equals(Integer.TYPE.getName())) return "I"; 181 else if (name.equals(Long.TYPE.getName())) return "J"; 182 else if (name.equals(Short.TYPE.getName())) return "S"; 183 else if (name.equals(Boolean.TYPE.getName())) return "Z"; 184 else if (name.equals(Void.TYPE.getName())) return "V"; 185 else if (name.startsWith("[")) return name.replace('.', '/'); 186 else return "L" + name.replace('.', '/') + ";"; 187 } 188 189 197 public static boolean isPrimitive(String name) 198 { 199 if (name.equals(Byte.TYPE.getName()) || 200 name.equals(Character.TYPE.getName()) || 201 name.equals(Double.TYPE.getName()) || 202 name.equals(Float.TYPE.getName()) || 203 name.equals(Integer.TYPE.getName()) || 204 name.equals(Long.TYPE.getName()) || 205 name.equals(Short.TYPE.getName()) || 206 name.equals(Boolean.TYPE.getName())) 207 208 return true; 209 210 return false; 211 } 212 213 214 215 217 224 protected static MethodGen createConstructor(ConstantPoolGen cp, String className) 225 { 226 InstructionList constrInstructions = new InstructionList(); 227 228 int constrRefIndex = cp.addMethodref( 229 SUPER_CLASS.getName(), 230 "<init>", 231 "(" + getDescriptorForType(MBeanInfo .class.getName()) 232 + getDescriptorForType(AttributeOperationResolver.class.getName()) 233 + getDescriptorForType(Object .class.getName()) 234 + ")V" 235 ); 236 237 constrInstructions.append(new ALOAD(0)); constrInstructions.append(new ALOAD(1)); constrInstructions.append(new ALOAD(2)); constrInstructions.append(new ALOAD(3)); constrInstructions.append(new INVOKESPECIAL(constrRefIndex)); constrInstructions.append(new RETURN()); 244 MethodGen constrMethod = new MethodGen( 245 Constants.ACC_PUBLIC, 246 Type.VOID, 247 new Type[] { 248 new ObjectType(MBeanInfo .class.getName()), 249 new ObjectType(AttributeOperationResolver.class.getName()), 250 new ObjectType(Object .class.getName()) }, 251 new String [] { "info", "resolver", "resource" }, 252 "<init>", 253 className, constrInstructions, cp 254 ); 255 constrMethod.setMaxStack(4); 256 257 return constrMethod; 258 } 259 260 296 protected static MethodGen createInvoke(ConstantPoolGen cp, MBeanInfo info, String className, String resourceClassName) 297 { 298 InstructionList invokeInstructions = new InstructionList(); 299 MethodEntry[] operations = getOperations(info); 300 301 for (int i = 0; i < operations.length; ++i) { 303 operations[i].nameIndexInCP = cp.addString(operations[i].getName()); 304 operations[i].methodIndexInCP = cp.addMethodref( 305 resourceClassName, 306 operations[i].getName(), 307 operations[i].methodDescriptor 308 ); 309 } 310 311 312 int invokeIndex = cp.addMethodref( 313 SUPER_CLASS.getName(), 314 "invoke", 315 "(" + getDescriptorForType(String .class.getName()) 316 + getDescriptorForType(Object [].class.getName()) 317 + getDescriptorForType(String [].class.getName()) 318 + 319 ")" + getDescriptorForType(Object .class.getName()) 320 ); 321 322 int getResourceObjectIndex = cp.addMethodref( 323 SUPER_CLASS.getName(), 324 "getResourceObject", 325 "()Ljava/lang/Object;" 326 ); 327 328 int strEqualsIndex = cp.addMethodref( 329 String .class.getName(), 330 "equals", 331 "(Ljava/lang/Object;)Z" 332 ); 333 334 InstructionHandle beginTryBlock = null; 335 InstructionHandle endTryBlock = null; 336 337 IFNULL ifOperationEqualsNull = new IFNULL(null); 338 IFEQ operationElseIfBranch = null; 339 340 if (operations.length > 0) 341 { 342 invokeInstructions.append(new ALOAD(1)); 347 beginTryBlock = 348 invokeInstructions.append(ifOperationEqualsNull); 350 for (int i = 0; i < operations.length; ++i) 351 { 352 InstructionHandle jumpToNextElse = 356 invokeInstructions.append(new ALOAD(1)); invokeInstructions.append(new LDC(operations[i].nameIndexInCP)); invokeInstructions.append(new INVOKEVIRTUAL(strEqualsIndex)); 360 if (operationElseIfBranch != null) 362 operationElseIfBranch.setTarget(jumpToNextElse); 363 364 operationElseIfBranch = new IFEQ(null); 365 invokeInstructions.append(operationElseIfBranch); 367 invokeInstructions.append(new ALOAD(0)); invokeInstructions.append(new INVOKEVIRTUAL(getResourceObjectIndex)); 370 int x = cp.addClass(resourceClassName); 371 invokeInstructions.append(new CHECKCAST(x)); 373 if (operations[i].getSignature().length > 0) 375 { 376 377 for (int arrayIndex = 0; arrayIndex < operations[i].getSignature().length; ++arrayIndex) 378 { 379 invokeInstructions.append(new ALOAD(2)); invokeInstructions.append(new PUSH(cp, arrayIndex)); invokeInstructions.append(new AALOAD()); 383 String type = operations[i].getSignature() [arrayIndex].getName(); 386 387 if (isPrimitive(type)) 388 invokeInstructions.append(convertObjectToPrimitive(cp, type)); 390 else 391 { 392 x = cp.addClass(type); 393 invokeInstructions.append(new CHECKCAST(x)); } 395 } 396 } 397 398 x = operations[i].methodIndexInCP; 402 invokeInstructions.append(new INVOKEVIRTUAL(x)); 404 String type = operations[i].getReturnType(); 406 407 if (isPrimitive(type)) 408 { 409 invokeInstructions.append(convertPrimitiveToObject(cp, type)); invokeInstructions.append(new ARETURN()); } 412 else if (type.equals(Void.TYPE.getName())) 413 { 414 invokeInstructions.append(new ACONST_NULL()); invokeInstructions.append(new ARETURN()); } 417 else 418 { 419 invokeInstructions.append(new ARETURN()); } 421 } 422 } 423 424 InstructionHandle jumpToSuperInvoke = 428 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()); 435 ifOperationEqualsNull.setTarget(jumpToSuperInvoke); 437 438 if (operations.length > 0) 439 { 440 if (operationElseIfBranch != null) 442 operationElseIfBranch.setTarget(jumpToSuperInvoke); 443 444 beginTryBlock = beginTryBlock.getNext(); 446 endTryBlock = jumpToSuperInvoke.getPrev(); 447 } 448 449 450 InstructionHandle exceptionHandlerCode = 453 invokeInstructions.append(new ALOAD(0)); 454 invokeInstructions.append(new ALOAD(1)); 455 invokeInstructions.append(new ALOAD(2)); 456 invokeInstructions.append(new ALOAD(3)); 457 invokeInstructions.append(new INVOKESPECIAL(invokeIndex)); 458 invokeInstructions.append(new ARETURN()); 459 460 MethodGen invokeMethod = new MethodGen( 461 Constants.ACC_PUBLIC, 462 Type.OBJECT, 463 new Type[] { 464 Type.STRING, 465 new ArrayType(Object .class.getName(), 1), 466 new ArrayType(String .class.getName(), 1) 467 }, 468 new String [] { 469 "operationName", 470 "args", 471 "signature" 472 }, 473 "invoke", 474 className, invokeInstructions, cp 475 ); 476 invokeMethod.setMaxLocals(7); 477 invokeMethod.setMaxStack(calculateMaxStackSize(info)); 478 479 invokeMethod.addException(ReflectionException .class.getName()); 480 invokeMethod.addException(MBeanException .class.getName()); 481 482 if (operations.length > 0) { 483 invokeMethod.addExceptionHandler(beginTryBlock, endTryBlock, exceptionHandlerCode, new ObjectType("java.lang.Throwable")); 484 } 485 486 return invokeMethod; 487 } 488 489 private static int calculateMaxStackSize(MBeanInfo info) 490 { 491 MBeanOperationInfo [] operations = info.getOperations(); 492 int maxSize = 7; 493 494 for (int i = 0; i < operations.length; ++i) 495 { 496 if (operations[i].getSignature().length > maxSize + 2) 497 maxSize = operations[i].getSignature().length + 2; 498 } 499 500 return maxSize; 501 } 502 503 514 protected static InstructionList convertObjectToPrimitive(ConstantPoolGen cp, String type) 515 { 516 InstructionList il = new InstructionList(); 517 518 int intValueIndex = cp.addMethodref(Integer .class.getName(), "intValue", "()I"); 519 int byteValueIndex = cp.addMethodref(Byte .class.getName(), "byteValue", "()B"); 520 int charValueIndex = cp.addMethodref(Character .class.getName(), "charValue", "()C"); 521 int doubleValueIndex = cp.addMethodref(Double .class.getName(), "doubleValue", "()D"); 522 int floatValueIndex = cp.addMethodref(Float .class.getName(), "floatValue", "()F"); 523 int longValueIndex = cp.addMethodref(Long .class.getName(), "longValue", "()J"); 524 int shortValueIndex = cp.addMethodref(Short .class.getName(), "shortValue", "()S"); 525 int booleanValueIndex = cp.addMethodref(Boolean .class.getName(), "booleanValue", "()Z"); 526 527 531 if (type.equals(Integer.TYPE.getName())) 532 { 533 int x = cp.addClass("java.lang.Integer"); 534 il.append(new CHECKCAST(x)); il.append(new INVOKEVIRTUAL(intValueIndex)); } 537 538 else if (type.equals(Byte.TYPE.getName())) 539 { 540 int x = cp.addClass("java.lang.Byte"); 541 il.append(new CHECKCAST(x)); il.append(new INVOKEVIRTUAL(byteValueIndex)); } 544 545 else if (type.equals(Character.TYPE.getName())) 546 { 547 int x = cp.addClass("java.lang.Character"); 548 il.append(new CHECKCAST(x)); il.append(new INVOKEVIRTUAL(charValueIndex)); } 551 552 else if (type.equals(Double.TYPE.getName())) 553 { 554 int x = cp.addClass("java.lang.Double"); 555 il.append(new CHECKCAST(x)); il.append(new INVOKEVIRTUAL(doubleValueIndex)); } 558 559 else if (type.equals(Float.TYPE.getName())) 560 { 561 int x = cp.addClass("java.lang.Float"); 562 il.append(new CHECKCAST(x)); il.append(new INVOKEVIRTUAL(floatValueIndex)); } 565 566 else if (type.equals(Long.TYPE.getName())) 567 { 568 int x = cp.addClass("java.lang.Long"); 569 il.append(new CHECKCAST(x)); il.append(new INVOKEVIRTUAL(longValueIndex)); } 572 573 else if (type.equals(Short.TYPE.getName())) 574 { 575 int x = cp.addClass("java.lang.Short"); 576 il.append(new CHECKCAST(x)); il.append(new INVOKEVIRTUAL(shortValueIndex)); } 579 580 else if (type.equals(Boolean.TYPE.getName())) 581 { 582 int x = cp.addClass("java.lang.Boolean"); 583 il.append(new CHECKCAST(x)); il.append(new INVOKEVIRTUAL(booleanValueIndex)); } 586 587 return il; 588 } 589 590 591 603 protected static InstructionList convertPrimitiveToObject(ConstantPoolGen cp, String type) 604 { 605 InstructionList il = new InstructionList(); 606 607 if (type.equals(Boolean.TYPE.getName())) 608 { 609 int x = cp.addClass("java.lang.Boolean"); 610 int constrIndex = cp.addMethodref("java.lang.Boolean", "<init>", "(B)V"); 611 612 il.append(new ISTORE(4)); 613 il.append(new NEW(x)); 614 il.append(new ASTORE(5)); 615 il.append(new ALOAD(5)); 616 il.append(new ILOAD(4)); 617 il.append(new INVOKESPECIAL(constrIndex)); 618 il.append(new ALOAD(5)); 619 } 620 621 else if (type.equals(Short.TYPE.getName())) 622 { 623 int x = cp.addClass("java.lang.Short"); 624 int constrIndex = cp.addMethodref("java.lang.Short", "<init>", "(S)V"); 625 626 il.append(new ISTORE(4)); 627 il.append(new NEW(x)); 628 il.append(new ASTORE(5)); 629 il.append(new ALOAD(5)); 630 il.append(new ILOAD(4)); 631 il.append(new INVOKESPECIAL(constrIndex)); 632 il.append(new ALOAD(5)); 633 } 634 635 else if (type.equals(Long.TYPE.getName())) 636 { 637 int x = cp.addClass("java.lang.Long"); 638 int constrIndex = cp.addMethodref("java.lang.Long", "<init>", "(J)V"); 639 640 il.append(new LSTORE(4)); 641 il.append(new NEW(x)); 642 il.append(new ASTORE(6)); 643 il.append(new ALOAD(6)); 644 il.append(new LLOAD(4)); 645 il.append(new INVOKESPECIAL(constrIndex)); 646 il.append(new ALOAD(6)); 647 } 648 649 else if (type.equals(Integer.TYPE.getName())) 650 { 651 int x = cp.addClass("java.lang.Integer"); 652 int constrIndex = cp.addMethodref("java.lang.Integer", "<init>", "(I)V"); 653 654 il.append(new ISTORE(4)); 655 il.append(new NEW(x)); 656 il.append(new ASTORE(5)); 657 il.append(new ALOAD(5)); 658 il.append(new ILOAD(4)); 659 il.append(new INVOKESPECIAL(constrIndex)); 660 il.append(new ALOAD(5)); 661 } 662 663 else if (type.equals(Float.TYPE.getName())) 664 { 665 int x = cp.addClass("java.lang.Float"); 666 int constrIndex = cp.addMethodref("java.lang.Float", "<init>", "(F)V"); 667 668 il.append(new FSTORE(4)); 669 il.append(new NEW(x)); 670 il.append(new ASTORE(5)); 671 il.append(new ALOAD(5)); 672 il.append(new FLOAD(4)); 673 il.append(new INVOKESPECIAL(constrIndex)); 674 il.append(new ALOAD(5)); 675 } 676 677 else if (type.equals(Double.TYPE.getName())) 678 { 679 int x = cp.addClass("java.lang.Double"); 680 int constrIndex = cp.addMethodref("java.lang.Double", "<init>", "(D)V"); 681 682 il.append(new DSTORE(4)); 683 il.append(new NEW(x)); 684 il.append(new ASTORE(6)); 685 il.append(new ALOAD(6)); 686 il.append(new DLOAD(4)); 687 il.append(new INVOKESPECIAL(constrIndex)); 688 il.append(new ALOAD(6)); 689 } 690 691 else if (type.equals(Character.TYPE.getName())) 692 { 693 int x = cp.addClass("java.lang.Character"); 694 int constrIndex = cp.addMethodref("java.lang.Character", "<init>", "(C)V"); 695 696 il.append(new ISTORE(4)); 697 il.append(new NEW(x)); 698 il.append(new ASTORE(5)); 699 il.append(new ALOAD(5)); 700 il.append(new ILOAD(4)); 701 il.append(new INVOKESPECIAL(constrIndex)); 702 il.append(new ALOAD(5)); 703 } 704 705 else if (type.equals(Byte.TYPE.getName())) 706 { 707 int x = cp.addClass("java.lang.Byte"); 708 int constrIndex = cp.addMethodref("java.lang.Byte", "<init>", "(B)V"); 709 710 il.append(new ISTORE(4)); 711 il.append(new NEW(x)); 712 il.append(new ASTORE(5)); 713 il.append(new ALOAD(5)); 714 il.append(new ILOAD(4)); 715 il.append(new INVOKESPECIAL(constrIndex)); 716 il.append(new ALOAD(5)); 717 } 718 719 return il; 720 } 721 722 723 733 protected static MethodEntry[] getOperations(MBeanInfo info) 734 { 735 HashMap operationMap = new HashMap (); 736 ArrayList overloadList = new ArrayList (); 737 MBeanOperationInfo [] operations = info.getOperations(); 738 739 for (int i = 0; i < operations.length; ++i) 740 { 741 String methodName = operations[i].getName(); 742 743 if (operationMap.containsKey(methodName)) 744 overloadList.add(methodName); 745 else 746 operationMap.put(methodName, new MethodEntry(operations[i])); 747 } 748 749 Iterator it = overloadList.iterator(); 751 while (it.hasNext()) 752 operationMap.remove(it.next()); 753 754 return (MethodEntry[])operationMap.values().toArray(new MethodEntry[0]); 755 } 756 757 758 private static class MethodEntry extends MBeanOperationInfo 760 { 761 private static final long serialVersionUID = 1792631947840418314L; 762 String methodDescriptor = null; 763 int nameIndexInCP = -1; 764 int methodIndexInCP = -1; 765 766 public MethodEntry(MBeanOperationInfo info) 767 { 768 super(info.getName(), info.getDescription(), info.getSignature(), info.getReturnType(), info.getImpact()); 769 770 this.methodDescriptor = getMethodDescriptor(info.getSignature(), info.getReturnType()); 771 } 772 } 773 774 775 } 776 777 778 779 780 | Popular Tags |