package org.jboss.mx.remoting;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.Map;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.NotificationFilter;
import javax.management.ObjectName;
import org.jboss.logging.Logger;
import org.jboss.remoting.*;
import org.jboss.remoting.invocation.NameBasedInvocation;
import org.jboss.remoting.ident.Identity;
public class JMXSubsystemInvocationHandler implements ServerInvocationHandler
{
private static final Logger log = Logger.getLogger(JMXSubsystemInvocationHandler.class);
private MBeanServer server;
private MBeanNotificationCache notificationCache;
private ServerInvoker invoker;
private Identity identity;
private static Method getObjectInstance;
private static Method isRegistered;
private static Method getAttribute;
private static Method getAttributes;
private static Method setAttribute;
private static Method setAttributes;
private static Method invoke;
private static Method getMBeanInfo;
static
{
try
{
Class LObject = (new Object[0]).getClass();
Class LString = (new String[0]).getClass();
Class[] Sig_ObjectName =
new Class[] { ObjectName.class };
Class[] Sig_ObjectName_String =
new Class[] { ObjectName.class, String.class };
Class[] Sig_ObjectName_LString =
new Class[] { ObjectName.class, LString };
Class[] Sig_ObjectName_Attribute =
new Class[] { ObjectName.class, Attribute.class };
Class[] Sig_ObjectName_AttributeList =
new Class[] { ObjectName.class, AttributeList.class };
Class[] Sig_ObjectName_String_LObject_LString =
new Class[] { ObjectName.class, String.class, LObject, LString };
getObjectInstance = MBeanServer.class.getMethod("getObjectInstance", Sig_ObjectName);
isRegistered = MBeanServer.class.getMethod("isRegistered", Sig_ObjectName);
getAttribute = MBeanServer.class.getMethod("getAttribute", Sig_ObjectName_String);
getAttributes = MBeanServer.class.getMethod("getAttributes", Sig_ObjectName_LString);
setAttribute = MBeanServer.class.getMethod("setAttribute", Sig_ObjectName_Attribute);
setAttributes = MBeanServer.class.getMethod("setAttributes", Sig_ObjectName_AttributeList);
invoke = MBeanServer.class.getMethod("invoke", Sig_ObjectName_String_LObject_LString);
getMBeanInfo = MBeanServer.class.getMethod("getMBeanInfo", Sig_ObjectName);
}
catch (Exception e)
{
throw new RuntimeException("Error resolving methods", e);
}
}
public JMXSubsystemInvocationHandler ()
{
super();
}
public void setInvoker ( ServerInvoker invoker )
{
this.invoker = invoker;
}
public void setMBeanServer ( MBeanServer server )
{
this.server = server;
identity = Identity.get(server);
MBeanTransportPreference.setLocalServer(server,identity);
if (log.isDebugEnabled())
{
log.debug("setMBeanServer called with: "+server+" with identity: "+identity);
}
}
public synchronized void destroy ()
{
if (notificationCache!=null)
{
notificationCache.destroy();
notificationCache=null;
}
}
protected void finalize () throws Throwable
{
destroy();
super.finalize();
}
private void storeNotifications (String sessionId, Map payload)
{
NotificationQueue q = (notificationCache==null) ? null : notificationCache.getNotifications(sessionId);
if (q!=null)
{
payload.put("notifications",q);
}
}
public Object invoke (InvocationRequest invocation)
throws Throwable
{
if (this.server==null)
{
throw new IllegalStateException("invoke called prior to mbean server being set");
}
try
{
NameBasedInvocation nbi = (NameBasedInvocation)invocation.getParameter();
String methodName = nbi.getMethodName();
Object args [] = nbi.getParameters();
String signature [] = nbi.getSignature();
String sessionId = invocation.getSessionId();
if (methodName.equals("$GetNotifications$")) {
return new Boolean(true);
}
if (methodName.equals("$NOTIFICATIONS$")) {
NotificationQueue queue=(NotificationQueue)args[0];
MBeanServerClientInvokerProxy p = MBeanServerClientInvokerProxy.get(queue.getSessionID());
if (p!=null)
{
if (log.isDebugEnabled())
{
log.debug("received remote notifications for JMX id: "+queue.getSessionID()+", queue: "+queue);
}
p.deliverNotifications(queue,true);
}
else
{
log.warn("couldn't find a client invoker proxy for mbean serverid: "+queue.getSessionID()+", dropping notifications ["+queue+"]");
}
return null;
}
if (methodName.equals("addNotificationListener") && signature.length==4)
{
handleAddNotificationListener(invocation.getLocator(),sessionId,(ObjectName)args[0],(NotificationFilter)args[2],args[3]);
return null;
}
else if (methodName.equals("removeNotificationListener") && signature.length==3)
{
handleRemoveNotificationListener(invocation.getLocator(),sessionId,(ObjectName)args[0],args[2]);
return null;
}
Object _args[] = (args==null && signature!=null) ? new Object[signature.length] : args;
Method method = getMethod(methodName,signature);
return method.invoke(server,_args);
}
catch (Throwable ex)
{
if (ex instanceof UndeclaredThrowableException)
{
UndeclaredThrowableException ut=(UndeclaredThrowableException)ex;
Throwable ute = ut.getUndeclaredThrowable();
if (ute instanceof Exception)
{
throw new MBeanException((Exception)ute,ut.getUndeclaredThrowable().getMessage());
}
else
{
throw new MBeanException (new Exception(ute.getMessage()),ute.getMessage());
}
}
if (ex instanceof InvocationTargetException)
throw ((InvocationTargetException) ex).getTargetException();
throw ex;
}
finally
{
if (notificationCache!=null)
{
storeNotifications(invocation.getSessionId(),invocation.getReturnPayload());
}
}
}
private synchronized void handleAddNotificationListener (InvokerLocator locator, String sessionId, ObjectName objName, NotificationFilter filter, Object handback)
throws Throwable
{
if (notificationCache==null)
{
notificationCache = new MBeanNotificationCache(invoker,server);
}
notificationCache.addNotificationListener(locator,sessionId,objName,filter,handback);
}
private synchronized void handleRemoveNotificationListener (InvokerLocator locator, String sessionId, ObjectName objName, Object key)
throws Throwable
{
if (notificationCache==null)
{
return;
}
notificationCache.removeNotificationListener(locator,sessionId,objName,key);
}
private Method getMethod (String methodName, String sig[])
throws Throwable
{
if (methodName.equals("invoke"))
return invoke;
else if (methodName.equals("getAttribute"))
return getAttribute;
else if (methodName.equals("setAttribute"))
return setAttribute;
else if (methodName.equals("getAttributes"))
return getAttributes;
else if (methodName.equals("setAttributes"))
return setAttributes;
else if (methodName.equals("setAttributes"))
return setAttributes;
else if (methodName.equals("getMBeanInfo"))
return getMBeanInfo;
else if (methodName.equals("getObjectInstance"))
return getObjectInstance;
else if (methodName.equals("isRegistered"))
return isRegistered;
Class[] params = null;
if (sig != null)
{
params = new Class[sig.length];
for (int i = 0 ; i < sig.length; ++i)
params[i] = Class.forName(sig[i]);
}
return MBeanServer.class.getMethod(methodName, params);
}
public void addListener(InvokerCallbackHandler callbackHandler)
{
}
public void removeListener(InvokerCallbackHandler callbackHandler)
{
}
}