com.gemstone.gemfire.management.internal.MBeanProxyInvocationHandler 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.beans.IntrospectionException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import javax.management.JMX;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.execute.FunctionService;
import com.gemstone.gemfire.cache.execute.ResultCollector;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.i18n.LogWriterI18n;
/**
* This class is the proxy handler for all the proxies created for federated
* MBeans. Its designed with Java proxy mechanism. All data calls are
* delegated to the federation components.
* All method calls are routed to specified members via Function service
*
* @author rishim
*
*/
public class MBeanProxyInvocationHandler implements InvocationHandler {
private static final String THIS_COMPONENT = MBeanProxyInvocationHandler.class
.getName();
/**
* Name of the MBean
*/
private ObjectName objectName;
/**
* The monitoring region where this Object resides.
*/
private Region monitoringRegion;
/**
* The member to which this proxy belongs
*/
private DistributedMember member;
/**
* emitter is a helper class for sending notifications on behalf of the proxy
*/
private final NotificationBroadcasterSupport emitter;
private final ProxyInterface proxyImpl;
private LogWriterI18n logger;
private boolean isMXBean;
private MXBeanProxyInvocationHandler mxbeanInvocationRef;
/**
*
* @param member
* member to which this MBean belongs
* @param monitoringRegion
* corresponding MonitoringRegion
* @param objectName
* ObjectName of the MBean
* @param interfaceClass
* on which interface the proxy to be exposed
* @return Object
* @throws ClassNotFoundException
* @throws IntrospectionException
*/
public static Object newProxyInstance(DistributedMember member,
Region monitoringRegion, ObjectName objectName,
Class interfaceClass) throws ClassNotFoundException,
IntrospectionException {
boolean isMXBean = JMX.isMXBeanInterface(interfaceClass);
boolean notificationBroadcaster = ((FederationComponent) monitoringRegion
.get(objectName.toString())).isNotificationEmitter();
InvocationHandler handler = new MBeanProxyInvocationHandler(member,
objectName, monitoringRegion, isMXBean);
Class[] interfaces;
if (notificationBroadcaster) {
interfaces = new Class[] { interfaceClass, ProxyInterface.class,
NotificationBroadCasterProxy.class };
} else {
interfaces = new Class[] { interfaceClass, ProxyInterface.class };
}
Object proxy = Proxy.newProxyInstance(MBeanProxyInvocationHandler.class
.getClassLoader(), interfaces, handler);
return interfaceClass.cast(proxy);
}
/**
*
* @param member
* member to which this MBean belongs
* @param objectName
* ObjectName of the MBean
* @param monitoringRegion
* corresponding MonitoringRegion
* @throws IntrospectionException
* @throws ClassNotFoundException
*/
private MBeanProxyInvocationHandler(DistributedMember member,
ObjectName objectName, Region monitoringRegion, boolean isMXBean)
throws IntrospectionException, ClassNotFoundException {
this.member = member;
this.logger = InternalDistributedSystem.getLoggerI18n();
this.objectName = objectName;
this.monitoringRegion = monitoringRegion;
this.emitter = new NotificationBroadcasterSupport();
this.proxyImpl = new ProxyInterfaceImpl();
this.isMXBean = isMXBean;
}
/**
* Inherited method from Invocation handler All object state requests are
* delegated to the federated component.
*
* All setters and operations() are delegated to the function service.
*
* Notification emmitter methods are also delegated to the function service
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (logger.finerEnabled()) {
logger.finer(THIS_COMPONENT + ": Invoking Method " + method.getName());
}
final Class methodClass = method.getDeclaringClass();
if (methodClass.equals(NotificationBroadcaster.class)
|| methodClass.equals(NotificationEmitter.class))
return invokeBroadcasterMethod(proxy, method, args);
final String methodName = method.getName();
final Class[] paramTypes = method.getParameterTypes();
final Class returnType = method.getReturnType();
final int nargs = (args == null) ? 0 : args.length;
if (methodName.equals("setLastRefreshedTime")) {
proxyImpl.setLastRefreshedTime((Long) args[0]);
return null;
}
if (methodName.equals("getLastRefreshedTime")) {
return proxyImpl.getLastRefreshedTime();
}
if (methodName.equals("sendNotification")) {
sendNotification(args[0]);
return null;
}
// local or not: equals, toString, hashCode
if (shouldDoLocally(proxy, method)){
return doLocally(proxy, method, args);
}
// Support For MXBean open types
if (isMXBean) {
MXBeanProxyInvocationHandler p = findMXBeanProxy(objectName, methodClass, this);
return p.invoke( proxy, method, args);
}
if (methodName.startsWith("get") && methodName.length() > 3 && nargs == 0
&& !returnType.equals(Void.TYPE)) {
return delegateToObjectState(methodName.substring(3));
}
if (methodName.startsWith("is")
&& methodName.length() > 2
&& nargs == 0
&& (returnType.equals(Boolean.TYPE) || returnType.equals(Boolean.class))) {
return delegateToObjectState(methodName.substring(2));
}
final String[] signature = new String[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++)
signature[i] = paramTypes[i].getName();
// if (methodName.startsWith("set") && methodName.length() > 3 && nargs == 1
// && returnType.equals(Void.TYPE)) {
// return delegateToFunctionService(objectName, methodName, args, signature); // TODO: Abhishek what's the diff between this & delegation below
//
// }
return delegateToFunctionService(objectName, methodName, args, signature);
}
/**
* As this proxy may behave as an notification emitter it delegates to the
* member NotificationBroadcasterSupport object
*
* @param notification
*/
private void sendNotification(Object notification) {
emitter.sendNotification((Notification) notification);
}
/**
* This will get the data from Object state which is replicated across the
* hidden region FederataionComponent being the carrier.
*
* @param attributeName
* @return Object
*/
protected Object delegateToObjectState(String attributeName) throws Throwable {
Object returnObj;
try {
FederationComponent fedComp = (FederationComponent) monitoringRegion
.get(objectName.toString());
returnObj = fedComp.getValue(attributeName);
} catch (IllegalArgumentException e) {
throw new MBeanException(e);
} catch (Exception e) {
throw new MBeanException(e);
} catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
} catch (Throwable th) {
SystemFailure.checkFailure();
throw new MBeanException(new Exception(th.getLocalizedMessage()));
}
return returnObj;
}
/**
* It will call the Generic function to execute the method on the remote VM
*
* @param objectName
* ObjectName of the MBean
* @param methodName
* method name
* @param args
* arguments to the methods
* @param signature
* signature of the method
* @return result Object
*/
protected Object delegateToFunctionService(ObjectName objectName,
String methodName, Object[] args, String[] signature) throws Throwable {
Object[] functionArgs = new Object[5];
functionArgs[0] = objectName;
functionArgs[1] = methodName;
functionArgs[2] = signature;
functionArgs[3] = args;
functionArgs[4] = member.getName();
List