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 
newMappedType(Type javaType)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
newBasicType(Class<?> c, OpenType<?> ot)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 
getMappedType(Type t)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
toOpenType(Type t)130     public static synchronized OpenType<?> toOpenType(Type t)
131             throws OpenDataException {
132         MappedMXBeanType mt = getMappedType(t);
133         return mt.getOpenType();
134     }
135 
toJavaTypeData(Object openData, Type t)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 
toOpenTypeData(Object data, Type t)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
getOpenType()155     public OpenType<?> getOpenType() {
156         return openType;
157     }
158 
isBasicType()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
getTypeName()166     String getTypeName() {
167         return getMappedTypeClass().getName();
168     }
169 
170     // Return the mapped open type
getMappedTypeClass()171     Class<?> getMappedTypeClass() {
172         return mappedTypeClass;
173     }
174 
getJavaType()175     abstract Type getJavaType();
176 
177     // return name of the class or the generic type
getName()178     abstract String getName();
179 
toOpenTypeData(Object javaTypeData)180     public abstract Object toOpenTypeData(Object javaTypeData)
181         throws OpenDataException;
182 
toJavaTypeData(Object openTypeData)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;
BasicMXBeanType(Class<?> c, OpenType<?> openType)196         BasicMXBeanType(Class<?> c, OpenType<?> openType) {
197             this.basicType = c;
198             this.openType = openType;
199             this.mappedTypeClass = c;
200             this.isBasicType = true;
201         }
202 
getJavaType()203         Type getJavaType() {
204             return basicType;
205         }
206 
getName()207         String getName() {
208             return basicType.getName();
209         }
210 
toOpenTypeData(Object data)211         public Object toOpenTypeData(Object data) throws OpenDataException {
212             return data;
213         }
214 
toJavaTypeData(Object data)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;
EnumMXBeanType(Class<?> c)232         EnumMXBeanType(Class<?> c) {
233             this.enumClass = c;
234             this.openType = STRING;
235             this.mappedTypeClass = String.class;
236         }
237 
getJavaType()238         Type getJavaType() {
239             return enumClass;
240         }
241 
getName()242         String getName() {
243             return enumClass.getName();
244         }
245 
toOpenTypeData(Object data)246         public Object toOpenTypeData(Object data) throws OpenDataException {
247             return ((Enum) data).name();
248         }
249 
toJavaTypeData(Object data)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 
ArrayMXBeanType(Class<?> c)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 
ArrayMXBeanType()306         protected ArrayMXBeanType() {
307             arrayClass = null;
308         };
309 
getJavaType()310         Type getJavaType() {
311             return arrayClass;
312         }
313 
getName()314         String getName() {
315             return arrayClass.getName();
316         }
317 
toOpenTypeData(Object data)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 
toJavaTypeData(Object data)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;
GenericArrayMXBeanType(GenericArrayType gat)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 
getJavaType()402         Type getJavaType() {
403             return gtype;
404         }
405 
getName()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 
ListMXBeanType(ParameterizedType pt)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 
getJavaType()452         Type getJavaType() {
453             return javaType;
454         }
455 
getName()456         String getName() {
457             return typeName;
458         }
459 
toOpenTypeData(Object data)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 
toJavaTypeData(Object data)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 
MapMXBeanType(ParameterizedType pt)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 
getJavaType()533         Type getJavaType() {
534             return javaType;
535         }
536 
getName()537         String getName() {
538             return typeName;
539         }
540 
toOpenTypeData(Object data)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 
toJavaTypeData(Object data)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 
CompositeDataMXBeanType(Class<?> c)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             if (COMPOSITE_DATA_CLASS.isAssignableFrom(c)) {
629                 // c implements CompositeData - set openType to null
630                 // defer generating the CompositeType
631                 // until the object is constructed
632                 this.isCompositeData = true;
633                 this.openType = null;
634             } else {
635                 this.isCompositeData = false;
636 
637                 // Make a CompositeData containing all the getters
638                 final Method[] methods =
639                     AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
640                             public Method[] run() {
641                                 return javaClass.getMethods();
642                             }
643                         });
644                 final List<String> names = new ArrayList<>();
645                 final List<OpenType<?>> types = new ArrayList<>();
646 
647                 /* Select public methods that look like "T getX()" or "boolean
648                  isX()", where T is not void and X is not the empty
649                  string.  Exclude "Class getClass()" inherited from Object.  */
650                 for (int i = 0; i < methods.length; i++) {
651                     final Method method = methods[i];
652                     final String name = method.getName();
653                     final Type type = method.getGenericReturnType();
654                     final String rest;
655                     if (name.startsWith("get")) {
656                         rest = name.substring(3);
657                     } else if (name.startsWith("is") &&
658                                type instanceof Class &&
659                                ((Class) type) == boolean.class) {
660                         rest = name.substring(2);
661                     } else {
662                         // ignore non-getter methods
663                         continue;
664                     }
665 
666                     if (rest.equals("") ||
667                         method.getParameterTypes().length > 0 ||
668                         type == void.class ||
669                         rest.equals("Class")) {
670 
671                         // ignore non-getter methods
672                         continue;
673                     }
674                     names.add(decapitalize(rest));
675                     types.add(toOpenType(type));
676                 }
677 
678                 final String[] nameArray = names.toArray(new String[0]);
679                 openType = new CompositeType(c.getName(),
680                         c.getName(),
681                         nameArray, // field names
682                         nameArray, // field descriptions
683                         types.toArray(new OpenType<?>[0]));
684             }
685         }
686 
getJavaType()687         Type getJavaType() {
688             return javaClass;
689         }
690 
getName()691         String getName() {
692             return javaClass.getName();
693         }
694 
toOpenTypeData(Object data)695         public Object toOpenTypeData(Object data) throws OpenDataException {
696             if (toMethod != null) {
697                 try {
698                     return toMethod.invoke(null, data);
699                 } catch (IllegalAccessException e) {
700                     // should never reach here
701                     throw new AssertionError(e);
702                 } catch (InvocationTargetException e) {
703                     final OpenDataException ode
704                             = new OpenDataException("Failed to invoke "
705                                     + toMethod.getName() + " to convert " + javaClass.getName()
706                                     + " to CompositeData");
707                     ode.initCause(e);
708                     throw ode;
709                 }
710             }
711 
712             if (data instanceof MemoryUsage) {
713                 return MemoryUsageCompositeData.toCompositeData((MemoryUsage) data);
714             }
715 
716             if (data instanceof ThreadInfo) {
717                 return ThreadInfoCompositeData.toCompositeData((ThreadInfo) data);
718             }
719 
720             if (data instanceof LockInfo) {
721                 if (data instanceof java.lang.management.MonitorInfo) {
722                     return MonitorInfoCompositeData.toCompositeData((MonitorInfo) data);
723                 }
724                 return LockInfoCompositeData.toCompositeData((LockInfo) data);
725             }
726 
727             if (data instanceof MemoryNotificationInfo) {
728                 return MemoryNotifInfoCompositeData.
729                     toCompositeData((MemoryNotificationInfo) data);
730             }
731 
732             if (isCompositeData) {
733                 // Classes that implement CompositeData
734                 //
735                 // construct a new CompositeDataSupport object
736                 // so that no other classes are sent over the wire
737                 CompositeData cd = (CompositeData) data;
738                 CompositeType ct = cd.getCompositeType();
739                 String[] itemNames = ct.keySet().toArray(new String[0]);
740                 Object[] itemValues = cd.getAll(itemNames);
741                 return new CompositeDataSupport(ct, itemNames, itemValues);
742             }
743 
744             throw new OpenDataException(javaClass.getName() +
745                 " is not supported for platform MXBeans");
746         }
747 
toJavaTypeData(Object data)748         public Object toJavaTypeData(Object data)
749             throws OpenDataException, InvalidObjectException {
750 
751             if (fromMethod == null) {
752                 throw new AssertionError("Does not support data conversion");
753             }
754 
755             try {
756                 return fromMethod.invoke(null, data);
757             } catch (IllegalAccessException e) {
758                 // should never reach here
759                 throw new AssertionError(e);
760             } catch (InvocationTargetException e) {
761                 final OpenDataException ode =
762                     new OpenDataException("Failed to invoke " +
763                         fromMethod.getName() + " to convert CompositeData " +
764                         " to " + javaClass.getName());
765                 ode.initCause(e);
766                 throw ode;
767             }
768         }
769     }
770 
771     private static class InProgress<T> extends OpenType<T> {
772         private static final String description =
773                   "Marker to detect recursive type use -- internal use only!";
774 
InProgress()775         InProgress() throws OpenDataException {
776             super("java.lang.String", "java.lang.String", description);
777         }
778 
toString()779         public String toString() {
780             return description;
781         }
782 
hashCode()783         public int hashCode() {
784             return 0;
785         }
786 
equals(Object o)787         public boolean equals(Object o) {
788             return false;
789         }
790 
isValue(Object o)791         public boolean isValue(Object o) {
792             return false;
793         }
794         private static final long serialVersionUID = -3413063475064374490L;
795     }
796     private static final OpenType<?> inProgress;
797     static {
798         OpenType<?> t;
799         try {
800             t = new InProgress<>();
801         } catch (OpenDataException e) {
802             // Should not reach here
803             throw new AssertionError(e);
804         }
805         inProgress = t;
806     }
807 
808     private static final OpenType<?>[] simpleTypes = {
809         BIGDECIMAL, BIGINTEGER, BOOLEAN, BYTE, CHARACTER, DATE,
810         DOUBLE, FLOAT, INTEGER, LONG, OBJECTNAME, SHORT, STRING,
811         VOID,
812     };
813     static {
814         try {
815             for (int i = 0; i < simpleTypes.length; i++) {
816                 final OpenType<?> t = simpleTypes[i];
817                 Class<?> c;
818                 try {
819                     c = Class.forName(t.getClassName(), false,
820                                       MappedMXBeanType.class.getClassLoader());
MappedMXBeanType.newBasicType(c, t)821                     MappedMXBeanType.newBasicType(c, t);
822                 } catch (ClassNotFoundException e) {
823                     // the classes that these predefined types declare
824                     // must exist!
825                     throw new AssertionError(e);
826                 } catch (OpenDataException e) {
827                     throw new AssertionError(e);
828                 }
829 
830                 if (c.getName().startsWith("java.lang.")) {
831                     try {
832                         final Field typeField = c.getField("TYPE");
833                         final Class<?> primitiveType = (Class<?>) typeField.get(null);
MappedMXBeanType.newBasicType(primitiveType, t)834                         MappedMXBeanType.newBasicType(primitiveType, t);
835                     } catch (NoSuchFieldException e) {
836                         // OK: must not be a primitive wrapper
837                     } catch (IllegalAccessException e) {
838                         // Should not reach here
839                        throw new AssertionError(e);
840                     }
841                 }
842             }
843         } catch (OpenDataException e) {
844             throw new AssertionError(e);
845         }
846     }
847 
848     /**
849      * Utility method to take a string and convert it to normal Java variable
850      * name capitalization.  This normally means converting the first
851      * character from upper case to lower case, but in the (unusual) special
852      * case when there is more than one character and both the first and
853      * second characters are upper case, we leave it alone.
854      * <p>
855      * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
856      * as "URL".
857      *
858      * @param  name The string to be decapitalized.
859      * @return  The decapitalized version of the string.
860      */
decapitalize(String name)861     private static String decapitalize(String name) {
862         if (name == null || name.length() == 0) {
863             return name;
864         }
865         if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
866                         Character.isUpperCase(name.charAt(0))){
867             return name;
868         }
869         char chars[] = name.toCharArray();
870         chars[0] = Character.toLowerCase(chars[0]);
871         return new String(chars);
872     }
873 
874 }
875