1 22 package org.jboss.mx.mxbean; 23 24 import java.lang.reflect.Array ; 25 import java.lang.reflect.GenericArrayType ; 26 import java.lang.reflect.InvocationHandler ; 27 import java.lang.reflect.Method ; 28 import java.lang.reflect.ParameterizedType ; 29 import java.lang.reflect.Proxy ; 30 import java.lang.reflect.Type ; 31 import java.math.BigDecimal ; 32 import java.math.BigInteger ; 33 import java.util.Arrays ; 34 import java.util.Collection ; 35 import java.util.Collections ; 36 import java.util.Date ; 37 import java.util.HashMap ; 38 import java.util.HashSet ; 39 import java.util.Iterator ; 40 import java.util.Map ; 41 import java.util.Set ; 42 import java.util.WeakHashMap ; 43 44 import javax.management.DynamicMBean ; 45 import javax.management.ObjectName ; 46 import javax.management.openmbean.ArrayType ; 47 import javax.management.openmbean.CompositeData ; 48 import javax.management.openmbean.CompositeDataSupport ; 49 import javax.management.openmbean.CompositeType ; 50 import javax.management.openmbean.OpenType ; 51 import javax.management.openmbean.SimpleType ; 52 import javax.management.openmbean.TabularData ; 53 import javax.management.openmbean.TabularDataSupport ; 54 import javax.management.openmbean.TabularType ; 55 56 import org.jboss.util.collection.WeakValueHashMap; 57 58 64 public class MXBeanUtils 65 { 66 67 private static final Map <Method , String > compositeDataKeyCache = Collections.synchronizedMap(new WeakHashMap <Method , String >()); 68 69 70 private static final Map <Class , Map <String , Method >> compositeDataMethodCache = Collections.synchronizedMap(new WeakHashMap <Class , Map <String , Method >>()); 71 72 73 public static final String MAP_KEY = "key"; 74 75 76 public static final String MAP_VALUE = "value"; 77 78 79 public static final String [] MAP_INDEX_NAMES = { MAP_KEY }; 80 81 82 public static final String [] MAP_ITEM_NAMES = { MAP_KEY, MAP_VALUE }; 83 84 90 public static OpenType getOpenType(Type type) 91 { 92 if (type == null) 93 throw new IllegalArgumentException ("Null type"); 94 95 OpenType result = checkType(type); 96 if (result != null) 97 return result; 98 Class clazz = (Class ) type; 99 return CompositeTypeMetaDataFactory.getCompositeType(clazz); 100 } 101 102 109 public static SimpleType getSimpleType(Class type) throws Exception 110 { 111 SimpleType simpleType = checkSimpleType(type); 112 if (simpleType == null) 113 throw new IllegalArgumentException ("Not a SimpleType: " + type.getName()); 114 return simpleType; 115 } 116 117 123 public static OpenType checkType(Type type) 124 { 125 OpenType result = checkSimpleType(type); 126 if (result != null) 127 return result; 128 result = checkEnum(type); 129 if (result != null) 130 return result; 131 result = checkArray(type); 132 if (result != null) 133 return result; 134 result = checkCollection(type); 135 if (result != null) 136 return result; 137 return checkMap(type); 138 } 139 140 148 public static <T> T createCompositeDataProxy(Class <T> intf, CompositeData compositeData) 149 { 150 if (intf == null) 151 throw new IllegalArgumentException ("Null interface"); 152 InvocationHandler handler = new CompositeDataInvocationHandler(compositeData); 153 Object object = Proxy.newProxyInstance(intf.getClassLoader(), new Class [] { intf }, handler); 154 return intf.cast(object); 155 } 156 157 166 public static Object construct(Type type, Object value, Object context) throws Exception 167 { 168 OpenType openType = getOpenType(type); 169 return construct(openType, value, context); 170 } 171 172 181 public static Object construct(OpenType openType, Object value, Object context) throws Exception 182 { 183 if (openType instanceof SimpleType ) 184 return constructSimpleData(value); 185 if (openType.isArray()) 186 return constructArrayData(openType, value, context); 187 if (openType instanceof TabularType ) 188 return constructTabularData(openType, value, context); 189 return constructCompositeData(openType, value, context); 190 } 191 192 201 public static Object reconstruct(Type type, Object value, Object context) throws Exception 202 { 203 OpenType openType = MXBeanUtils.getOpenType(type); 204 return reconstruct(openType, type, value, context); 205 } 206 207 217 public static Object reconstruct(OpenType openType, Type type, Object value, Object context) throws Exception 218 { 219 if (openType instanceof SimpleType ) 220 return reconstructSimpleData(type, value, context); 221 if (openType.isArray()) 222 return reconstructArrayData(openType, type, value, context); 223 if (openType instanceof TabularType ) 224 return reconstructTabularData(openType, type, value, context); 225 return reconstructCompositeData(openType, type, value, context); 226 } 227 228 234 public static SimpleType checkSimpleType(Type type) 235 { 236 if (BigDecimal .class.equals(type)) 237 return SimpleType.BIGDECIMAL; 238 if (BigInteger .class.equals(type)) 239 return SimpleType.BIGINTEGER; 240 if (Boolean .class.equals(type)) 241 return SimpleType.BOOLEAN; 242 if (Boolean.TYPE.equals(type)) 243 return SimpleType.BOOLEAN; 244 if (Byte .class.equals(type)) 245 return SimpleType.BYTE; 246 if (Byte.TYPE.equals(type)) 247 return SimpleType.BYTE; 248 if (Character .class.equals(type)) 249 return SimpleType.CHARACTER; 250 if (Character.TYPE.equals(type)) 251 return SimpleType.CHARACTER; 252 if (Date .class.equals(type)) 253 return SimpleType.DATE; 254 if (Double .class.equals(type)) 255 return SimpleType.DOUBLE; 256 if (Double.TYPE.equals(type)) 257 return SimpleType.DOUBLE; 258 if (Float .class.equals(type)) 259 return SimpleType.FLOAT; 260 if (Float.TYPE.equals(type)) 261 return SimpleType.FLOAT; 262 if (Integer .class.equals(type)) 263 return SimpleType.INTEGER; 264 if (Integer.TYPE.equals(type)) 265 return SimpleType.INTEGER; 266 if (Long .class.equals(type)) 267 return SimpleType.LONG; 268 if (Long.TYPE.equals(type)) 269 return SimpleType.LONG; 270 if (ObjectName .class.equals(type)) 271 return SimpleType.OBJECTNAME; 272 if (Short .class.equals(type)) 273 return SimpleType.SHORT; 274 if (Short.TYPE.equals(type)) 275 return SimpleType.SHORT; 276 if (String .class.equals(type)) 277 return SimpleType.STRING; 278 if (Void .class.equals(type)) 279 return SimpleType.VOID; 280 return null; 281 } 282 283 289 public static SimpleType checkEnum(Type type) 290 { 291 if (type instanceof Class == false) 292 return null; 293 Class clazz = (Class ) type; 294 if (clazz.isEnum() || Enum .class.equals(clazz)) 295 return SimpleType.STRING; 296 return null; 297 } 298 299 305 public static Object constructSimpleData(Object value) 306 { 307 if (value != null && value instanceof Enum ) 308 { 309 Enum enumeration = (Enum ) value; 310 return enumeration.name(); 311 } 312 return value; 313 } 314 315 323 @SuppressWarnings ("unchecked") 324 private static Object reconstructSimpleData(Type type, Object value, Object context) 325 { 326 if (type instanceof Class ) 327 { 328 if (value != null) 329 { 330 Class clazz = (Class ) type; 331 if (clazz.isEnum() || Enum .class.equals(clazz)) 332 { 333 String string = (String ) value; 334 return Enum.valueOf(clazz, string); 335 } 336 } 337 else 338 { 339 Class clazz = (Class ) type; 340 if (clazz.isPrimitive()) 341 throw new IllegalArgumentException ("Attempt to use null as a primitive for: " + context); 342 return null; 343 } 344 } 345 return value; 346 } 347 348 354 public static ArrayType checkArray(Type type) 355 { 356 if (type instanceof Class ) 357 { 358 Class clazz = (Class ) type; 359 if (clazz.isArray() == false) 360 return null; 361 int dimension = 1; 362 Class componentType = clazz.getComponentType(); 363 while (componentType.isArray()) 364 { 365 ++dimension; 366 componentType = componentType.getComponentType(); 367 } 368 OpenType componentOpenType = getOpenType(componentType); 369 try 370 { 371 return new ArrayType (dimension, componentOpenType); 372 } 373 catch (RuntimeException e) 374 { 375 throw e; 376 } 377 catch (Exception e) 378 { 379 throw new RuntimeException (e); 380 } 381 } 382 if (type instanceof GenericArrayType ) 383 { 384 GenericArrayType arrayType = (GenericArrayType ) type; 385 int dimension = 1; 386 Type componentType = arrayType.getGenericComponentType(); 387 while (componentType instanceof GenericArrayType ) 388 { 389 ++dimension; 390 arrayType = (GenericArrayType ) componentType; 391 componentType = arrayType.getGenericComponentType(); 392 } 393 OpenType componentOpenType = getOpenType(componentType); 394 try 395 { 396 return new ArrayType (dimension, componentOpenType); 397 } 398 catch (RuntimeException e) 399 { 400 throw e; 401 } 402 catch (Exception e) 403 { 404 throw new RuntimeException (e); 405 } 406 } 407 return null; 408 } 409 410 416 public static ArrayType checkCollection(Type type) 417 { 418 if (type instanceof ParameterizedType == false) 419 { 420 if (type instanceof Class ) 421 return checkCollectionClass((Class ) type); 422 else 423 return null; 424 } 425 ParameterizedType parameterizedType = (ParameterizedType ) type; 426 Type rawType = parameterizedType.getRawType(); 427 if (rawType instanceof Class == false) 428 return null; 429 Class rawClass = (Class ) rawType; 430 if (Collection .class.isAssignableFrom(rawClass) == false) 431 return null; 432 Type componentType = parameterizedType.getActualTypeArguments()[0]; 433 OpenType componentOpenType = getOpenType(componentType); 434 try 435 { 436 return new ArrayType (1, componentOpenType); 437 } 438 catch (RuntimeException e) 439 { 440 throw e; 441 } 442 catch (Exception e) 443 { 444 throw new RuntimeException (e); 445 } 446 } 447 448 454 public static ArrayType checkCollectionClass(Class clazz) 455 { 456 if (Collection .class.isAssignableFrom(clazz) == false) 457 return null; 458 OpenType componentOpenType = getOpenType(Object .class); 459 try 460 { 461 return new ArrayType (1, componentOpenType); 462 } 463 catch (RuntimeException e) 464 { 465 throw e; 466 } 467 catch (Exception e) 468 { 469 throw new RuntimeException (e); 470 } 471 } 472 473 482 public static Object constructArrayData(OpenType openType, Object value, Object context) throws Exception 483 { 484 if (value == null) 485 return null; 486 487 ArrayType arrayType = (ArrayType ) openType; 488 OpenType elementType = arrayType.getElementOpenType(); 489 int dimension = arrayType.getDimension(); 490 491 Class clazz = value.getClass(); 492 if (clazz.isArray()) 493 { 494 Object [] oldArray = (Object []) value; 495 Class <?> componentType = Class.forName(arrayType.getClassName()); 496 return constructArray(elementType, componentType.getComponentType(), dimension, oldArray, context); 497 } 498 if (value instanceof Collection ) 499 { 500 Collection c = (Collection ) value; 501 Object [] oldArray = c.toArray(); 502 Class <?> componentType = Class.forName(arrayType.getClassName()); 503 return constructArray(elementType, componentType.getComponentType(), dimension, oldArray, context); 504 } 505 throw new UnsupportedOperationException ("Cannot construct array for: " + value); 506 } 507 508 519 private static Object [] constructArray(OpenType elementType, Class <?> componentType, int dimension, Object [] oldArray, Object context) throws Exception 520 { 521 if (oldArray == null) 522 return null; 523 524 Object [] newArray = (Object []) Array.newInstance(componentType, oldArray.length); 525 if (dimension > 1) 526 { 527 for (int i = 0; i < oldArray.length; ++i) 528 { 529 Object [] nestedOld = (Object []) oldArray[i]; 530 newArray[i] = constructArray(elementType, componentType.getComponentType(), dimension-1, nestedOld, context); 531 } 532 } 533 else 534 { 535 if (Object .class.equals(componentType)) 536 { 537 for (int i = 0; i < oldArray.length; ++i) 538 newArray[i] = oldArray[i]; 539 } 540 else 541 { 542 for (int i = 0; i < oldArray.length; ++i) 543 newArray[i] = construct(elementType, oldArray[i], context); 544 } 545 } 546 547 return newArray; 548 } 549 550 560 public static Object reconstructArrayData(OpenType openType, Type type, Object value, Object context) throws Exception 561 { 562 if (value == null) 563 return null; 564 565 ArrayType arrayType = (ArrayType ) getOpenType(type); 566 OpenType elementType = arrayType.getElementOpenType(); 567 int dimension = arrayType.getDimension(); 568 Object [] oldArray = (Object []) value; 569 if (type instanceof Class ) 570 { 571 Class clazz = (Class ) type; 572 if (clazz.isArray()) 573 return reconstructArray(elementType, clazz.getComponentType(), dimension, oldArray, context); 574 } 580 else if (type instanceof ParameterizedType ) 581 { 582 ParameterizedType parameterizedType = (ParameterizedType ) type; 583 Type rawType = parameterizedType.getRawType(); 584 if (rawType instanceof Class ) 585 { 586 Class raw = (Class ) rawType; 587 if (Set .class.isAssignableFrom(raw)) 588 return createSet(oldArray); 589 else if (Collection .class.isAssignableFrom(raw)) 590 return createCollection(oldArray); 591 } 592 } 593 throw new UnsupportedOperationException ("Cannot convert array type: " + type); 594 } 595 596 607 private static Object [] reconstructArray(OpenType elementType, Class componentType, int dimension, Object [] oldArray, Object context) throws Exception 608 { 609 if (oldArray == null) 610 return null; 611 612 Object [] newArray = (Object []) Array.newInstance(componentType, oldArray.length); 613 if (dimension > 1) 614 { 615 for (int i = 0; i < oldArray.length; ++i) 616 { 617 Object [] nestedOld = (Object []) oldArray[i]; 618 newArray[i] = reconstructArray(elementType, componentType.getComponentType(), dimension-1, nestedOld, context); 619 } 620 } 621 else 622 { 623 for (int i = 0; i < oldArray.length; ++i) 624 newArray[i] = reconstruct(elementType, componentType, oldArray[i], context); 625 } 626 627 return newArray; 628 } 629 630 636 private static Collection createCollection(Object [] array) 637 { 638 return Arrays.asList(array); 639 } 640 641 647 @SuppressWarnings ("unchecked") 648 private static Set createSet(Object [] array) 649 { 650 HashSet result = new HashSet (array.length); 651 for (int i = 0; i < array.length; ++i) 652 result.add(array[i]); 653 return result; 654 } 655 656 662 public static TabularType checkMap(Type type) 663 { 664 if (type instanceof ParameterizedType == false) 665 { 666 if (type instanceof Class ) 667 return checkMapClass((Class ) type); 668 else 669 return null; 670 } 671 ParameterizedType parameterizedType = (ParameterizedType ) type; 672 Type rawType = parameterizedType.getRawType(); 673 if (rawType instanceof Class == false) 674 return null; 675 Class rawClass = (Class ) rawType; 676 if (Map .class.isAssignableFrom(rawClass) == false) 677 return null; 678 Type [] args = parameterizedType.getActualTypeArguments(); 679 Type keyType = args[0]; 680 Type valueType = args[1]; 681 return createMapType(keyType, valueType); 682 } 683 684 690 public static TabularType checkMapClass(Class clazz) 691 { 692 if (Map .class.isAssignableFrom(clazz) == false) 693 return null; 694 return createMapType(Object .class, Object .class); 695 } 696 697 704 public static TabularType createMapType(Type keyType, Type valueType) 705 { 706 String name = Map .class.getName(); 707 OpenType [] itemTypes = { getOpenType(keyType), getOpenType(valueType) }; 708 try 709 { 710 CompositeType entryType = createMapEntryType(itemTypes); 711 return new TabularType (name, name, entryType, MAP_INDEX_NAMES); 712 } 713 catch (RuntimeException e) 714 { 715 throw e; 716 } 717 catch (Exception e) 718 { 719 throw new RuntimeException (e); 720 } 721 } 722 723 729 private static CompositeType createMapEntryType(OpenType [] itemTypes) 730 { 731 String entryName = Map.Entry .class.getName(); 732 try 733 { 734 return new CompositeType (entryName, entryName, MAP_ITEM_NAMES, MAP_ITEM_NAMES, itemTypes); 735 } 736 catch (RuntimeException e) 737 { 738 throw e; 739 } 740 catch (Exception e) 741 { 742 throw new RuntimeException (e); 743 } 744 } 745 746 755 @SuppressWarnings ("unchecked") 756 public static Object constructTabularData(OpenType openType, Object value, Object context) throws Exception 757 { 758 if (value == null) 759 return null; 760 761 TabularType tabularType = (TabularType ) openType; 762 763 if (value instanceof Map ) 764 { 765 TabularDataSupport table = new TabularDataSupport (tabularType); 766 CompositeType entryType = tabularType.getRowType(); 767 OpenType keyType = entryType.getType(MAP_KEY); 768 OpenType valueType = entryType.getType(MAP_VALUE); 769 770 Map <Object , Object > m = (Map <Object , Object >) value; 771 for (Iterator <Map.Entry <Object , Object >> i = m.entrySet().iterator(); i.hasNext();) 772 { 773 Map.Entry <Object , Object > entry = i.next(); 774 Object key = construct(keyType, entry.getKey(), context); 775 Object val = construct(valueType, entry.getValue(), context); 776 CompositeDataSupport data = new CompositeDataSupport (entryType, MXBeanUtils.MAP_ITEM_NAMES, new Object [] { key, val }); 777 table.put(data); 778 } 779 return table; 780 } 781 throw new UnsupportedOperationException ("Cannot construct map for: " + value); 782 } 783 784 794 public static Object reconstructTabularData(OpenType openType, Type type, Object value, Object context) throws Exception 795 { 796 if (value == null) 797 return null; 798 799 TabularType tabularType = (TabularType ) getOpenType(type); 800 if (type instanceof Class ) 801 { 802 } 807 else if (type instanceof ParameterizedType ) 808 { 809 ParameterizedType parameterizedType = (ParameterizedType ) type; 810 Type rawType = parameterizedType.getRawType(); 811 if (rawType instanceof Class ) 812 { 813 Class raw = (Class ) rawType; 814 if (Map .class.isAssignableFrom(raw)) 815 { 816 Type keyType = parameterizedType.getActualTypeArguments()[0]; 817 Type valueType = parameterizedType.getActualTypeArguments()[1]; 818 return createMap(tabularType, keyType, valueType, value, context); 819 } 820 } 821 } 822 throw new UnsupportedOperationException ("Cannot convert array type: " + type); 823 } 824 825 836 @SuppressWarnings ("unchecked") 837 private static Map createMap(TabularType openType, Type keyType, Type valueType, Object value, Object context) throws Exception 838 { 839 if (value == null) 840 return null; 841 842 Map <Object , Object > result = new HashMap <Object , Object >(); 843 844 TabularData table = (TabularData ) value; 845 Collection <CompositeData > values = table.values(); 846 for (CompositeData entry : values) 847 { 848 Object key = reconstruct(keyType, entry.get(MAP_KEY), context); 849 Object val = reconstruct(valueType, entry.get(MAP_VALUE), context); 850 result.put(key, val); 851 } 852 853 return result; 854 } 855 856 865 @SuppressWarnings ("unchecked") 866 public static Object constructCompositeData(OpenType openType, Object value, Object context) throws Exception 867 { 868 if (value == null) 869 return null; 870 871 Class clazz = value.getClass(); 872 873 CompositeType compositeType = (CompositeType ) openType; 874 Set <String > nameSet = compositeType.keySet(); 875 String [] names = nameSet.toArray(new String [nameSet.size()]); 876 877 Object [] values = new Object [names.length]; 878 879 for (int i = 0 ; i < names.length; ++i) 880 { 881 String name = names[i]; 882 OpenType itemType = compositeType.getType(name); 883 Method method = getCompositeDataMethod(clazz, name, itemType == SimpleType.BOOLEAN); 884 Object itemValue = method.invoke(value, null); 885 values[i] = construct(itemType, itemValue, context); 886 } 887 return new CompositeDataSupport (compositeType, names, values); 888 } 889 890 900 public static Object reconstructCompositeData(OpenType openType, Type type, Object value, Object context) throws Exception 901 { 902 if (value == null) 903 return null; 904 905 CompositeData compositeData = (CompositeData ) value; 906 CompositeDataInvocationHandler handler = new CompositeDataInvocationHandler(compositeData); 907 Class clazz = (Class ) type; 908 Class [] interfaces = null; 909 if (clazz.isInterface()) 910 interfaces = new Class [] { clazz }; 911 else 912 interfaces = clazz.getInterfaces(); 913 return Proxy.newProxyInstance(clazz.getClassLoader(), interfaces, handler); 914 } 915 916 922 public static String getCompositeDataKey(Method method) 923 { 924 String key = compositeDataKeyCache.get(method); 925 if (key != null) 926 return key; 927 928 StringBuilder fieldName = null; 929 930 Class returnType = method.getReturnType(); 931 Class [] paramTypes = method.getParameterTypes(); 932 if (Void.TYPE.equals(returnType) == false && paramTypes.length == 0) 933 { 934 String name = method.getName(); 935 if (name.startsWith("is") && name.length() > 2) 936 { 937 if (Boolean.TYPE.equals(returnType)) 938 { 939 fieldName = new StringBuilder (); 940 fieldName.append(Character.toLowerCase(name.charAt(2))); 941 if (name.length() > 3) 942 fieldName.append(name.substring(3)); 943 } 944 } 945 else if (name.startsWith("get") && name.length() > 3) 946 { 947 fieldName = new StringBuilder (); 948 fieldName.append(Character.toLowerCase(name.charAt(3))); 949 if (name.length() > 4) 950 fieldName.append(name.substring(4)); 951 } 952 } 953 954 if (fieldName == null) 955 return null; 956 957 String result = fieldName.toString(); 958 compositeDataKeyCache.put(method, result); 959 return result; 960 } 961 962 971 @SuppressWarnings ("unchecked") 972 public static Method getCompositeDataMethod(Class clazz, String key, boolean isBoolean) throws Exception 973 { 974 Map <String , Method > cache = compositeDataMethodCache.get(clazz); 975 if (cache != null) 976 { 977 Method method = cache.get(key); 978 if (method != null) 979 return method; 980 } 981 982 StringBuilder name = new StringBuilder (); 983 name.append(Character.toUpperCase(key.charAt(0))); 984 if (key.length() > 1) 985 name.append(key.substring(1)); 986 Method method = null; 987 try 988 { 989 method = clazz.getMethod("get" + name, null); 990 } 991 catch (NoSuchMethodException e) 992 { 993 if (isBoolean) 994 { 995 try 996 { 997 method = clazz.getMethod("is" + name, null); 998 } 999 catch (NoSuchMethodException ignored) 1000 { 1001 throw e; 1002 } 1003 } 1004 else 1005 { 1006 throw e; 1007 } 1008 } 1009 1010 if (cache == null) 1011 { 1012 cache = new WeakValueHashMap(); 1013 compositeDataMethodCache.put(clazz, cache); 1014 } 1015 cache.put(key, method); 1016 return method; 1017 } 1018 1019 1026 public static DynamicMBean createMXBean(Object resource, Class <?> mxbeanInterface) 1027 { 1028 try 1029 { 1030 return new MXBeanDelegate(resource, mxbeanInterface); 1031 } 1032 catch (RuntimeException e) 1033 { 1034 throw e; 1035 } 1036 catch (Exception e) 1037 { 1038 throw new RuntimeException ("Error creating MXBean", e); 1039 } 1040 } 1041} 1042 | Popular Tags |