Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jolokia.support.jmx.JsonDynamicMBeanImpl Maven / Gradle / Ivy
package org.jolokia.support.jmx;
/*
* Copyright 2009-2013 Roland Huss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.*;
import javax.management.*;
import javax.management.openmbean.*;
import org.jolokia.server.core.service.serializer.SerializeOptions;
import org.jolokia.server.core.service.serializer.Serializer;
/**
* A {@link DynamicMBean} used to wrap an MBean registered at the Jolokia MBeanServer and translated
* non-native datatype into JSON strings.
*
* @author roland
* @since 24.01.13
*/
class JsonDynamicMBeanImpl implements DynamicMBean, MBeanRegistration {
// String type used for announcing registration infos
public static final String STRING_TYPE = String.class.getName();
// Set containing all types which are directly supported and are not converted
private static final Set DIRECT_TYPES = new HashSet();
// Serializer to use
private final Serializer serializer;
// MBeanInfo for the MBean registered at the delegate server, where complex types are replaced with strings
private MBeanInfo wrappedMBeanInfo;
// The hosting Jolokia MBean Server for accessing the serializers
private MBeanServer jolokiaMBeanServer;
// Name of this MBean
private ObjectName objectName;
// Maps holding all attribute and operations infos used during the mapping phase
private Map attributeInfoMap;
private Map> operationInfoMap;
// Options used for converting return values
private final SerializeOptions serializeOptions;
/**
* Construct a DynamicMBean wrapping an original MBean object. For attributes
* and operations all non-trivial data types are translated into Strings
* for a JSON representation
*
* @param pJolokiaMBeanServer the hosting Jolokia MBean Server
* @param pObjectName object name of this MBean
* @param pInfo the original MBeanInfo
* @param pConvertOptions options used for converting return values to JSON
*/
JsonDynamicMBeanImpl(MBeanServer pJolokiaMBeanServer, ObjectName pObjectName, MBeanInfo pInfo,
Serializer pSerializer, SerializeOptions pConvertOptions) {
jolokiaMBeanServer = pJolokiaMBeanServer;
serializer = pSerializer;
objectName = pObjectName;
serializeOptions = pConvertOptions != null ? pConvertOptions : SerializeOptions.DEFAULT;
attributeInfoMap = new HashMap();
operationInfoMap = new HashMap>();
wrappedMBeanInfo = getWrappedInfo(pInfo);
}
/** {@inheritDoc} */
@SuppressWarnings("PMD.PreserveStackTrace")
public Object getAttribute(String pAttribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
try {
if (!attributeInfoMap.containsKey(pAttribute)) {
return jolokiaMBeanServer.getAttribute(objectName, pAttribute);
} else {
return toJson(jolokiaMBeanServer.getAttribute(objectName, pAttribute));
}
} catch (InstanceNotFoundException e) {
AttributeNotFoundException exp = new AttributeNotFoundException("MBean " + objectName + " not found for attribute " + pAttribute);
exp.initCause(e);
throw exp;
}
}
/** {@inheritDoc} */
@SuppressWarnings("PMD.PreserveStackTrace")
public void setAttribute(Attribute pAttribute)
throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
try {
if (!attributeInfoMap.containsKey(pAttribute.getName())) {
jolokiaMBeanServer.setAttribute(objectName, pAttribute);
} else {
String name = pAttribute.getName();
MBeanAttributeInfo info = attributeInfoMap.get(name);
Object value;
if (info instanceof OpenMBeanAttributeInfo) {
value = fromJson(((OpenMBeanAttributeInfo) info).getOpenType(), (String) pAttribute.getValue());
} else {
value = fromJson(info.getType(), (String) pAttribute.getValue());
}
Attribute attr = new Attribute(name, value);
jolokiaMBeanServer.setAttribute(objectName, attr);
}
} catch (InstanceNotFoundException e) {
AttributeNotFoundException exp = new AttributeNotFoundException("MBean " + objectName + " not found for attribute " + pAttribute);
exp.initCause(e);
throw exp;
}
}
/** {@inheritDoc} */
public Object invoke(String pOperation, Object[] pParams, String[] pSignature)
throws MBeanException, ReflectionException {
OperationMapInfo opMapInfo = getOperationMapInfo(pOperation, pSignature);
try {
if (opMapInfo == null) {
return jolokiaMBeanServer.invoke(objectName, pOperation, pParams, pSignature);
} else {
return mapAndInvoke(pOperation, pParams, pSignature, opMapInfo);
}
} catch (InstanceNotFoundException e) {
// Should not happen, since the Jolokia MBeanServer and the delegate MBeanServer this bean is registered
// at are in sync.
throw new IllegalStateException("Internal: Could find MBean " + objectName +
" on Jolokia MBeanServer. Should be in sync",e);
}
}
/** {@inheritDoc} */
public AttributeList getAttributes(String[] attributes /* cannot be null */) {
final AttributeList ret = new AttributeList(attributes.length);
for (String attrName : attributes) {
try {
final Object attrValue = getAttribute(attrName);
ret.add(new Attribute(attrName, attrValue));
} catch (Exception e) {
// Ignore this attribute. As specified in the JMX Spec
}
}
return ret;
}
/** {@inheritDoc} */
@edu.umd.cs.findbugs.annotations.SuppressWarnings({"REC_CATCH_EXCEPTION","DE_MIGHT_IGNORE"})
public AttributeList setAttributes(AttributeList attributes) {
final AttributeList ret = new AttributeList(attributes.size());
for (Object o : attributes) {
Attribute attr = (Attribute) o;
try {
setAttribute(attr);
ret.add(new Attribute(attr.getName(), getAttribute(attr.getName())));
} catch (Exception e) {
// Attribute is not included in returned list. The spec says so
}
}
return ret;
}
/** {@inheritDoc} */
public MBeanInfo getMBeanInfo() {
return wrappedMBeanInfo;
}
// =================================================================================================
// Delegate serialization/deserialization the Jolokia MBeanServer
private Object toJson(Object pValue) {
try {
Object ret = serializer.serialize(pValue, null, serializeOptions);
return ret.toString();
} catch (AttributeNotFoundException exp) {
// Cannot happen, since we dont use a path
return "";
}
}
private Object fromJson(String pType, String pValue) {
return serializer.deserialize(pType, pValue);
}
private Object fromJson(OpenType> pType, String pValue) {
return serializer.deserializeOpenType(pType, pValue);
}
// Map the parameters and the return value if required
private Object mapAndInvoke(String pOperation, Object[] pParams, String[] pSignature, OperationMapInfo pOpMapInfo)
throws InstanceNotFoundException, MBeanException, ReflectionException {
// Map parameters
Object realParams[] = new Object[pSignature.length];
String realSignature[] = new String[pSignature.length];
for (int i = 0; i < pSignature.length; i++) {
if (pOpMapInfo.isParamMapped(i)) {
String origType = pOpMapInfo.getOriginalType(i);
OpenType openType = pOpMapInfo.getOpenMBeanType(i);
if (openType != null) {
realParams[i] = fromJson(openType, (String) pParams[i]);
} else {
realParams[i] = fromJson(origType, (String) pParams[i]);
}
realSignature[i] = origType;
} else {
realParams[i] = pParams[i];
realSignature[i] = pSignature[i];
}
}
Object ret = jolokiaMBeanServer.invoke(objectName, pOperation, realParams, realSignature);
return pOpMapInfo.isRetTypeMapped() ? toJson(ret) : ret;
}
// Lookup, whether a mapping is required for this call
private OperationMapInfo getOperationMapInfo(String pOperation, String[] pSignature) {
List opMapInfoList = operationInfoMap.get(pOperation);
OperationMapInfo opMapInfo = null;
if (opMapInfoList != null) {
for (OperationMapInfo i : opMapInfoList) {
if (i.matchSignature(pSignature)) {
opMapInfo = i;
break;
}
}
}
return opMapInfo;
}
// Check for all type which should *not* be mapped
private boolean isDirectlySupported(String pType) {
return DIRECT_TYPES.contains(pType);
}
// Wrap the given MBeanInfo, modified for translated signatures
private MBeanInfo getWrappedInfo(MBeanInfo pMBeanInfo) {
MBeanAttributeInfo[] attrInfo = getWrappedAttributeInfo(pMBeanInfo);
MBeanOperationInfo[] opInfo = getWrappedOperationInfo(pMBeanInfo);
return new MBeanInfo(pMBeanInfo.getClassName(),
pMBeanInfo.getDescription(),
attrInfo,
null, /* We dont allow construction of this MBean, hence null-constructors */
opInfo,
pMBeanInfo.getNotifications()
);
}
private MBeanAttributeInfo[] getWrappedAttributeInfo(MBeanInfo pMBeanInfo) {
MBeanAttributeInfo origAttrInfo[] = pMBeanInfo.getAttributes();
MBeanAttributeInfo attrInfo[] = new MBeanAttributeInfo[origAttrInfo.length];
for (int i = 0; i < origAttrInfo.length; i++) {
MBeanAttributeInfo aInfo = origAttrInfo[i];
String clazz = aInfo.getType();
String attrType;
if (isDirectlySupported(clazz)) {
attrType = clazz;
} else {
attrType = STRING_TYPE;
// Remember type for later conversion when setting an attribute
attributeInfoMap.put(aInfo.getName(), aInfo);
}
attrInfo[i] =
new MBeanAttributeInfo(
aInfo.getName(),
attrType,
aInfo.getDescription(),
aInfo.isReadable(),
aInfo.isWritable(),
aInfo.isIs(),
aInfo.getDescriptor());
}
return attrInfo;
}
private MBeanOperationInfo[] getWrappedOperationInfo(MBeanInfo pMBeanInfo) {
MBeanOperationInfo origOpInfo[] = pMBeanInfo.getOperations();
MBeanOperationInfo opInfo[] = new MBeanOperationInfo[origOpInfo.length];
for (int i = 0; i < origOpInfo.length; i++) {
MBeanOperationInfo oInfo = origOpInfo[i];
String retType;
OperationMapInfo opMapInfo;
if (isDirectlySupported(oInfo.getReturnType())) {
retType = oInfo.getReturnType();
opMapInfo = new OperationMapInfo(oInfo, false);
} else {
retType = STRING_TYPE;
opMapInfo = new OperationMapInfo(oInfo, true);
}
MBeanParameterInfo[] paramInfo = getWrappedParameterInfo(oInfo, opMapInfo);
// Remember that we mapped this operation info
if (opMapInfo.containsMapping()) {
String name = oInfo.getName();
List infos = operationInfoMap.get(name);
if (infos == null) {
infos = new ArrayList();
operationInfoMap.put(name, infos);
}
infos.add(opMapInfo);
}
opInfo[i] =
new MBeanOperationInfo(
oInfo.getName(),
oInfo.getDescription(),
paramInfo,
retType,
oInfo.getImpact(),
oInfo.getDescriptor()
);
}
return opInfo;
}
private MBeanParameterInfo[] getWrappedParameterInfo(MBeanOperationInfo pOInfo, OperationMapInfo pMapInfo) {
MBeanParameterInfo origParamInfo[] = pOInfo.getSignature();
MBeanParameterInfo paramInfo[] = new MBeanParameterInfo[origParamInfo.length];
for (int j = 0; j < origParamInfo.length; j++) {
MBeanParameterInfo pInfo = origParamInfo[j];
String pType;
if (isDirectlySupported(pInfo.getType())) {
pType = pInfo.getType();
pMapInfo.pushParamTypes(pType, null, null);
} else {
pType = STRING_TYPE;
if (pInfo instanceof OpenMBeanParameterInfo) {
pMapInfo.pushParamTypes(STRING_TYPE, pInfo.getType(), ((OpenMBeanParameterInfo) pInfo).getOpenType());
} else {
pMapInfo.pushParamTypes(STRING_TYPE, pInfo.getType(), null);
}
}
paramInfo[j] = new MBeanParameterInfo(
pInfo.getName(),
pType,
pInfo.getDescription(),
pInfo.getDescriptor()
);
}
return paramInfo;
}
// ======================================================
// Lifecycle method for cleaning up
/** {@inheritDoc} */
public ObjectName preRegister(MBeanServer server, ObjectName name) {
return name;
}
/** {@inheritDoc} */
public void postRegister(Boolean registrationDone) {
}
/** {@inheritDoc} */
public void preDeregister() {
}
// Cleanup, release all references
/** {@inheritDoc} */
public void postDeregister() {
jolokiaMBeanServer = null;
wrappedMBeanInfo = null;
objectName = null;
attributeInfoMap = null;
operationInfoMap = null;
}
// ==========================================
private static final class OperationMapInfo {
private boolean retTypeMapped;
private String[] signature;
private String[] origTypes;
private OpenType[] openMBeanTypes;
private int idx;
private boolean paramMapped;
private OperationMapInfo(MBeanOperationInfo pInfo, boolean pRetTypeMapped) {
retTypeMapped = pRetTypeMapped;
origTypes = new String[pInfo.getSignature().length];
openMBeanTypes = new OpenType[pInfo.getSignature().length];
signature = new String[pInfo.getSignature().length];
idx = 0;
paramMapped = false;
}
private void pushParamTypes(String pNewType, String pOrigType, OpenType pOpenType) {
signature[idx] = pNewType;
origTypes[idx] = pOrigType;
openMBeanTypes[idx] = pOpenType;
idx++;
if (pOrigType != null || pOpenType != null) {
paramMapped = true;
}
}
private boolean isParamMapped(int pIdx) {
return origTypes[pIdx] != null;
}
private String getOriginalType(int pIdx) {
return origTypes[pIdx];
}
private OpenType getOpenMBeanType(int pIdx) {
return openMBeanTypes[pIdx];
}
private boolean isRetTypeMapped() {
return retTypeMapped;
}
private boolean containsMapping() {
return retTypeMapped || paramMapped;
}
private boolean matchSignature(String pSignature[]) {
return Arrays.equals(signature, pSignature);
}
}
// =======================================================
// Static initialized for filling in the set for all directly used types
static {
Collections.addAll(DIRECT_TYPES,
Byte.class.getName(), "byte",
Integer.class.getName(), "int",
Long.class.getName(), "long",
Short.class.getName(), "short",
Double.class.getName(), "double",
Float.class.getName(), "float",
Boolean.class.getName(), "boolean",
Character.class.getName(), "char",
String.class.getName());
}
}