1 /* 2 * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.management; 27 import java.lang.management.MemoryUsage; 28 import java.lang.management.MemoryNotificationInfo; 29 import java.lang.management.MonitorInfo; 30 import java.lang.management.LockInfo; 31 import java.lang.management.ThreadInfo; 32 import java.lang.reflect.*; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.*; 36 import java.io.InvalidObjectException; 37 import java.security.AccessController; 38 import java.security.PrivilegedAction; 39 import java.security.PrivilegedActionException; 40 import java.security.PrivilegedExceptionAction; 41 import javax.management.openmbean.*; 42 import static javax.management.openmbean.SimpleType.*; 43 44 /** 45 * A mapped mxbean type maps a Java type to an open type. 46 * Only the following Java types are mappable 47 * (currently required by the platform MXBeans): 48 * 1. Primitive types 49 * 2. Wrapper classes such java.lang.Integer, etc 50 * 3. Classes with only getter methods and with a static "from" method 51 * that takes a CompositeData argument. 52 * 4. E[] where E is a type of 1-4 (can be multi-dimensional array) 53 * 5. List<E> where E is a type of 1-3 54 * 6. Map<K, V> where K and V are a type of 1-4 55 * 56 * OpenDataException will be thrown if a Java type is not supported. 57 */ 58 // Suppress unchecked cast warnings at line 442, 523 and 546 59 // Suppress unchecked calls at line 235, 284, 380 and 430. 60 @SuppressWarnings("unchecked") 61 public abstract class MappedMXBeanType { 62 private static final WeakHashMap<Type,MappedMXBeanType> convertedTypes = 63 new WeakHashMap<>(); 64 65 boolean isBasicType = false; 66 OpenType<?> openType = inProgress; 67 Class<?> mappedTypeClass; 68 69 static synchronized MappedMXBeanType newMappedType(Type javaType) 70 throws OpenDataException { 71 72 MappedMXBeanType mt = null; 73 if (javaType instanceof Class) { 74 final Class<?> c = (Class<?>) javaType; 75 if (c.isEnum()) { 76 mt = new EnumMXBeanType(c); 77 } else if (c.isArray()) { 78 mt = new ArrayMXBeanType(c); 79 } else { 80 mt = new CompositeDataMXBeanType(c); 81 } 82 } else if (javaType instanceof ParameterizedType) { 83 final ParameterizedType pt = (ParameterizedType) javaType; 84 final Type rawType = pt.getRawType(); 85 if (rawType instanceof Class) { 86 final Class<?> rc = (Class<?>) rawType; 87 if (rc == List.class) { 88 mt = new ListMXBeanType(pt); 89 } else if (rc == Map.class) { 90 mt = new MapMXBeanType(pt); 91 } 92 } 93 } else if (javaType instanceof GenericArrayType) { 94 final GenericArrayType t = (GenericArrayType) javaType; 95 mt = new GenericArrayMXBeanType(t); 96 } 97 // No open type mapped for the javaType 98 if (mt == null) { 99 throw new OpenDataException(javaType + 100 " is not a supported MXBean type."); 101 } 102 convertedTypes.put(javaType, mt); 103 return mt; 104 } 105 106 // basic types do not require data mapping 107 static synchronized MappedMXBeanType newBasicType(Class<?> c, OpenType<?> ot) 108 throws OpenDataException { 109 MappedMXBeanType mt = new BasicMXBeanType(c, ot); 110 convertedTypes.put(c, mt); 111 return mt; 112 } 113 114 public static synchronized MappedMXBeanType getMappedType(Type t) 115 throws OpenDataException { 116 MappedMXBeanType mt = convertedTypes.get(t); 117 if (mt == null) { 118 mt = newMappedType(t); 119 } 120 121 if (mt.getOpenType() instanceof InProgress) { 122 throw new OpenDataException("Recursive data structure"); 123 } 124 return mt; 125 } 126 127 // Convert a class to an OpenType 128 public static synchronized OpenType<?> toOpenType(Type t) 129 throws OpenDataException { 130 MappedMXBeanType mt = getMappedType(t); 131 return mt.getOpenType(); 132 } 133 134 public static Object toJavaTypeData(Object openData, Type t) 135 throws OpenDataException, InvalidObjectException { 136 if (openData == null) { 137 return null; 138 } 139 MappedMXBeanType mt = getMappedType(t); 140 return mt.toJavaTypeData(openData); 141 } 142 143 public static Object toOpenTypeData(Object data, Type t) 144 throws OpenDataException { 145 if (data == null) { 146 return null; 147 } 148 MappedMXBeanType mt = getMappedType(t); 149 return mt.toOpenTypeData(data); 150 } 151 152 // Return the mapped open type 153 public OpenType<?> getOpenType() { 154 return openType; 155 } 156 157 boolean isBasicType() { 158 return isBasicType; 159 } 160 161 // Return the type name of the mapped open type 162 // For primitive types, the type name is the same as the javaType 163 // but the mapped open type is the wrapper class 164 String getTypeName() { 165 return getMappedTypeClass().getName(); 166 } 167 168 // Return the mapped open type 169 Class<?> getMappedTypeClass() { 170 return mappedTypeClass; 171 } 172 173 abstract Type getJavaType(); 174 175 // return name of the class or the generic type 176 abstract String getName(); 177 178 public abstract Object toOpenTypeData(Object javaTypeData) 179 throws OpenDataException; 180 181 public abstract Object toJavaTypeData(Object openTypeData) 182 throws OpenDataException, InvalidObjectException; 183 184 // Basic Types - Classes that do not require data conversion 185 // including primitive types and all SimpleType 186 // 187 // Mapped open type: SimpleType for corresponding basic type 188 // 189 // Data Mapping: 190 // T <-> T (no conversion) 191 // 192 static class BasicMXBeanType extends MappedMXBeanType { 193 final Class<?> basicType; 194 BasicMXBeanType(Class<?> c, OpenType<?> openType) { 195 this.basicType = c; 196 this.openType = openType; 197 this.mappedTypeClass = c; 198 this.isBasicType = true; 199 } 200 201 Type getJavaType() { 202 return basicType; 203 } 204 205 String getName() { 206 return basicType.getName(); 207 } 208 209 public Object toOpenTypeData(Object data) throws OpenDataException { 210 return data; 211 } 212 213 public Object toJavaTypeData(Object data) 214 throws OpenDataException, InvalidObjectException { 215 216 return data; 217 } 218 } 219 220 221 // Enum subclasses 222 // Mapped open type - String 223 // 224 // Data Mapping: 225 // Enum <-> enum's name 226 // 227 static class EnumMXBeanType extends MappedMXBeanType { 228 @SuppressWarnings("rawtypes") 229 final Class enumClass; 230 EnumMXBeanType(Class<?> c) { 231 this.enumClass = c; 232 this.openType = STRING; 233 this.mappedTypeClass = String.class; 234 } 235 236 Type getJavaType() { 237 return enumClass; 238 } 239 240 String getName() { 241 return enumClass.getName(); 242 } 243 244 public Object toOpenTypeData(Object data) throws OpenDataException { 245 return ((Enum) data).name(); 246 } 247 248 public Object toJavaTypeData(Object data) 249 throws OpenDataException, InvalidObjectException { 250 251 try { 252 return Enum.valueOf(enumClass, (String) data); 253 } catch (IllegalArgumentException e) { 254 // missing enum constants 255 final InvalidObjectException ioe = 256 new InvalidObjectException("Enum constant named " + 257 (String) data + " is missing"); 258 ioe.initCause(e); 259 throw ioe; 260 } 261 } 262 } 263 264 // Array E[] 265 // Mapped open type - Array with element of OpenType for E 266 // 267 // Data Mapping: 268 // E[] <-> openTypeData(E)[] 269 // 270 static class ArrayMXBeanType extends MappedMXBeanType { 271 final Class<?> arrayClass; 272 protected MappedMXBeanType componentType; 273 protected MappedMXBeanType baseElementType; 274 275 ArrayMXBeanType(Class<?> c) throws OpenDataException { 276 this.arrayClass = c; 277 this.componentType = getMappedType(c.getComponentType()); 278 279 StringBuilder className = new StringBuilder(); 280 Class<?> et = c; 281 int dim; 282 for (dim = 0; et.isArray(); dim++) { 283 className.append('['); 284 et = et.getComponentType(); 285 } 286 baseElementType = getMappedType(et); 287 if (et.isPrimitive()) { 288 className = new StringBuilder(c.getName()); 289 } else { 290 className.append('L').append(baseElementType.getTypeName()).append(';'); 291 } 292 try { 293 mappedTypeClass = Class.forName(className.toString()); 294 } catch (ClassNotFoundException e) { 295 final OpenDataException ode = 296 new OpenDataException("Cannot obtain array class"); 297 ode.initCause(e); 298 throw ode; 299 } 300 301 openType = new ArrayType<>(dim, baseElementType.getOpenType()); 302 } 303 304 protected ArrayMXBeanType() { 305 arrayClass = null; 306 }; 307 308 Type getJavaType() { 309 return arrayClass; 310 } 311 312 String getName() { 313 return arrayClass.getName(); 314 } 315 316 public Object toOpenTypeData(Object data) throws OpenDataException { 317 // If the base element type is a basic type 318 // return the data as no conversion is needed. 319 // Primitive types are not converted to wrappers. 320 if (baseElementType.isBasicType()) { 321 return data; 322 } 323 324 final Object[] array = (Object[]) data; 325 final Object[] openArray = (Object[]) 326 Array.newInstance(componentType.getMappedTypeClass(), 327 array.length); 328 int i = 0; 329 for (Object o : array) { 330 if (o == null) { 331 openArray[i] = null; 332 } else { 333 openArray[i] = componentType.toOpenTypeData(o); 334 } 335 i++; 336 } 337 return openArray; 338 } 339 340 341 public Object toJavaTypeData(Object data) 342 throws OpenDataException, InvalidObjectException { 343 344 // If the base element type is a basic type 345 // return the data as no conversion is needed. 346 if (baseElementType.isBasicType()) { 347 return data; 348 } 349 350 final Object[] openArray = (Object[]) data; 351 final Object[] array = (Object[]) 352 Array.newInstance((Class) componentType.getJavaType(), 353 openArray.length); 354 int i = 0; 355 for (Object o : openArray) { 356 if (o == null) { 357 array[i] = null; 358 } else { 359 array[i] = componentType.toJavaTypeData(o); 360 } 361 i++; 362 } 363 return array; 364 } 365 366 } 367 368 static class GenericArrayMXBeanType extends ArrayMXBeanType { 369 final GenericArrayType gtype; 370 GenericArrayMXBeanType(GenericArrayType gat) throws OpenDataException { 371 this.gtype = gat; 372 this.componentType = getMappedType(gat.getGenericComponentType()); 373 374 StringBuilder className = new StringBuilder(); 375 Type elementType = gat; 376 int dim; 377 for (dim = 0; elementType instanceof GenericArrayType; dim++) { 378 className.append('['); 379 GenericArrayType et = (GenericArrayType) elementType; 380 elementType = et.getGenericComponentType(); 381 } 382 baseElementType = getMappedType(elementType); 383 if (elementType instanceof Class && ((Class) elementType).isPrimitive()) { 384 className = new StringBuilder(gat.toString()); 385 } else { 386 className.append('L').append(baseElementType.getTypeName()).append(';'); 387 } 388 try { 389 mappedTypeClass = Class.forName(className.toString()); 390 } catch (ClassNotFoundException e) { 391 final OpenDataException ode = 392 new OpenDataException("Cannot obtain array class"); 393 ode.initCause(e); 394 throw ode; 395 } 396 397 openType = new ArrayType<>(dim, baseElementType.getOpenType()); 398 } 399 400 Type getJavaType() { 401 return gtype; 402 } 403 404 String getName() { 405 return gtype.toString(); 406 } 407 } 408 409 // List<E> 410 // Mapped open type - Array with element of OpenType for E 411 // 412 // Data Mapping: 413 // List<E> <-> openTypeData(E)[] 414 // 415 static class ListMXBeanType extends MappedMXBeanType { 416 final ParameterizedType javaType; 417 final MappedMXBeanType paramType; 418 final String typeName; 419 420 ListMXBeanType(ParameterizedType pt) throws OpenDataException { 421 this.javaType = pt; 422 423 final Type[] argTypes = pt.getActualTypeArguments(); 424 assert(argTypes.length == 1); 425 426 if (!(argTypes[0] instanceof Class)) { 427 throw new OpenDataException("Element Type for " + pt + 428 " not supported"); 429 } 430 final Class<?> et = (Class<?>) argTypes[0]; 431 if (et.isArray()) { 432 throw new OpenDataException("Element Type for " + pt + 433 " not supported"); 434 } 435 paramType = getMappedType(et); 436 typeName = "List<" + paramType.getName() + ">"; 437 438 try { 439 mappedTypeClass = Class.forName( 440 "[L" + paramType.getTypeName() + ";"); 441 } catch (ClassNotFoundException e) { 442 final OpenDataException ode = 443 new OpenDataException("Array class not found"); 444 ode.initCause(e); 445 throw ode; 446 } 447 openType = new ArrayType<>(1, paramType.getOpenType()); 448 } 449 450 Type getJavaType() { 451 return javaType; 452 } 453 454 String getName() { 455 return typeName; 456 } 457 458 public Object toOpenTypeData(Object data) throws OpenDataException { 459 final List<Object> list = (List<Object>) data; 460 461 final Object[] openArray = (Object[]) 462 Array.newInstance(paramType.getMappedTypeClass(), 463 list.size()); 464 int i = 0; 465 for (Object o : list) { 466 openArray[i++] = paramType.toOpenTypeData(o); 467 } 468 return openArray; 469 } 470 471 public Object toJavaTypeData(Object data) 472 throws OpenDataException, InvalidObjectException { 473 474 final Object[] openArray = (Object[]) data; 475 List<Object> result = new ArrayList<>(openArray.length); 476 for (Object o : openArray) { 477 result.add(paramType.toJavaTypeData(o)); 478 } 479 return result; 480 } 481 } 482 483 private static final String KEY = "key"; 484 private static final String VALUE = "value"; 485 private static final String[] mapIndexNames = {KEY}; 486 private static final String[] mapItemNames = {KEY, VALUE}; 487 488 // Map<K,V> 489 // Mapped open type - TabularType with row type: 490 // CompositeType: 491 // "key" of openDataType(K) 492 // "value" of openDataType(V) 493 // "key" is the index name 494 // 495 // Data Mapping: 496 // Map<K,V> <-> TabularData 497 // 498 static class MapMXBeanType extends MappedMXBeanType { 499 final ParameterizedType javaType; 500 final MappedMXBeanType keyType; 501 final MappedMXBeanType valueType; 502 final String typeName; 503 504 MapMXBeanType(ParameterizedType pt) throws OpenDataException { 505 this.javaType = pt; 506 507 final Type[] argTypes = pt.getActualTypeArguments(); 508 assert(argTypes.length == 2); 509 this.keyType = getMappedType(argTypes[0]); 510 this.valueType = getMappedType(argTypes[1]); 511 512 513 // FIXME: generate typeName for generic 514 typeName = "Map<" + keyType.getName() + "," + 515 valueType.getName() + ">"; 516 final OpenType<?>[] mapItemTypes = new OpenType<?>[] { 517 keyType.getOpenType(), 518 valueType.getOpenType(), 519 }; 520 final CompositeType rowType = 521 new CompositeType(typeName, 522 typeName, 523 mapItemNames, 524 mapItemNames, 525 mapItemTypes); 526 527 openType = new TabularType(typeName, typeName, rowType, mapIndexNames); 528 mappedTypeClass = javax.management.openmbean.TabularData.class; 529 } 530 531 Type getJavaType() { 532 return javaType; 533 } 534 535 String getName() { 536 return typeName; 537 } 538 539 public Object toOpenTypeData(Object data) throws OpenDataException { 540 final Map<Object,Object> map = (Map<Object,Object>) data; 541 final TabularType tabularType = (TabularType) openType; 542 final TabularData table = new TabularDataSupport(tabularType); 543 final CompositeType rowType = tabularType.getRowType(); 544 545 for (Map.Entry<Object, Object> entry : map.entrySet()) { 546 final Object key = keyType.toOpenTypeData(entry.getKey()); 547 final Object value = valueType.toOpenTypeData(entry.getValue()); 548 final CompositeData row = 549 new CompositeDataSupport(rowType, 550 mapItemNames, 551 new Object[] {key, value}); 552 table.put(row); 553 } 554 return table; 555 } 556 557 public Object toJavaTypeData(Object data) 558 throws OpenDataException, InvalidObjectException { 559 560 final TabularData td = (TabularData) data; 561 562 Map<Object, Object> result = new HashMap<>(); 563 for (CompositeData row : (Collection<CompositeData>) td.values()) { 564 Object key = keyType.toJavaTypeData(row.get(KEY)); 565 Object value = valueType.toJavaTypeData(row.get(VALUE)); 566 result.put(key, value); 567 } 568 return result; 569 } 570 } 571 572 private static final Class<?> COMPOSITE_DATA_CLASS = 573 javax.management.openmbean.CompositeData.class; 574 575 // Classes that have a static from method 576 // Mapped open type - CompositeData 577 // 578 // Data Mapping: 579 // Classes <-> CompositeData 580 // 581 // The name and type of items for a class are identified from 582 // the getter methods. For example, a class defines a method: 583 // 584 // public FooType getFoo(); 585 // 586 // The composite data view for this class will contain one 587 // item entry for a "foo" attribute and the item type is 588 // one of the open types defined in the OpenType class that 589 // can be determined in the following manner: 590 // o If FooType is a primitive type, the item type a wrapper 591 // class for the corresponding primitive type (such as 592 // Integer, Long, Boolean, etc). 593 // o If FooType is of type CompositeData or TabularData, 594 // the item type is FooType. 595 // o If FooType is an Enum, the item type is a String and 596 // the value is the name of the enum constant. 597 // o If FooType is a class or an interface other than the above, 598 // the item type is CompositeData. The same convention 599 // can be recursively applied to the FooType class when 600 // constructing the composite data for the "foo" attribute. 601 // o If FooType is an array, the item type is an array and 602 // its element type is determined as described above. 603 // 604 static class CompositeDataMXBeanType extends MappedMXBeanType { 605 final Class<?> javaClass; 606 boolean isCompositeData = false; 607 Method fromMethod = null; 608 Method toMethod = null; 609 610 CompositeDataMXBeanType(Class<?> c) throws OpenDataException { 611 this.javaClass = c; 612 this.mappedTypeClass = COMPOSITE_DATA_CLASS; 613 614 // check if a static from method exists 615 try { 616 fromMethod = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() { 617 public Method run() throws NoSuchMethodException { 618 return javaClass.getMethod("from", COMPOSITE_DATA_CLASS); 619 } 620 }); 621 } catch (PrivilegedActionException e) { 622 // ignore NoSuchMethodException since we allow classes 623 // that has no from method to be embeded in another class. 624 } 625 626 // check if a static "toCompositeData" method exists 627 try { 628 toMethod = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() { 629 public Method run() throws NoSuchMethodException { 630 Method m = javaClass.getDeclaredMethod("toCompositeData", javaClass); 631 if (m != null 632 && CompositeData.class.isAssignableFrom(m.getReturnType()) 633 && Modifier.isStatic(m.getModifiers())) { 634 m.setAccessible(true); 635 return m; 636 } else { 637 return null; 638 } 639 } 640 }); 641 } catch (PrivilegedActionException e) { 642 // ignore NoSuchMethodException since we allow classes 643 // that has no from method to be embeded in another class. 644 } 645 646 if (COMPOSITE_DATA_CLASS.isAssignableFrom(c)) { 647 // c implements CompositeData - set openType to null 648 // defer generating the CompositeType 649 // until the object is constructed 650 this.isCompositeData = true; 651 this.openType = null; 652 } else { 653 this.isCompositeData = false; 654 655 // Make a CompositeData containing all the getters 656 final Method[] methods = 657 AccessController.doPrivileged(new PrivilegedAction<Method[]>() { 658 public Method[] run() { 659 return javaClass.getMethods(); 660 } 661 }); 662 final List<String> names = new ArrayList<>(); 663 final List<OpenType<?>> types = new ArrayList<>(); 664 665 /* Select public methods that look like "T getX()" or "boolean 666 isX()", where T is not void and X is not the empty 667 string. Exclude "Class getClass()" inherited from Object. */ 668 for (int i = 0; i < methods.length; i++) { 669 final Method method = methods[i]; 670 final String name = method.getName(); 671 final Type type = method.getGenericReturnType(); 672 final String rest; 673 if (name.startsWith("get")) { 674 rest = name.substring(3); 675 } else if (name.startsWith("is") && 676 type instanceof Class && 677 ((Class) type) == boolean.class) { 678 rest = name.substring(2); 679 } else { 680 // ignore non-getter methods 681 continue; 682 } 683 684 if (rest.equals("") || 685 method.getParameterTypes().length > 0 || 686 type == void.class || 687 rest.equals("Class")) { 688 689 // ignore non-getter methods 690 continue; 691 } 692 names.add(decapitalize(rest)); 693 types.add(toOpenType(type)); 694 } 695 696 final String[] nameArray = names.toArray(new String[0]); 697 openType = new CompositeType(c.getName(), 698 c.getName(), 699 nameArray, // field names 700 nameArray, // field descriptions 701 types.toArray(new OpenType<?>[0])); 702 } 703 } 704 705 Type getJavaType() { 706 return javaClass; 707 } 708 709 String getName() { 710 return javaClass.getName(); 711 } 712 713 public Object toOpenTypeData(Object data) throws OpenDataException { 714 if (toMethod != null) { 715 try { 716 return toMethod.invoke(null, data); 717 } catch (IllegalAccessException e) { 718 // should never reach here 719 throw new AssertionError(e); 720 } catch (InvocationTargetException e) { 721 final OpenDataException ode 722 = new OpenDataException("Failed to invoke " 723 + toMethod.getName() + " to convert " + javaClass.getName() 724 + " to CompositeData"); 725 ode.initCause(e); 726 throw ode; 727 } 728 } 729 730 if (data instanceof MemoryUsage) { 731 return MemoryUsageCompositeData.toCompositeData((MemoryUsage) data); 732 } 733 734 if (data instanceof ThreadInfo) { 735 return ThreadInfoCompositeData.toCompositeData((ThreadInfo) data); 736 } 737 738 if (data instanceof LockInfo) { 739 if (data instanceof java.lang.management.MonitorInfo) { 740 return MonitorInfoCompositeData.toCompositeData((MonitorInfo) data); 741 } 742 return LockInfoCompositeData.toCompositeData((LockInfo) data); 743 } 744 745 if (data instanceof MemoryNotificationInfo) { 746 return MemoryNotifInfoCompositeData. 747 toCompositeData((MemoryNotificationInfo) data); 748 } 749 750 if (isCompositeData) { 751 // Classes that implement CompositeData 752 // 753 // construct a new CompositeDataSupport object 754 // so that no other classes are sent over the wire 755 CompositeData cd = (CompositeData) data; 756 CompositeType ct = cd.getCompositeType(); 757 String[] itemNames = ct.keySet().toArray(new String[0]); 758 Object[] itemValues = cd.getAll(itemNames); 759 return new CompositeDataSupport(ct, itemNames, itemValues); 760 } 761 762 throw new OpenDataException(javaClass.getName() + 763 " is not supported for platform MXBeans"); 764 } 765 766 public Object toJavaTypeData(Object data) 767 throws OpenDataException, InvalidObjectException { 768 769 if (fromMethod == null) { 770 throw new AssertionError("Does not support data conversion"); 771 } 772 773 try { 774 return fromMethod.invoke(null, data); 775 } catch (IllegalAccessException e) { 776 // should never reach here 777 throw new AssertionError(e); 778 } catch (InvocationTargetException e) { 779 final OpenDataException ode = 780 new OpenDataException("Failed to invoke " + 781 fromMethod.getName() + " to convert CompositeData " + 782 " to " + javaClass.getName()); 783 ode.initCause(e); 784 throw ode; 785 } 786 } 787 } 788 789 private static class InProgress<T> extends OpenType<T> { 790 private static final String description = 791 "Marker to detect recursive type use -- internal use only!"; 792 793 InProgress() throws OpenDataException { 794 super("java.lang.String", "java.lang.String", description); 795 } 796 797 public String toString() { 798 return description; 799 } 800 801 public int hashCode() { 802 return 0; 803 } 804 805 public boolean equals(Object o) { 806 return false; 807 } 808 809 public boolean isValue(Object o) { 810 return false; 811 } 812 private static final long serialVersionUID = -3413063475064374490L; 813 } 814 private static final OpenType<?> inProgress; 815 static { 816 OpenType<?> t; 817 try { 818 t = new InProgress<>(); 819 } catch (OpenDataException e) { 820 // Should not reach here 821 throw new AssertionError(e); 822 } 823 inProgress = t; 824 } 825 826 private static final OpenType<?>[] simpleTypes = { 827 BIGDECIMAL, BIGINTEGER, BOOLEAN, BYTE, CHARACTER, DATE, 828 DOUBLE, FLOAT, INTEGER, LONG, OBJECTNAME, SHORT, STRING, 829 VOID, 830 }; 831 static { 832 try { 833 for (int i = 0; i < simpleTypes.length; i++) { 834 final OpenType<?> t = simpleTypes[i]; 835 Class<?> c; 836 try { 837 c = Class.forName(t.getClassName(), false, 838 MappedMXBeanType.class.getClassLoader()); 839 MappedMXBeanType.newBasicType(c, t); 840 } catch (ClassNotFoundException e) { 841 // the classes that these predefined types declare 842 // must exist! 843 throw new AssertionError(e); 844 } catch (OpenDataException e) { 845 throw new AssertionError(e); 846 } 847 848 if (c.getName().startsWith("java.lang.")) { 849 try { 850 final Field typeField = c.getField("TYPE"); 851 final Class<?> primitiveType = (Class<?>) typeField.get(null); 852 MappedMXBeanType.newBasicType(primitiveType, t); 853 } catch (NoSuchFieldException e) { 854 // OK: must not be a primitive wrapper 855 } catch (IllegalAccessException e) { 856 // Should not reach here 857 throw new AssertionError(e); 858 } 859 } 860 } 861 } catch (OpenDataException e) { 862 throw new AssertionError(e); 863 } 864 } 865 866 /** 867 * Utility method to take a string and convert it to normal Java variable 868 * name capitalization. This normally means converting the first 869 * character from upper case to lower case, but in the (unusual) special 870 * case when there is more than one character and both the first and 871 * second characters are upper case, we leave it alone. 872 * <p> 873 * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays 874 * as "URL". 875 * 876 * @param name The string to be decapitalized. 877 * @return The decapitalized version of the string. 878 */ 879 private static String decapitalize(String name) { 880 if (name == null || name.length() == 0) { 881 return name; 882 } 883 if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && 884 Character.isUpperCase(name.charAt(0))){ 885 return name; 886 } 887 char chars[] = name.toCharArray(); 888 chars[0] = Character.toLowerCase(chars[0]); 889 return new String(chars); 890 } 891 892 }