package org.jboss.mx.remoting;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.io.Serializable;
import java.io.IOException;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.HashMap;
import javax.management.Attribute;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.ReflectionException;
import org.jboss.remoting.loading.ClassUtil;
import org.jboss.mx.remoting.LocationAware;
import org.jboss.mx.remoting.MBeanLocator;
public class MoveableMBean implements InvocationHandler, Serializable
{
static final long serialVersionUID = -7506487379354274551L;
private transient static Map methodArgs = new WeakHashMap ();
private static transient Method hashCodeMethod;
private static transient Method equalsMethod;
private static transient Method toStringMethod;
private static transient Method notifyAllMethod;
private static transient Method notifyMethod;
private static transient Method wait0Method;
private static transient Method wait1Method;
private static transient Method wait2Method;
protected MBeanLocator locator;
protected Integer hashCode;
protected Map staticAttributes;
static
{
try
{
hashCodeMethod = Object.class.getMethod ("hashCode", null);
equalsMethod = Object.class.getMethod ("equals", new Class[]{Object.class});
toStringMethod = Object.class.getMethod ("toString", null);
notifyMethod = Object.class.getMethod ("notify", null);
notifyAllMethod = Object.class.getMethod ("notifyAll", null);
notifyMethod = Object.class.getMethod ("notify", null);
wait0Method = Object.class.getMethod ("wait", null);
wait1Method = Object.class.getMethod ("wait", new Class[]{Long.TYPE});
wait2Method = Object.class.getMethod ("wait", new Class[]{Long.TYPE,Integer.TYPE});
}
catch (NoSuchMethodException e)
{
throw new InternalError (e.getMessage ());
}
}
protected MoveableMBean (MBeanLocator locator, Map staticAttributes)
{
this.locator = locator;
this.staticAttributes = staticAttributes;
this.hashCode = new Integer (System.identityHashCode (locator));
}
public final MBeanLocator getMBeanLocator ()
{
return locator;
}
public static Object create (MBeanLocator locator, ClassLoader loader, Class interfaceClass)
{
Class classes[]=ClassUtil.getInterfacesFor(interfaceClass);
return create (locator, loader, classes, null);
}
public static Object create (MBeanLocator locator, ClassLoader loader, Class interfaceClass, Map staticAttributes)
{
Class classes[]=ClassUtil.getInterfacesFor(interfaceClass);
return create (locator, loader, classes, staticAttributes);
}
public static Object create (MBeanLocator locater, Class interfaceClass)
{
Class classes[]=ClassUtil.getInterfacesFor(interfaceClass);
return create (locater, classes);
}
public static Object create (MBeanLocator locator, Class interfaces[])
{
ClassLoader loader = Thread.currentThread ().getContextClassLoader ();
if (loader == null)
{
loader = interfaces[0].getClassLoader ();
}
return create (locator, loader, interfaces, null);
}
public static Object create (MBeanLocator locator, ClassLoader loader, Class interfaces[], Map staticAttributes)
{
Class _inf[]=interfaces;
boolean found = false;
for (int c=0;c<interfaces.length;c++)
{
if (interfaces[c]==LocationAware.class)
{
found=true;
break;
}
}
if (found==false)
{
_inf=new Class[interfaces.length+1];
System.arraycopy(interfaces,0,_inf,0,interfaces.length);
_inf[interfaces.length]=LocationAware.class;
}
return Proxy.newProxyInstance (loader, _inf, new MoveableMBean (locator,staticAttributes));
}
public void addStaticAttributes (Map values)
{
if (staticAttributes==null)
{
staticAttributes = values;
}
else
{
staticAttributes.putAll(values);
}
}
public void addStaticAttribute (String name, Object value)
{
if (staticAttributes==null)
{
staticAttributes = new HashMap(1);
}
staticAttributes.put(name,value);
}
protected Object handleLocationMethods (Object proxy, Method method, Object[] args)
throws Throwable
{
return locator;
}
public Object invoke (Object proxy, Method method, Object[] args)
throws Throwable
{
if (method.getDeclaringClass () == Object.class)
{
return handleObjectMethods (proxy, method, args);
}
if (method.getDeclaringClass() == LocationAware.class)
{
return handleLocationMethods (proxy, method, args);
}
try
{
String name = method.getName();
if (name.startsWith("get") && name.length()>3 && (args==null || args.length<=0))
{
String attributeName = method.getName().substring(3);
if (staticAttributes!=null)
{
if (staticAttributes.containsKey(attributeName))
{
return staticAttributes.get(attributeName);
}
}
return locator.getMBeanServer ().getAttribute (locator.getObjectName (), attributeName);
}
else if (name.startsWith("set") && name.length()>3)
{
String attributeName = method.getName().substring(3);
locator.getMBeanServer().setAttribute(locator.getObjectName(),new Attribute(attributeName,(args==null?null:args[0])));
if (staticAttributes!=null)
{
if (staticAttributes.containsKey(attributeName))
{
return staticAttributes.put(attributeName,(args==null ? null : args[0]));
}
}
return null;
}
else
{
return locator.getMBeanServer ().invoke (locator.getObjectName (), method.getName (), args, makeArgSignature (method, args));
}
}
catch (InstanceNotFoundException inf)
{
throw inf;
}
catch (MBeanException mbe)
{
throw mbe.getTargetException ();
}
catch (ReflectionException re)
{
throw re.getTargetException ();
}
}
protected Boolean proxyEquals (Object proxy, Object other)
{
return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
}
protected String proxyToString (Object proxy)
{
return (locator == null ? ("MoveableMBean [Proxy" + "@" + proxy.hashCode ()+"]") : locator.toString ());
}
protected Integer proxyHashCode (Object proxy)
{
return hashCode;
}
protected Object handleObjectMethods (Object proxy, Method method, Object args[])
throws Exception
{
if (method.equals (hashCodeMethod))
{
return proxyHashCode (proxy);
}
else if (method.equals (equalsMethod))
{
return proxyEquals (proxy, args[0]);
}
else if (method.equals (toStringMethod))
{
return proxyToString (proxy);
}
else if (method.equals (notifyAllMethod))
{
notifyAll();
return null;
}
else if (method.equals(notifyMethod))
{
notify();
return null;
}
else if (method.equals(wait0Method))
{
wait();
return null;
}
else if (method.equals(wait1Method))
{
wait(((Long)args[0]).longValue());
return null;
}
else if (method.equals(wait2Method))
{
wait(((Long)args[0]).longValue(), ((Integer)args[1]).intValue());
return null;
}
else
{
throw new InternalError (
"unexpected Object method dispatched: " + method);
}
}
protected synchronized String[] makeArgSignature (Method method, Object args[])
{
if (methodArgs.containsKey (method))
{
return (String[]) methodArgs.get (method);
}
Class pt[] = method.getParameterTypes ();
if (pt == null || pt.length <= 0)
{
return null;
}
String sig[] = new String[args.length];
for (int c = 0; c < pt.length; c++)
{
sig[c] = pt[c].getName ();
}
methodArgs.put (method, sig);
return sig;
}
protected Class resolveProxyClass(String[] interfaces)
throws IOException, ClassNotFoundException
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl==null)
{
cl = MoveableMBean.class.getClassLoader();
}
Class inf[]=new Class[interfaces.length];
for (int c=0;c<interfaces.length;c++)
{
inf[c]=cl.loadClass(interfaces[c]);
}
return java.lang.reflect.Proxy.getProxyClass(cl, inf);
}
}