/*
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.management;
import java.lang.management.MemoryUsage;
import java.lang.management.MemoryNotificationInfo;
import java.lang.management.MonitorInfo;
import java.lang.management.LockInfo;
import java.lang.management.ThreadInfo;
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.io.InvalidObjectException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.management.openmbean.*;
import static javax.management.openmbean.SimpleType.*;
/**
* A mapped mxbean type maps a Java type to an open type.
* Only the following Java types are mappable
* (currently required by the platform MXBeans):
*
*
Primitive types
*
Wrapper classes such java.lang.Integer, etc
*
Classes with only getter methods and with a static "from" method
* that takes a CompositeData argument.
*
{@code E[]} where {@code E} is a type of 1-4 (can be multi-dimensional array)
*
{@code List} where E is a type of 1-3
*
{@code Map} where {@code K} and {@code V} are a type of 1-4
*
*
* OpenDataException will be thrown if a Java type is not supported.
*/
// Suppress unchecked cast warnings at line 442, 523 and 546
// Suppress unchecked calls at line 235, 284, 380 and 430.
@SuppressWarnings("unchecked")
public abstract class MappedMXBeanType {
private static final WeakHashMap convertedTypes =
new WeakHashMap<>();
boolean isBasicType = false;
OpenType> openType = inProgress;
Class> mappedTypeClass;
static synchronized MappedMXBeanType newMappedType(Type javaType)
throws OpenDataException {
MappedMXBeanType mt = null;
if (javaType instanceof Class) {
final Class> c = (Class>) javaType;
if (c.isEnum()) {
mt = new EnumMXBeanType(c);
} else if (c.isArray()) {
mt = new ArrayMXBeanType(c);
} else {
mt = new CompositeDataMXBeanType(c);
}
} else if (javaType instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) javaType;
final Type rawType = pt.getRawType();
if (rawType instanceof Class) {
final Class> rc = (Class>) rawType;
if (rc == List.class) {
mt = new ListMXBeanType(pt);
} else if (rc == Map.class) {
mt = new MapMXBeanType(pt);
}
}
} else if (javaType instanceof GenericArrayType) {
final GenericArrayType t = (GenericArrayType) javaType;
mt = new GenericArrayMXBeanType(t);
}
// No open type mapped for the javaType
if (mt == null) {
throw new OpenDataException(javaType +
" is not a supported MXBean type.");
}
convertedTypes.put(javaType, mt);
return mt;
}
// basic types do not require data mapping
static synchronized MappedMXBeanType newBasicType(Class> c, OpenType> ot)
throws OpenDataException {
MappedMXBeanType mt = new BasicMXBeanType(c, ot);
convertedTypes.put(c, mt);
return mt;
}
public static synchronized MappedMXBeanType getMappedType(Type t)
throws OpenDataException {
MappedMXBeanType mt = convertedTypes.get(t);
if (mt == null) {
mt = newMappedType(t);
}
if (mt.getOpenType() instanceof InProgress) {
throw new OpenDataException("Recursive data structure");
}
return mt;
}
// Convert a class to an OpenType
public static synchronized OpenType> toOpenType(Type t)
throws OpenDataException {
MappedMXBeanType mt = getMappedType(t);
return mt.getOpenType();
}
public static Object toJavaTypeData(Object openData, Type t)
throws OpenDataException, InvalidObjectException {
if (openData == null) {
return null;
}
MappedMXBeanType mt = getMappedType(t);
return mt.toJavaTypeData(openData);
}
public static Object toOpenTypeData(Object data, Type t)
throws OpenDataException {
if (data == null) {
return null;
}
MappedMXBeanType mt = getMappedType(t);
return mt.toOpenTypeData(data);
}
// Return the mapped open type
public OpenType> getOpenType() {
return openType;
}
boolean isBasicType() {
return isBasicType;
}
// Return the type name of the mapped open type
// For primitive types, the type name is the same as the javaType
// but the mapped open type is the wrapper class
String getTypeName() {
return getMappedTypeClass().getName();
}
// Return the mapped open type
Class> getMappedTypeClass() {
return mappedTypeClass;
}
abstract Type getJavaType();
// return name of the class or the generic type
abstract String getName();
public abstract Object toOpenTypeData(Object javaTypeData)
throws OpenDataException;
public abstract Object toJavaTypeData(Object openTypeData)
throws OpenDataException, InvalidObjectException;
// Basic Types - Classes that do not require data conversion
// including primitive types and all SimpleType
//
// Mapped open type: SimpleType for corresponding basic type
//
// Data Mapping:
// T <-> T (no conversion)
//
static class BasicMXBeanType extends MappedMXBeanType {
final Class> basicType;
BasicMXBeanType(Class> c, OpenType> openType) {
this.basicType = c;
this.openType = openType;
this.mappedTypeClass = c;
this.isBasicType = true;
}
Type getJavaType() {
return basicType;
}
String getName() {
return basicType.getName();
}
public Object toOpenTypeData(Object data) throws OpenDataException {
return data;
}
public Object toJavaTypeData(Object data)
throws OpenDataException, InvalidObjectException {
return data;
}
}
// Enum subclasses
// Mapped open type - String
//
// Data Mapping:
// Enum <-> enum's name
//
static class EnumMXBeanType extends MappedMXBeanType {
@SuppressWarnings("rawtypes")
final Class enumClass;
EnumMXBeanType(Class> c) {
this.enumClass = c;
this.openType = STRING;
this.mappedTypeClass = String.class;
}
Type getJavaType() {
return enumClass;
}
String getName() {
return enumClass.getName();
}
public Object toOpenTypeData(Object data) throws OpenDataException {
return ((Enum) data).name();
}
public Object toJavaTypeData(Object data)
throws OpenDataException, InvalidObjectException {
try {
return Enum.valueOf(enumClass, (String) data);
} catch (IllegalArgumentException e) {
// missing enum constants
final InvalidObjectException ioe =
new InvalidObjectException("Enum constant named " +
(String) data + " is missing");
ioe.initCause(e);
throw ioe;
}
}
}
// Array E[]
// Mapped open type - Array with element of OpenType for E
//
// Data Mapping:
// E[] <-> openTypeData(E)[]
//
static class ArrayMXBeanType extends MappedMXBeanType {
final Class> arrayClass;
protected MappedMXBeanType componentType;
protected MappedMXBeanType baseElementType;
ArrayMXBeanType(Class> c) throws OpenDataException {
this.arrayClass = c;
this.componentType = getMappedType(c.getComponentType());
StringBuilder className = new StringBuilder();
Class> et = c;
int dim;
for (dim = 0; et.isArray(); dim++) {
className.append('[');
et = et.getComponentType();
}
baseElementType = getMappedType(et);
if (et.isPrimitive()) {
className = new StringBuilder(c.getName());
} else {
className.append('L').append(baseElementType.getTypeName()).append(';');
}
try {
mappedTypeClass = Class.forName(className.toString());
} catch (ClassNotFoundException e) {
final OpenDataException ode =
new OpenDataException("Cannot obtain array class");
ode.initCause(e);
throw ode;
}
openType = new ArrayType<>(dim, baseElementType.getOpenType());
}
protected ArrayMXBeanType() {
arrayClass = null;
};
Type getJavaType() {
return arrayClass;
}
String getName() {
return arrayClass.getName();
}
public Object toOpenTypeData(Object data) throws OpenDataException {
// If the base element type is a basic type
// return the data as no conversion is needed.
// Primitive types are not converted to wrappers.
if (baseElementType.isBasicType()) {
return data;
}
final Object[] array = (Object[]) data;
final Object[] openArray = (Object[])
Array.newInstance(componentType.getMappedTypeClass(),
array.length);
int i = 0;
for (Object o : array) {
if (o == null) {
openArray[i] = null;
} else {
openArray[i] = componentType.toOpenTypeData(o);
}
i++;
}
return openArray;
}
public Object toJavaTypeData(Object data)
throws OpenDataException, InvalidObjectException {
// If the base element type is a basic type
// return the data as no conversion is needed.
if (baseElementType.isBasicType()) {
return data;
}
final Object[] openArray = (Object[]) data;
final Object[] array = (Object[])
Array.newInstance((Class) componentType.getJavaType(),
openArray.length);
int i = 0;
for (Object o : openArray) {
if (o == null) {
array[i] = null;
} else {
array[i] = componentType.toJavaTypeData(o);
}
i++;
}
return array;
}
}
static class GenericArrayMXBeanType extends ArrayMXBeanType {
final GenericArrayType gtype;
GenericArrayMXBeanType(GenericArrayType gat) throws OpenDataException {
this.gtype = gat;
this.componentType = getMappedType(gat.getGenericComponentType());
StringBuilder className = new StringBuilder();
Type elementType = gat;
int dim;
for (dim = 0; elementType instanceof GenericArrayType; dim++) {
className.append('[');
GenericArrayType et = (GenericArrayType) elementType;
elementType = et.getGenericComponentType();
}
baseElementType = getMappedType(elementType);
if (elementType instanceof Class && ((Class) elementType).isPrimitive()) {
className = new StringBuilder(gat.toString());
} else {
className.append('L').append(baseElementType.getTypeName()).append(';');
}
try {
mappedTypeClass = Class.forName(className.toString());
} catch (ClassNotFoundException e) {
final OpenDataException ode =
new OpenDataException("Cannot obtain array class");
ode.initCause(e);
throw ode;
}
openType = new ArrayType<>(dim, baseElementType.getOpenType());
}
Type getJavaType() {
return gtype;
}
String getName() {
return gtype.toString();
}
}
// List
// Mapped open type - Array with element of OpenType for E
//
// Data Mapping:
// List <-> openTypeData(E)[]
//
static class ListMXBeanType extends MappedMXBeanType {
final ParameterizedType javaType;
final MappedMXBeanType paramType;
final String typeName;
ListMXBeanType(ParameterizedType pt) throws OpenDataException {
this.javaType = pt;
final Type[] argTypes = pt.getActualTypeArguments();
assert(argTypes.length == 1);
if (!(argTypes[0] instanceof Class)) {
throw new OpenDataException("Element Type for " + pt +
" not supported");
}
final Class> et = (Class>) argTypes[0];
if (et.isArray()) {
throw new OpenDataException("Element Type for " + pt +
" not supported");
}
paramType = getMappedType(et);
typeName = "List<" + paramType.getName() + ">";
try {
mappedTypeClass = Class.forName(
"[L" + paramType.getTypeName() + ";");
} catch (ClassNotFoundException e) {
final OpenDataException ode =
new OpenDataException("Array class not found");
ode.initCause(e);
throw ode;
}
openType = new ArrayType<>(1, paramType.getOpenType());
}
Type getJavaType() {
return javaType;
}
String getName() {
return typeName;
}
public Object toOpenTypeData(Object data) throws OpenDataException {
final List