package jadex.bridge;
import jadex.commons.Future;
import jadex.commons.IFuture;
import jadex.commons.ThreadSuspendable;
import jadex.commons.collection.MultiCollection;
import jadex.commons.concurrent.DelegationResultListener;
import jadex.commons.service.IInternalService;
import jadex.commons.service.IServiceIdentifier;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* Invocvation interceptor for executing a call on
* the underlying component thread.
*/
public class DecouplingServiceInvocationInterceptor implements IServiceInvocationInterceptor
{
//-------- attributes --------
/** The external access. */
protected IExternalAccess ea;
/** The component adapter. */
protected IComponentAdapter adapter;
/** The service. */
protected Object service;
//-------- constructors --------
/**
* Create a new invocation handler.
*/
public DecouplingServiceInvocationInterceptor(IExternalAccess ea, IComponentAdapter adapter, Object service)
{
this.ea = ea;
this.adapter = adapter;
this.service = service;
}
//-------- methods --------
/**
* Execute the command.
* @param args The argument(s) for the call.
* @return The result of the command.
*/
public void execute(final ServiceInvocationContext sic)
{
Object ret;
Class returntype = sic.getMethod().getReturnType();
boolean scheduleable = returntype.equals(IFuture.class) || returntype.equals(void.class);
boolean directcall = true;
if(!adapter.isExternalThread() || (!scheduleable && directcall))
{
try
{
ret = sic.getMethod().invoke(service, sic.getArguments());
}
catch(Exception e)
{
if(returntype.equals(IFuture.class))
{
Future fut = new Future();
fut.setException(e);
ret = fut;
}
else
{
throw new RuntimeException(e);
}
}
}
else
{
final Future future = new Future();
// if(sic.getMethod().getName().indexOf("calcu")!=-1)
// {
// System.out.println("cal start: "+sic.getArguments()[0]+" "+ea.getComponentIdentifier());
// future.addResultListener(new IResultListener()
// {
// public void resultAvailable(Object source, Object result)
// {
// System.out.println("cal end: "+sic.getArguments()[0]+" "+ea.getComponentIdentifier());
// }
//
// public void exceptionOccurred(Object source, Exception exception)
// {
// System.out.println("cal ex: "+sic.getArguments()[0]+" "+ea.getComponentIdentifier());
// }
// });
// }
IFuture resfut = ea.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
final Future fut = new Future();
try
{
Object res = sic.getMethod().invoke(service, sic.getArguments());
if(res instanceof IFuture)
{
((IFuture)res).addResultListener(new DelegationResultListener(fut));
}
else
{
// Not correct when not null but some other value.
fut.setResult(res);
}
}
catch(Exception e)
{
fut.setException(e);
}
return fut;
}
public String toString()
{
return "invokeMethod("+sic.getMethod()+")";
}
});
if(scheduleable)
{
ret = future;
resfut.addResultListener(new DelegationResultListener(future));
}
else
{
System.out.println("Warning, blocking call: "+sic.getMethod());
ret = resfut.get(new ThreadSuspendable());
// ret = new Future(null);
}
}
sic.setResult(ret);
}
/**
* Get the standard interceptors for composite service proxies;
*/
public static MultiCollection getInterceptors()
{
MultiCollection ret = new MultiCollection();
try
{
ret.put(Object.class.getMethod("toString", new Class[0]), new IServiceInvocationInterceptor()
{
public void execute(ServiceInvocationContext context)
{
Object proxy = context.getProxy();
InvocationHandler handler = (InvocationHandler)Proxy.getInvocationHandler(proxy);
context.setResult(handler.toString());
}
});
ret.put(Object.class.getMethod("equals", new Class[]{Object.class}), new IServiceInvocationInterceptor()
{
public void execute(ServiceInvocationContext context)
{
Object proxy = context.getProxy();
InvocationHandler handler = (InvocationHandler)Proxy.getInvocationHandler(proxy);
Object[] args = (Object[])context.getArguments();
context.setResult(new Boolean(args[0]!=null && Proxy.isProxyClass(args[0].getClass())
&& handler.equals(Proxy.getInvocationHandler(args[0]))));
}
});
ret.put(Object.class.getMethod("hashCode", new Class[0]), new IServiceInvocationInterceptor()
{
public void execute(ServiceInvocationContext context)
{
Object proxy = context.getProxy();
InvocationHandler handler = Proxy.getInvocationHandler(proxy);
context.setResult(new Integer(handler.hashCode()));
}
});
// todo: other object methods?!
}
catch(Exception e)
{
e.printStackTrace();
}
return ret;
}
/**
* Static method for creating a service proxy.
*/
public static IInternalService createServiceProxy(IExternalAccess ea, IComponentAdapter adapter, IInternalService service)
{
IServiceIdentifier sid = service.getServiceIdentifier();
return (IInternalService)Proxy.newProxyInstance(ea.getModel().getClassLoader(), new Class[]{IInternalService.class, sid.getServiceType()},
new BasicServiceInvocationHandler(sid, getInterceptors(), new DecouplingServiceInvocationInterceptor(ea, adapter, service)));
}
}