package org.rzo.netty.ahessian.rpc.client;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Future;
import org.jboss.netty.channel.Channel;
import org.rzo.netty.ahessian.Constants;
import org.rzo.netty.ahessian.rpc.message.HessianRPCReplyMessage;
import com.caucho.hessian4.services.server.AbstractSkeleton;
/**
* A proxy object implementing asynchronous invocations.
* All invocations return a HessianProxyFuture
*/
public class AsyncHessianProxy implements InvocationHandler, Constants
{
private WeakHashMap<Method,String> _mangleMap = new WeakHashMap<Method,String>();
private HessianProxyFactory _factory;
private Class _api;
private boolean _valid = true;
Map _options;
private Map<String, Integer> _groups = new HashMap<String, Integer>();
/**
* Instantiates a new async hessian proxy.
*
* @param factory the factory
* @param api the api
* @param options the options
*/
AsyncHessianProxy(HessianProxyFactory factory, Class api, Map options)
{
_factory = factory;
_api = api;
_options = options;
}
/**
* Gets the channel.
*
* @return the channel
*/
Channel getChannel()
{
if (!_valid)
throw new RuntimeException("invalidated proxy");
return _factory.getChannel();
}
/* (non-Javadoc)
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(Object proxy, Method method, Object []args)
throws Throwable
{
String mangleName;
Channel channel = getChannel();
synchronized (_mangleMap) {
mangleName = _mangleMap.get(method);
}
if (mangleName == null) {
String methodName = method.getName();
Class []params = method.getParameterTypes();
// equals and hashCode are special cased
if (methodName.equals("equals")
&& params.length == 1 && params[0].equals(Object.class)) {
Object value = args[0];
if (value == null || ! Proxy.isProxyClass(value.getClass()))
return Boolean.FALSE;
Object proxyHandler = Proxy.getInvocationHandler(value);
if (! (proxyHandler instanceof AsyncHessianProxy))
return Boolean.FALSE;
AsyncHessianProxy handler = (AsyncHessianProxy) proxyHandler;
return new Boolean(this.equals(handler));
}
else if (methodName.equals("hashCode") && params.length == 0)
return new Integer(System.identityHashCode(this));
else if (methodName.equals("getHessianType"))
return proxy.getClass().getInterfaces()[0].getName();
else if (methodName.equals("getHessianURL"))
return channel == null ? "?" : channel.toString();
else if (methodName.equals("toString") && params.length == 0)
return "HessianProxy[" + _api + "]";
if (! _factory.isOverloadEnabled())
mangleName = method.getName();
else
mangleName = mangleName(method);
synchronized (_mangleMap) {
_mangleMap.put(method, mangleName);
}
}
Integer group = getGroup(mangleName, method.getName());
return sendRequest(mangleName, args, group);
}
private Integer getGroup(String mangleName, String name)
{
Integer result = _groups.get(mangleName);
if (result == null)
{
// get the group for the method
result = (Integer) _options.get("method.group."+mangleName);
if (result == null)
result = (Integer) _options.get("method.group."+name);
// if no group found set to default group 0
if (result == null)
result = 0;
_groups.put(mangleName, result);
}
return result;
}
protected Future<Object> sendRequest(String methodName, Object []args, Integer group)
throws InterruptedException
{
if (!_valid)
throw new RuntimeException("invalidated proxy");
//Map options = new HashMap(_options);
Map options = new HashMap();
options.put(GROUP_HEADER_KEY, group);
options.put(SERVICE_ID_HEADER_KEY, _options.get(SERVICE_ID_HEADER_KEY));
return _factory.sendRequest(methodName, args, options);
}
/** The id. */
static volatile long id = 0;
protected Map getHeaders()
{
Map result = new HashMap();
result.put(CALL_ID_HEADER_KEY, id++);
return result;
}
protected String mangleName(Method method)
{
Class []param = method.getParameterTypes();
if (param == null || param.length == 0)
return method.getName();
else
return AbstractSkeleton.mangleName(method, false);
}
private Future immediateFuture(Object result)
{
HessianProxyFuture future = new HessianProxyFuture();
future.set(new HessianRPCReplyMessage(result, null, null));
return future;
}
protected void invalidate()
{
_valid = false;
}
public String getHost()
{
Channel c = getChannel();
if (c == null)
return null;
InetSocketAddress addr = (InetSocketAddress) c.getRemoteAddress();
return addr.getHostName();
}
}