package javax.management;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
public class MBeanServerInvocationHandler
implements InvocationHandler
{
private MBeanServerConnection connection;
private ObjectName name;
private HashMap mappings;
private static final String[] EMPTY_SIGNATURE = new String[0];
private static final String[] EQUALS_SIGNATURE = new String[] { Object.class.getName() };
private static final Class[] LISTENER = new Class[] { NotificationListener.class };
private static final Class[] TRIPLET = new Class[] { NotificationListener.class, NotificationFilter.class, Object.class };
private static final Method EQUALS;
private static final Method HASH_CODE;
private static final Method TO_STRING;
private static final Method ADD_NOTIFICATION_LISTENER;
private static final Method GET_NOTIFICATION_INFO;
private static final Method REMOVE_NOTIFICATION_LISTENER;
private static final Method REMOVE_NOTIFICATION_LISTENER_TRIPLET;
static
{
try
{
ADD_NOTIFICATION_LISTENER = NotificationBroadcaster.class.getDeclaredMethod("addNotificationListener", TRIPLET);
GET_NOTIFICATION_INFO = NotificationBroadcaster.class.getDeclaredMethod("getNotificationInfo", new Class[0]);
REMOVE_NOTIFICATION_LISTENER = NotificationBroadcaster.class.getDeclaredMethod("removeNotificationListener", LISTENER);
REMOVE_NOTIFICATION_LISTENER_TRIPLET = NotificationEmitter.class.getDeclaredMethod("removeNotificationListener", TRIPLET);
EQUALS = Object.class.getDeclaredMethod("equals", new Class[] { Object.class });
HASH_CODE = Object.class.getDeclaredMethod("hashCode", new Class[0]);
TO_STRING = Object.class.getDeclaredMethod("toString", new Class[0]);
}
catch (Exception e)
{
throw new RuntimeException(e.toString());
}
}
public MBeanServerInvocationHandler(MBeanServerConnection connection,
ObjectName name)
{
if (connection == null)
throw new IllegalArgumentException("Null connection");
if (name == null)
throw new IllegalArgumentException("Null name");
if (name.isPattern())
throw new IllegalArgumentException("Name is a pattern");
this.connection = connection;
this.name = name;
}
public static Object newProxyInstance(MBeanServerConnection connection,
ObjectName name,
Class interfaceClass,
boolean broadcaster)
{
MBeanServerInvocationHandler handler =
new MBeanServerInvocationHandler(connection, name);
if (interfaceClass == null)
throw new IllegalArgumentException("Null interface");
Class[] interfaces;
if (broadcaster)
interfaces = new Class[] { interfaceClass, NotificationEmitter.class };
else
interfaces = new Class[] { interfaceClass };
return Proxy.newProxyInstance(interfaceClass.getClassLoader(), interfaces, handler);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
return getAction(proxy, method).perform(args);
}
private Action getAction(Object proxy, Method method)
throws Throwable
{
if (mappings == null)
mappings = getMappings(proxy);
Action result = (Action) mappings.get(method);
if (result == null)
throw new IllegalArgumentException("Unknown method " + method);
return result;
}
private HashMap getMappings(Object proxy)
throws Throwable
{
HashMap result = new HashMap();
Class[] interfaces = proxy.getClass().getInterfaces();
for (int i = 0; i < interfaces.length; ++i)
{
if (interfaces[i].equals(NotificationEmitter.class))
{
result.put(ADD_NOTIFICATION_LISTENER, new AddNotificationListenerAction());
result.put(GET_NOTIFICATION_INFO, new GetNotificationInfoAction());
result.put(REMOVE_NOTIFICATION_LISTENER, new RemoveNotificationListenerAction());
result.put(REMOVE_NOTIFICATION_LISTENER_TRIPLET, new RemoveNotificationListenerTripletAction());
}
else
{
Method[] methods = interfaces[i].getMethods();
for (int m = 0; m < methods.length; ++m)
{
String methodName = methods[m].getName();
Class returnType = methods[m].getReturnType();
Class[] parameterTypes = methods[m].getParameterTypes();
if (methodName.startsWith("get") &&
methodName.length() > 3 &&
Void.TYPE.equals(returnType) == false &&
parameterTypes.length == 0)
{
result.put(methods[m], new GetAction(methodName.substring(3)));
}
else if(methodName.startsWith("is") &&
methodName.length() > 2 &&
(Boolean.TYPE.equals(returnType) || Boolean.class.equals(returnType)) &&
parameterTypes.length == 0)
{
result.put(methods[m], new GetAction(methodName.substring(2)));
}
else if(methodName.startsWith("set") &&
methodName.length() > 3 &&
Void.TYPE.equals(returnType) &&
parameterTypes.length == 1)
{
result.put(methods[m], new SetAction(methodName.substring(3)));
}
else
{
result.put(methods[m], new InvokeAction(methodName, getSignature(parameterTypes)));
}
}
}
}
result.put(EQUALS, new InvokeAction(EQUALS.getName(), EQUALS_SIGNATURE));
result.put(HASH_CODE, new InvokeAction(HASH_CODE.getName(), EMPTY_SIGNATURE));
result.put(TO_STRING, new InvokeAction(TO_STRING.getName(), EMPTY_SIGNATURE));
return result;
}
private static String[] getSignature(final Class[] parameterTypes)
{
String[] signature = new String[parameterTypes.length];
for (int p = 0; p < parameterTypes.length; ++p)
signature[p] = parameterTypes[p].getName();
return signature;
}
private interface Action
{
public Object perform(Object[] args)
throws Throwable;
}
private class GetAction
implements Action
{
private String attribute;
public GetAction(String attribute)
{
this.attribute = attribute;
}
public Object perform(Object[] args)
throws Throwable
{
try
{
return connection.getAttribute(name, attribute);
}
catch(MBeanException exception)
{
throw exception.getTargetException();
}
}
}
private class SetAction
implements Action
{
private String attribute;
public SetAction(String attribute)
{
this.attribute = attribute;
}
public Object perform(Object[] args)
throws Throwable
{
try
{
connection.setAttribute(name, new Attribute(attribute, args[0]));
return null;
}
catch(MBeanException exception)
{
throw exception.getTargetException();
}
}
}
private class InvokeAction
implements Action
{
private String operation;
private String[] signature;
public InvokeAction(String operation, String[] signature)
{
this.operation = operation;
this.signature = signature;
}
public Object perform(Object[] args)
throws Throwable
{
try
{
return connection.invoke(name, operation, args, signature);
}
catch(MBeanException exception)
{
throw exception.getTargetException();
}
}
}
private class AddNotificationListenerAction
implements Action
{
public Object perform(Object[] args)
throws Throwable
{
connection.addNotificationListener(name,
(NotificationListener) args[0], (NotificationFilter) args[1], args[2]);
return null;
}
}
private class GetNotificationInfoAction
implements Action
{
public Object perform(Object[] args)
throws Throwable
{
return connection.getMBeanInfo(name).getNotifications();
}
}
private class RemoveNotificationListenerAction
implements Action
{
public Object perform(Object[] args)
throws Throwable
{
connection.removeNotificationListener(name, (NotificationListener) args[0]);
return null;
}
}
private class RemoveNotificationListenerTripletAction
implements Action
{
public Object perform(Object[] args)
throws Throwable
{
connection.removeNotificationListener(name,
(NotificationListener) args[0], (NotificationFilter) args[1], args[2]);
return null;
}
}
}