package jadex.base.service.remote; import jadex.base.service.remote.commands.RemoteMethodInvocationCommand; import jadex.bridge.IComponentIdentifier; import jadex.bridge.IComponentStep; import jadex.bridge.IInternalAccess; import jadex.commons.Future; import jadex.commons.IFuture; import jadex.commons.SUtil; import jadex.commons.ThreadSuspendable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * Class that implements the Java proxy InvocationHandler, which * is called when a method on a proxy is called. */ public class RemoteMethodInvocationHandler implements InvocationHandler { protected static Method finalize; static { try { finalize = IFinalize.class.getMethod("finalize", new Class[0]); } catch(Exception e) { e.printStackTrace(); } } //-------- attributes -------- /** The remote service management service. */ protected RemoteServiceManagementService rsms; /** The proxy reference. */ protected ProxyReference pr; //-------- constructors -------- /** * Create a new invocation handler. */ public RemoteMethodInvocationHandler(RemoteServiceManagementService rsms, ProxyReference pr) { this.rsms = rsms; this.pr = pr; // System.out.println("handler: "+pi.getServiceIdentifier().getServiceType()+" "+pi.getCache()); } //-------- methods -------- /** * Invoke a method. */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ProxyInfo pi = pr.getProxyInfo(); // System.out.println("remote method invoc: "+method.getName()); // Test if method is excluded. if(pi.isExcluded(method)) throw new UnsupportedOperationException("Method is excluded from interface for remote invocations: "+method.getName()); // Test if method is constant and a cache value is available. if(pr.getCache()!=null && !pi.isUncached(method) && !pi.isReplaced(method)) { Class rt = method.getReturnType(); Class[] ar = method.getParameterTypes(); if(!rt.equals(void.class) && !(rt.isAssignableFrom(IFuture.class)) && ar.length==0) { return pr.getCache().get(method.getName()); } } // Test if method has a replacement command. IMethodReplacement replacement = pi.getMethodReplacement(method); if(replacement!=null) { // Todo: super pointer for around-advice-like replacements. return replacement.invoke(proxy, args); } // Test if finalize is called. if(finalize.equals(method)) { // System.out.println("Finalize called on: "+proxy); rsms.component.scheduleStep(new IComponentStep() { public Object execute(IInternalAccess ia) { rsms.getRemoteReferenceModule().decProxyCount(pr.getRemoteReference()); return null; } }); return null; } // Call remote method otherwise. final Future future = new Future(); Object ret = future; final IComponentIdentifier compid = rsms.getRMSComponentIdentifier(); final String callid = SUtil.createUniqueId(compid.getLocalName()); final RemoteMethodInvocationCommand content = new RemoteMethodInvocationCommand( pr.getRemoteReference(), method.getName(), method.getParameterTypes(), args, callid); // Can be invoked directly, because uses internally redirects to agent thread. rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), content, callid, -1, future); if(method.getReturnType().equals(void.class) && !pi.isSynchronous(method)) { // System.out.println("Warning, void method call will be executed asynchronously: " // +method.getDeclaringClass()+" "+method.getName()+" "+Thread.currentThread()); future.setResult(null); } else if(!IFuture.class.isAssignableFrom(method.getReturnType())) { // Thread.dumpStack(); System.out.println("Warning, blocking method call: "+method.getDeclaringClass() +" "+method.getName()+" "+Thread.currentThread()+" "+pi); ret = future.get(new ThreadSuspendable()); // System.out.println("Resumed call: "+method.getName()+" "+ret); } return ret; } }