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