com.gemstone.gemfire.management.internal.MXBeanProxyInvocationHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
SnappyData store based off Pivotal GemFireXD
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.management.internal;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.ObjectName;
/**
* This proxy handler handles all the method call invoked on an MXBean It
* follows same route as MBeanProxyInvocationHandler Only difference is after
* obtaining the result it transforms the open type to the actual java type
*
* @author rishim
*
*/
public class MXBeanProxyInvocationHandler {
private ObjectName objectName;
private MBeanProxyInvocationHandler proxyHandler;
private final Map methodHandlerMap = OpenTypeUtil
.newMap();
// private LogWriterI18n logger;
public MXBeanProxyInvocationHandler(ObjectName objectName,
Class> mxbeanInterface, MBeanProxyInvocationHandler proxyHandler)
throws Exception {
if (mxbeanInterface == null)
throw new IllegalArgumentException("Null parameter");
this.objectName = objectName;
this.proxyHandler = proxyHandler;
// this.logger = InternalDistributedSystem.getLoggerI18n();
this.initHandlers(mxbeanInterface);
}
// Introspect the mbeanInterface and initialize this object's maps.
//
private void initHandlers(Class> mbeanInterface) throws Exception {
final Method[] methodArray = mbeanInterface.getMethods();
final List methods = eliminateCovariantMethods(methodArray);
for (Method m : methods) {
String name = m.getName();
String attrName = "";
if (name.startsWith("get")) {
attrName = name.substring(3);
} else if (name.startsWith("is") && m.getReturnType() == boolean.class) {
attrName = name.substring(2);
}
if (attrName.length() != 0 && m.getParameterTypes().length == 0
&& m.getReturnType() != void.class) { // For Getters
methodHandlerMap
.put(m, new GetterHandler(attrName, new OpenMethod(m)));
} else if (name.startsWith("set") && name.length() > 3
&& m.getParameterTypes().length == 1
&& m.getReturnType() == void.class) { // For Setteres
methodHandlerMap
.put(m, new SetterHandler(attrName, new OpenMethod(m)));
} else {
methodHandlerMap.put(m, new OpHandler(attrName, new OpenMethod(m)));
}
}
}
/**
* Eliminate methods that are overridden with a covariant return type.
* Reflection will return both the original and the overriding method but we
* need only the overriding one is of interest
*
* @param methodArray methods for elimination of covariant return types
* @return the method after eliminating covariant menthods
*/
static List eliminateCovariantMethods(Method[] methodArray) {
final int len = methodArray.length;
final Method[] sorted = methodArray.clone();
Arrays.sort(sorted, MethodOrder.instance);
final Set overridden = OpenTypeUtil.newSet();
for (int i = 1; i < len; i++) {
final Method m0 = sorted[i - 1];
final Method m1 = sorted[i];
if (!m0.getName().equals(m1.getName()))
continue;
if (Arrays.equals(m0.getParameterTypes(), m1.getParameterTypes())) {
overridden.add(m0);
}
}
final List methods = OpenTypeUtil.newList(Arrays
.asList(methodArray));
methods.removeAll(overridden);
return methods;
}
/**
* A comparator that defines a total order so that methods have the same name
* and identical signatures appear next to each others. The methods are sorted
* in such a way that methods which override each other will sit next to each
* other, with the overridden method first - e.g. Object getFoo() is placed
* before Integer getFoo(). This makes it possible to determine whether a
* method overrides another one simply by looking at the method(s) that
* precedes it in the list. (see eliminateCovariantMethods).
**/
private static class MethodOrder implements Comparator {
public int compare(Method a, Method b) {
final int cmp = a.getName().compareTo(b.getName());
if (cmp != 0)
return cmp;
final Class>[] aparams = a.getParameterTypes();
final Class>[] bparams = b.getParameterTypes();
if (aparams.length != bparams.length)
return aparams.length - bparams.length;
if (!Arrays.equals(aparams, bparams)) {
return Arrays.toString(aparams).compareTo(Arrays.toString(bparams));
}
final Class> aret = a.getReturnType();
final Class> bret = b.getReturnType();
if (aret == bret)
return 0;
if (aret.isAssignableFrom(bret))
return -1;
return +1;
}
public final static MethodOrder instance = new MethodOrder();
}
/**
* Hanlder for MXBean Proxy
*
* @author rishim
*
*/
private abstract class MethodHandler {
MethodHandler(String name, OpenMethod cm) {
this.name = name;
this.convertingMethod = cm;
}
String getName() {
return name;
}
OpenMethod getConvertingMethod() {
return convertingMethod;
}
abstract Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
private final String name;
private final OpenMethod convertingMethod;
}
private class GetterHandler extends MethodHandler {
GetterHandler(String attributeName, OpenMethod cm) {
super(attributeName, cm);
}
@Override
Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
assert (args == null || args.length == 0);
final String methodName = method.getName();
String attrName = "";
if (methodName.startsWith("get")) {
attrName = methodName.substring(3);
} else if (methodName.startsWith("is")
&& method.getReturnType() == boolean.class) {
attrName = methodName.substring(2);
}
return proxyHandler.delegateToObjectState(attrName);
}
}
private class SetterHandler extends MethodHandler {
SetterHandler(String attributeName, OpenMethod cm) {
super(attributeName, cm);
}
@Override
Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String methodName = method.getName();
final Class[] paramTypes = method.getParameterTypes();
final String[] signature = new String[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++)
signature[i] = paramTypes[i].getName();
return proxyHandler.delegateToFunctionService(objectName, methodName,
args, signature);
}
}
private class OpHandler extends MethodHandler {
OpHandler(String operationName, OpenMethod cm) {
super(operationName, cm);
}
Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String methodName = method.getName();
final Class[] paramTypes = method.getParameterTypes();
final String[] signature = new String[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++)
signature[i] = paramTypes[i].getName();
return proxyHandler.delegateToFunctionService(objectName, methodName,
args, signature);
}
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
MethodHandler handler = methodHandlerMap.get(method);
OpenMethod cm = handler.getConvertingMethod();
Object[] openArgs = cm.convertParamsToOpenTypes(args);
Object result = handler.invoke(proxy, method, openArgs);
return cm.convertOpenTypeToReturnValue(result);
}
}