All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.platform.service.remote.RemoteMethodInvocationHandler Maven / Gradle / Ivy

package jadex.platform.service.remote;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IComponentStep;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.ITargetResolver;
import jadex.bridge.ServiceCall;
import jadex.bridge.service.IServiceIdentifier;
import jadex.bridge.service.annotation.SecureTransmission;
import jadex.bridge.service.annotation.Timeout;
import jadex.bridge.service.component.ISwitchCall;
import jadex.bridge.service.component.ServiceInvocationContext;
import jadex.bridge.service.component.interceptors.CallAccess;
import jadex.bridge.service.component.interceptors.IntelligentProxyInterceptor;
import jadex.commons.SReflect;
import jadex.commons.SUtil;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IIntermediateFuture;
import jadex.commons.future.IPullIntermediateFuture;
import jadex.commons.future.IPullSubscriptionIntermediateFuture;
import jadex.commons.future.ISubscriptionIntermediateFuture;
import jadex.commons.future.ITerminableFuture;
import jadex.commons.future.ITerminableIntermediateFuture;
import jadex.commons.future.ITuple2Future;
import jadex.commons.future.IntermediateFuture;
import jadex.commons.future.PullIntermediateDelegationFuture;
import jadex.commons.future.PullSubscriptionIntermediateDelegationFuture;
import jadex.commons.future.SubscriptionIntermediateDelegationFuture;
import jadex.commons.future.TerminableDelegationFuture;
import jadex.commons.future.TerminableIntermediateDelegationFuture;
import jadex.commons.future.Tuple2Future;
import jadex.commons.transformation.annotations.Classname;
import jadex.platform.service.remote.commands.RemoteFuturePullCommand;
import jadex.platform.service.remote.commands.RemoteFutureTerminationCommand;
import jadex.platform.service.remote.commands.RemoteMethodInvocationCommand;

/**
 *  Class that implements the Java proxy InvocationHandler, which
 *  is called when a method on a proxy is called.
 */
public class RemoteMethodInvocationHandler implements InvocationHandler, ISwitchCall //extends MethodListenerHandler
{
	protected static final Method schedulestep;
	
	protected static final Method finalize;
	
	static
	{
		try
		{
			finalize = IFinalize.class.getMethod("finalize", new Class[0]);
			schedulestep = IExternalAccess.class.getMethod("scheduleStep", new Class[]{IComponentStep.class});
		}
		catch(Exception e)
		{
			throw new RuntimeException(e);
		}
	}
	
	//-------- attributes --------
	
	/** The remote service management service. */
	protected RemoteServiceManagementService rsms;

	/** The proxy reference. */
	protected ProxyReference pr;
	
	/** The target resolver. */
	protected ITargetResolver tr;
		
	//-------- 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 --------
	
//	public static Object debugcallid	= null;	
	
	/**
	 *  Invoke a method.
	 */
	public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
	{		
		final IComponentIdentifier compid = rsms.getRMSComponentIdentifier();
		final String callid = SUtil.createUniqueId(compid.getName()+".0."+method.toString());
	
//		notifyMethodListeners(true, proxy, method, args, callid);
		
		final ProxyInfo pi = pr.getProxyInfo();
		
		if(pi.isExcluded(method)) 
			throw new UnsupportedOperationException("The method is excluded for remote: " + method);
		
		// Determine if call goes to
		// a) cached method
		// b) method replacement
		// c) finalize method
		// d) real method invocation
		
		if(pr.getCache()!=null && !pi.isUncached(method) && !pi.isReplaced(method))
		{
			Class rt = method.getReturnType();
			Class[] ar = method.getParameterTypes();
			if(!rt.equals(void.class) && !(SReflect.isSupertype(IFuture.class, rt)) && ar.length==0)
			{
				Object res = pr.getCache().get(method.getName());
				if(res instanceof Throwable && SReflect.isSupertype(Throwable.class, rt))
				{
					throw (Throwable)res;
				}
				else
				{
					return res;
				}
			}
		}
		
		// 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);
			try
			{
				rsms.component.scheduleStep(new IComponentStep()
				{
					@Classname("fin")
					public IFuture execute(IInternalAccess ia)
					{
						rsms.getRemoteReferenceModule().decProxyCount(pr.getRemoteReference());
						return IFuture.DONE;
					}
				});
			}
			catch(Exception e)
			{
				// Finalize is called internally -> Exception pop up to the console :-(
				System.out.println("Warning, could not call finalize method: "+rsms.component.getComponentIdentifier()+" "+proxy);
			}
			return null;
		}
		
		final ServiceInvocationContext sic = ServiceInvocationContext.SICS.get();
		ServiceInvocationContext.SICS.remove();
		
		// Get the current service invocation 
//		ServiceCall invoc = ServiceCall.getCurrentInvocation();
		Map	props	= new HashMap();
//		props.put("method2", method.getName());
		// Must use call from ServiceCall because could not have required chain
		ServiceCall invoc = ServiceCall.getOrCreateNextInvocation(props);
//		ServiceCall invoc = sic.getServiceCall();
		
		// The reatime property is not necessary, as currently message are sent with realtime timeouts always  
		
//		if(method.getName().indexOf("schedule")!=-1)
//		System.out.println("step: "+method.getName()+", "+invoc);
		
		Map nf = invoc!=null? invoc.getProperties(): new HashMap();
		boolean sec = pi.isSecure(method);
		if(sec)
			nf.put(SecureTransmission.SECURE_TRANSMISSION, sec? Boolean.TRUE: Boolean.FALSE);
		final long to = invoc!=null && invoc.hasUserTimeout()? invoc.getTimeout(): pi.getMethodTimeout(rsms.getComponent().getComponentIdentifier(), method);
		nf.put(Timeout.TIMEOUT, Long.valueOf(to));
		final Map nonfunc = nf; 
		
		Class type = determineReturnType(proxy, method, args);
		Future future = createReturnFuture(compid, callid, method, type, to, nonfunc, sic);

		// determine the call target
		// can be redirected by intelligent proxies
		ITargetResolver tr = getTargetResolver();
		if(tr!=null)
		{
			IServiceIdentifier sid = (IServiceIdentifier)pr.getRemoteReference().getTargetIdentifier();
			
			IntelligentProxyInterceptor.invoke(null, sic, sid, rsms.getComponent(), tr, 3, 0).addResultListener(new DelegationResultListener(future)); 

//			final Future ffuture = future;
//			tr.determineTarget((IServiceIdentifier)pr.getRemoteReference().getTargetIdentifier(), rsms.getComponent())
//				.addResultListener(new ExceptionDelegationResultListener(future) 
//			{
//				public void customResultAvailable(IService ser) 
//				{
//					IServiceIdentifier sid = ser.getServiceIdentifier();
//					IComponentIdentifier rrms = new ComponentIdentifier("rms@system."+sid.getProviderId().getPlatformName(), sid.getProviderId().getAddresses());
//					RemoteReference rr = new RemoteReference(rrms, sid);
//					// non-func is in command to let stream handlers access the properties in RMI processing
//					final RemoteMethodInvocationCommand content = new RemoteMethodInvocationCommand(
//						rr, method, args, callid, IComponentIdentifier.LOCAL.get(), nonfunc);
//					
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("invoke: "+method.getName());
////					if(method.getName().equals("getResult"))
////						System.out.println("sending invoke");
//					rsms.sendMessage(rr.getRemoteManagementServiceIdentifier(), 
//						null, content, callid, to, ffuture, nonfunc, sic);
//					
////					// Provide alternative immediate future result, if method is asynchronous.
////					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	= new Future(null);
////					}
//				}
//			});
		}
		else
		{
			// non-func is in command to let stream handlers access the properties in RMI processing
			final RemoteMethodInvocationCommand content = new RemoteMethodInvocationCommand(
				pr.getRemoteReference(), method, args, callid, IComponentIdentifier.LOCAL.get(), nonfunc);
			
			// Can be invoked directly, because internally redirects to agent thread.
//			System.out.println("invoke: "+method.getName());
//			if(method.getName().equals("getResult"))
//				System.out.println("sending invoke");
			rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), 
				null, content, callid, to, future, nonfunc, sic);
			
			// Provide alternative immediate future result, if method is asynchronous.
			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	= new Future((Object)null);
			}
		}
		
		CallAccess.resetNextInvocation();
		// todo: also set last call in future
		
		return future;
	}
	
//	/**
//	 *  Invoke a method.
//	 */
//	protected Object internalInvoke(final Object proxy, final Method method, final Object[] args) throws Throwable
//	{
//		// non-func is in command to let stream handlers access the properties in RMI processing
//		final RemoteMethodInvocationCommand content = new RemoteMethodInvocationCommand(
//			pr.getRemoteReference(), method, args, callid, IComponentIdentifier.LOCAL.get(), nonfunc);
//		
//		// Can be invoked directly, because internally redirects to agent thread.
////		System.out.println("invoke: "+method.getName());
////		if(method.getName().equals("getResult"))
////			System.out.println("sending invoke");
//		rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), 
//			null, content, callid, to, future, nonfunc, sic);
//		
//		// Provide alternative immediate future result, if method is asynchronous.
//		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	= new Future(null);
//		}
//	}
//		final IComponentIdentifier compid = rsms.getRMSComponentIdentifier();
//		final String callid = SUtil.createUniqueId(compid.getName()+".0."+method.toString());
//		
////		notifyMethodListeners(true, proxy, method, args, callid);
//		
//		ProxyInfo pi = pr.getProxyInfo();
//		
//		// Determine if call goes to
//		// a) cached method
//		// b) method replacement
//		// c) finalize method
//		// d) real method invocation
//		
//		// determine the call target
//		// can be redirected by intelligent proxies
////		final ProxyReference pr = pi.getTargetDeterminer()!=null? pi.getTargetDeterminer().determineTarget(): pr;
//		
//		final ServiceInvocationContext sic = ServiceInvocationContext.SICS.get();
//		ServiceInvocationContext.SICS.remove();
//		
//		// Get the current service invocation 
////		ServiceCall invoc = ServiceCall.getCurrentInvocation();
//		Map	props	= new HashMap();
////		props.put("method2", method.getName());
//		ServiceCall invoc = ServiceCall.getOrCreateNextInvocation(props);
//		
//		// Get method timeout
//		final long to = invoc!=null && invoc.hasUserTimeout()? invoc.getTimeout(): pi.getMethodTimeout(method);
//		// The reatime property is not necessary, as currently message are sent with realtime timeouts always  
//		
////		if(method.getName().indexOf("schedule")!=-1)
////		System.out.println("step: "+method.getName()+", "+invoc);
//		
//		// Get the secure transmission
//		boolean sec = pi.isSecure(method);
//		
//		Map nf = invoc!=null? invoc.getProperties(): new HashMap();
//		if(sec)
//		{
//			nf.put(SecureTransmission.SECURE_TRANSMISSION, sec? Boolean.TRUE: Boolean.FALSE);
//		}
//		nf.put(Timeout.TIMEOUT, Long.valueOf(to));
//		final Map nonfunc = nf; 
//		
//		CallAccess.resetNextInvocation(); 
//		
//		Future future;
//		Class type = determineReturnType(proxy, method, args);
////		Class type = method.getReturnType();
//
//		if(SReflect.isSupertype(IPullSubscriptionIntermediateFuture.class, type))
//		{
//			future = new PullSubscriptionIntermediateDelegationFuture()
//			{
//				public void pullIntermediateResult() 
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getLocalName()+"."+method.toString());
//					RemoteFuturePullCommand content = new RemoteFuturePullCommand(mycallid, callid);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending terminate");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
//				
//				public void terminate(Exception reason) 
//				{
//					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
//					boolean	set	= setExceptionIfUndone(reason);
//					
//					// Send message to announce termination to remote
//					if(set)
//					{
//						Future res = new Future();
//	//					res.addResultListener(new IResultListener()
//	//					{
//	//						public void resultAvailable(Object result)
//	//						{
//	//							System.out.println("received result: "+result);
//	//						}
//	//						public void exceptionOccurred(Exception exception)
//	//						{
//	//							System.out.println("received exception: "+exception);
//	//						}
//	//					});
//						final String mycallid = SUtil.createUniqueId(compid.getName()+".pullsub."+method.toString());
//						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, reason);
//						// Can be invoked directly, because internally redirects to agent thread.
//	//					System.out.println("sending terminate");
//						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//							content, mycallid, to, res, nonfunc, sic);
//					}
//				}
//				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".pullsub."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
//				
//				// Called from delegation listeners in RMS -> ignore if already terminated
//				public void setException(Exception exception)
//				{
//					super.setExceptionIfUndone(exception);
//				}
//			};
//		}
//		else if(SReflect.isSupertype(IPullIntermediateFuture.class, type))
//		{
//			future = new PullIntermediateDelegationFuture()
//			{
//				public void pullIntermediateResult() 
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getLocalName()+"."+method.toString());
//					RemoteFuturePullCommand content = new RemoteFuturePullCommand(mycallid, callid);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending terminate");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
//				
//				public void terminate(Exception reason) 
//				{
//					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
//					boolean	set	= setExceptionIfUndone(reason);
//					
//					// Send message to announce termination to remote
//					if(set)
//					{
//						Future res = new Future();
//	//					res.addResultListener(new IResultListener()
//	//					{
//	//						public void resultAvailable(Object result)
//	//						{
//	//							System.out.println("received result: "+result);
//	//						}
//	//						public void exceptionOccurred(Exception exception)
//	//						{
//	//							System.out.println("received exception: "+exception);
//	//						}
//	//					});
//						final String mycallid = SUtil.createUniqueId(compid.getName()+".pull."+method.toString());
//						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, reason);
//						// Can be invoked directly, because internally redirects to agent thread.
//	//					System.out.println("sending terminate");
//						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//							content, mycallid, to, res, nonfunc, sic);
//					}
//				}
//				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".pull."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
//				
//				// Called from delegation listeners in RMS -> ignore if already terminated
//				public void setException(Exception exception)
//				{
//					super.setExceptionIfUndone(exception);
//				}
//			};
//		}
//		else if(SReflect.isSupertype(ISubscriptionIntermediateFuture.class, type))
//		{
//			future = new SubscriptionIntermediateDelegationFuture()
//			{
//				public void terminate(Exception reason) 
//				{
//					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
//					boolean	set	= setExceptionIfUndone(reason);
//					
//					// Send message to announce termination to remote
//					if(set)
//					{
//						Future res = new Future();
//	//					res.addResultListener(new IResultListener()
//	//					{
//	//						public void resultAvailable(Object result)
//	//						{
//	//							System.out.println("received result: "+result);
//	//						}
//	//						public void exceptionOccurred(Exception exception)
//	//						{
//	//							System.out.println("received exception: "+exception);
//	//						}
//	//					});
//						final String mycallid = SUtil.createUniqueId(compid.getName()+".sub."+method.toString());
//						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, reason);
//						// Can be invoked directly, because internally redirects to agent thread.
//	//					System.out.println("sending terminate");
//						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//							content, mycallid, to, res, nonfunc, sic);
//					}
//				}
//				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".sub."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
//				
//				// Called from delegation listeners in RMS -> ignore if already terminated
//				public void setException(Exception exception)
//				{
//					super.setExceptionIfUndone(exception);
//				}
//			};
//		}
//		else if(SReflect.isSupertype(ITerminableIntermediateFuture.class, type))
//		{
//			future = new TerminableIntermediateDelegationFuture()
//			{
//				public void terminate(Exception e) 
//				{
//					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
//					boolean	set	= setExceptionIfUndone(e);
//					
//					// Send message to announce termination to remote
//					if(set)
//					{
//						Future res = new Future();
//	//					res.addResultListener(new IResultListener()
//	//					{
//	//						public void resultAvailable(Object result)
//	//						{
//	//							System.out.println("received result: "+result);
//	//						}
//	//						public void exceptionOccurred(Exception exception)
//	//						{
//	//							System.out.println("received exception: "+exception);
//	//						}
//	//					});
//						final String mycallid = SUtil.createUniqueId(compid.getName()+".interm."+method.toString());
//						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, e);
//						// Can be invoked directly, because internally redirects to agent thread.
//	//					System.out.println("sending terminate");
//						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), 
//							null, content, mycallid, to, res, nonfunc, sic);
//					}
//				}
//				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".interm."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
//				
//				// Called from delegation listeners in RMS -> ignore if already terminated
//				public void setException(Exception exception)
//				{
//					super.setExceptionIfUndone(exception);
//				}
//			};
//		}
//		else if(SReflect.isSupertype(ITerminableFuture.class, type))
//		{
//			future = new TerminableDelegationFuture()
//			{
//				public void terminate(Exception reason) 
//				{
//					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
//					boolean set	= setExceptionIfUndone(reason);
//					
//					// Send message to announce termination to remote
//					if(set)
//					{
//						Future res = new Future();
//	//					res.addResultListener(new IResultListener()
//	//					{
//	//						public void resultAvailable(Object result)
//	//						{
//	//							System.out.println("received result: "+result);
//	//						}
//	//						public void exceptionOccurred(Exception exception)
//	//						{
//	//							System.out.println("received exception: "+exception);
//	//						}
//	//					});
//						final String mycallid = SUtil.createUniqueId(compid.getName()+".term."+method.toString());
//						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, reason);
//						// Can be invoked directly, because internally redirects to agent thread.
//	//					System.out.println("sending terminate");
//						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), 
//							null, content, mycallid, to, res, nonfunc, sic);
//					}
//				}
//				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".term."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
//				
//				// Called from delegation listeners in RMS -> ignore if already terminated
//				public void setException(Exception exception)
//				{
//					super.setExceptionIfUndone(exception);
//				}
//			};
//		}
//		else if(SReflect.isSupertype(ITuple2Future.class, type))
//		{
//			future = new Tuple2Future();
//		}
//		else if(SReflect.isSupertype(IIntermediateFuture.class, type))
//		{
//			future = new IntermediateFuture();
//		}
//		else
//		{
//			future = new Future();
//		}
//		
////		FutureFunctionality func = new FutureFunctionality()
////		{
////			public IFuture terminate() 
////			{
////				Future res = new Future();
//////				res.addResultListener(new IResultListener()
//////				{
//////					public void resultAvailable(Object result)
//////					{
//////						System.out.println("received result: "+result);
//////					}
//////					public void exceptionOccurred(Exception exception)
//////					{
//////						System.out.println("received exception: "+exception);
//////					}
//////				});
////				final String mycallid = SUtil.createUniqueId(compid.getLocalName()+"."+method.toString());
////				RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid);
////				// Can be invoked directly, because internally redirects to agent thread.
//////				System.out.println("sending terminate");
////				rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), 
////					content, mycallid, to, res);
////			
////				return IFuture.DONE;
////			}
////		};
////
////		future = FutureFunctionality.getDelegationFuture(type, func);
//		
//		Object ret = future;
//		
////		if(method.getName().indexOf("store")!=-1)
////			System.out.println("remote method invoc: "+method.getName());
//		
//		// Test if method is excluded.
//		if(pi.isExcluded(method))
//		{
//			Exception	ex	= new UnsupportedOperationException("Method is excluded from interface for remote invocations: "+method.getName());
//			ex.fillInStackTrace();
//			future.setException(ex);
//		}
//		else
//		{
//			// 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) && !(SReflect.isSupertype(IFuture.class, rt)) && ar.length==0)
//				{
//					Object res = pr.getCache().get(method.getName());
//					if(res instanceof Throwable && SReflect.isSupertype(Throwable.class, rt))
//					{
//						throw (Throwable)res;
//					}
//					else
//					{
//						return res;
//					}
//				}
//			}
//			
//			// 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()
//				{
//					@Classname("fin")
//					public IFuture execute(IInternalAccess ia)
//					{
//						rsms.getRemoteReferenceModule().decProxyCount(pr.getRemoteReference());
//						return IFuture.DONE;
//					}
//				});
//				return null;
//			}
//			
////			System.out.println("timeout: "+to);
//			
//			// Call remote method using invocation command.	
////			System.out.println("call: "+callid+" "+method);
////			if("getServices".equals(method.getName()))
////				debugcallid	= callid;
//			
//			// non-func is in command to let stream handlers access the properties in RMI processing
//			final RemoteMethodInvocationCommand content = new RemoteMethodInvocationCommand(
//				pr.getRemoteReference(), method, args, callid, IComponentIdentifier.LOCAL.get(), nonfunc);
//			
//			// Can be invoked directly, because internally redirects to agent thread.
////			System.out.println("invoke: "+method.getName());
////			if(method.getName().equals("getResult"))
////				System.out.println("sending invoke");
//			rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), 
//				null, content, callid, to, future, nonfunc, sic);
//			
//			// Provide alternative immediate future result, if method is asynchronous.
//			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	= new Future(null);
//			}
//		}
//		
//		// Wait for future, if blocking method.
//		if(!IFuture.class.isAssignableFrom(method.getReturnType()))
//		{
////			Thread.dumpStack();
//			if(future.isDone())
//			{
//				ret = future.get(null);
//			}
//			else
//			{
//				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);
//		}
//		
////		if(ret instanceof IFuture)
////		{
////			((IFuture)ret).addResultListener(new IResultListener()
////			{
////				public void resultAvailable(Object result)
////				{
////					notifyMethodListeners(false, proxy, method, args, callid);
////				}
////				
////				public void exceptionOccurred(Exception exception)
////				{
////					notifyMethodListeners(false, proxy, method, args, callid);
////				}
////			});
////		}
////		else
////		{
////			notifyMethodListeners(false, proxy, method, args, callid);
////		}
//	
//		return ret;
//	}
	
	/**
	 *  Create a return future of suitable type for a method call.
	 */
	protected Future createReturnFuture(final IComponentIdentifier compid, final String callid, 
		final Method method, final Class type, final long to, final Map nonfunc, final ServiceInvocationContext sic)
	{
		Future future;
		
		if(SReflect.isSupertype(IPullSubscriptionIntermediateFuture.class, type))
		{
			future = new PullSubscriptionIntermediateDelegationFuture()
			{
				public void pullIntermediateResult() 
				{
					Future res = new Future();
					final String mycallid = SUtil.createUniqueId(compid.getLocalName()+"."+method.toString());
					RemoteFuturePullCommand content = new RemoteFuturePullCommand(mycallid, callid);
					// Can be invoked directly, because internally redirects to agent thread.
//					System.out.println("sending terminate");
					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
						content, mycallid, to, res, nonfunc, sic);
				}
				
				public void terminate(Exception reason) 
				{
					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
					boolean	set	= setExceptionIfUndone(reason);
					
					// Send message to announce termination to remote
					if(set)
					{
						Future res = new Future();
	//					res.addResultListener(new IResultListener()
	//					{
	//						public void resultAvailable(Object result)
	//						{
	//							System.out.println("received result: "+result);
	//						}
	//						public void exceptionOccurred(Exception exception)
	//						{
	//							System.out.println("received exception: "+exception);
	//						}
	//					});
						final String mycallid = SUtil.createUniqueId(compid.getName()+".pullsub."+method.toString());
						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, reason);
						// Can be invoked directly, because internally redirects to agent thread.
	//					System.out.println("sending terminate");
						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
							content, mycallid, to, res, nonfunc, sic);
					}
				}
				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".pullsub."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
				
				// Called from delegation listeners in RMS -> ignore if already terminated
				public void setException(Exception exception)
				{
					super.setExceptionIfUndone(exception);
				}
			};
		}
		else if(SReflect.isSupertype(IPullIntermediateFuture.class, type))
		{
			future = new PullIntermediateDelegationFuture()
			{
				public void pullIntermediateResult() 
				{
					Future res = new Future();
					final String mycallid = SUtil.createUniqueId(compid.getLocalName()+"."+method.toString());
					RemoteFuturePullCommand content = new RemoteFuturePullCommand(mycallid, callid);
					// Can be invoked directly, because internally redirects to agent thread.
//					System.out.println("sending terminate");
					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
						content, mycallid, to, res, nonfunc, sic);
				}
				
				public void terminate(Exception reason) 
				{
					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
					boolean	set	= setExceptionIfUndone(reason);
					
					// Send message to announce termination to remote
					if(set)
					{
						Future res = new Future();
	//					res.addResultListener(new IResultListener()
	//					{
	//						public void resultAvailable(Object result)
	//						{
	//							System.out.println("received result: "+result);
	//						}
	//						public void exceptionOccurred(Exception exception)
	//						{
	//							System.out.println("received exception: "+exception);
	//						}
	//					});
						final String mycallid = SUtil.createUniqueId(compid.getName()+".pull."+method.toString());
						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, reason);
						// Can be invoked directly, because internally redirects to agent thread.
	//					System.out.println("sending terminate");
						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
							content, mycallid, to, res, nonfunc, sic);
					}
				}
				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".pull."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
				
				// Called from delegation listeners in RMS -> ignore if already terminated
				public void setException(Exception exception)
				{
					super.setExceptionIfUndone(exception);
				}
			};
		}
		else if(SReflect.isSupertype(ISubscriptionIntermediateFuture.class, type))
		{
			future = new SubscriptionIntermediateDelegationFuture()
			{
				public void terminate(Exception reason) 
				{
					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
					boolean	set	= setExceptionIfUndone(reason);
					
					// Send message to announce termination to remote
					if(set)
					{
						Future res = new Future();
	//					res.addResultListener(new IResultListener()
	//					{
	//						public void resultAvailable(Object result)
	//						{
	//							System.out.println("received result: "+result);
	//						}
	//						public void exceptionOccurred(Exception exception)
	//						{
	//							System.out.println("received exception: "+exception);
	//						}
	//					});
						final String mycallid = SUtil.createUniqueId(compid.getName()+".sub."+method.toString());
						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, reason);
						// Can be invoked directly, because internally redirects to agent thread.
	//					System.out.println("sending terminate");
						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
							content, mycallid, to, res, nonfunc, sic);
					}
				}
				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".sub."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
				
				// Called from delegation listeners in RMS -> ignore if already terminated
				public void setException(Exception exception)
				{
					super.setExceptionIfUndone(exception);
				}
				
//				public void addResultListener(IResultListener listener) 
//				{
//					if(method.getName().indexOf("calculate")!=-1)
//						System.out.println("dfg");
//						
//					super.addResultListener(listener);
//				}
			};
		}
		else if(SReflect.isSupertype(ITerminableIntermediateFuture.class, type))
		{
			future = new TerminableIntermediateDelegationFuture()
			{
				public void terminate(Exception e) 
				{
					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
					boolean	set	= setExceptionIfUndone(e);
					
					// Send message to announce termination to remote
					if(set)
					{
						Future res = new Future();
	//					res.addResultListener(new IResultListener()
	//					{
	//						public void resultAvailable(Object result)
	//						{
	//							System.out.println("received result: "+result);
	//						}
	//						public void exceptionOccurred(Exception exception)
	//						{
	//							System.out.println("received exception: "+exception);
	//						}
	//					});
						final String mycallid = SUtil.createUniqueId(compid.getName()+".interm."+method.toString());
						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, e);
						// Can be invoked directly, because internally redirects to agent thread.
	//					System.out.println("sending terminate");
						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), 
							null, content, mycallid, to, res, nonfunc, sic);
					}
				}
				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".interm."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
				
				// Called from delegation listeners in RMS -> ignore if already terminated
				public void setException(Exception exception)
				{
					super.setExceptionIfUndone(exception);
				}
			};
		}
		else if(SReflect.isSupertype(ITerminableFuture.class, type))
		{
			future = new TerminableDelegationFuture()
			{
				public void terminate(Exception reason) 
				{
					// Set exception for local state (as rms removes waiting call, cannot receive remote result any more)
					boolean set	= setExceptionIfUndone(reason);
					
					// Send message to announce termination to remote
					if(set)
					{
						Future res = new Future();
	//					res.addResultListener(new IResultListener()
	//					{
	//						public void resultAvailable(Object result)
	//						{
	//							System.out.println("received result: "+result);
	//						}
	//						public void exceptionOccurred(Exception exception)
	//						{
	//							System.out.println("received exception: "+exception);
	//						}
	//					});
						final String mycallid = SUtil.createUniqueId(compid.getName()+".term."+method.toString());
						RemoteFutureTerminationCommand content = new RemoteFutureTerminationCommand(mycallid, callid, reason);
						// Can be invoked directly, because internally redirects to agent thread.
	//					System.out.println("sending terminate");
						rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), 
							null, content, mycallid, to, res, nonfunc, sic);
					}
				}
				
//				public void sendBackwardCommand(Object info)
//				{
//					Future res = new Future();
//					final String mycallid = SUtil.createUniqueId(compid.getName()+".term."+method.toString());
//					RemoteFutureBackwardCommand content = new RemoteFutureBackwardCommand(mycallid, callid, info);
//					// Can be invoked directly, because internally redirects to agent thread.
////					System.out.println("sending backward cmd");
//					rsms.sendMessage(pr.getRemoteReference().getRemoteManagementServiceIdentifier(), null,
//						content, mycallid, to, res, nonfunc, sic);
//				}
				
				// Called from delegation listeners in RMS -> ignore if already terminated
				public void setException(Exception exception)
				{
					super.setExceptionIfUndone(exception);
				}
			};
		}
		else if(SReflect.isSupertype(ITuple2Future.class, type))
		{
			future = new Tuple2Future();
		}
		else if(SReflect.isSupertype(IIntermediateFuture.class, type))
		{
			future = new IntermediateFuture();
		}
		else
		{
			future = new Future();
		}
		
		return future;
	}
	
	/**
	 *  Determine return type of method.
	 */
	public Class determineReturnType(Object proxy, final Method method, Object[] args)
	{
		Class ret = null;
		
		// Hack! special case schedule step, which may return different
		// kinds of result types according to the concrete step used.
		if(schedulestep.equals(method))
		{
			try
			{
				Method m = args[0].getClass().getMethod("execute", new Class[]{IInternalAccess.class});
				ret = m.getReturnType();
			}
			catch(Exception e)
			{
				throw new RuntimeException(e);
			}
		}
		else
		{
			ret = method.getReturnType();
		}
		
		return ret;
	}
	
	/**
	 *  Get the pr.
	 *  @return the pr.
	 */
	public ProxyReference getProxyReference()
	{
		return pr;
	}
	
	/**
	 *  Check if a switch call should be done.
	 *  @return True, if switch should be done.
	 */
	public boolean isSwitchCall()
	{
		return false;
	}
	
	/**
	 *  Get the target resolver.
	 *  @return The target resolver.
	 */
	protected ITargetResolver getTargetResolver()
	{
		if(tr==null)
		{
			Class cl = pr.getProxyInfo().getTargetResolverClazz();
			if(cl!=null)
			{
				try
				{
					tr = cl.newInstance();
				}
				catch(RuntimeException e)
				{
					throw e;
				}
				catch(Exception e)
				{
					throw new RuntimeException(e);
				}
			}
		}
		
		return tr;
	}
	
	/**
	 *  Test equality.
	 */
	public boolean equals(Object obj)
	{
		boolean ret = obj instanceof RemoteMethodInvocationHandler;
		if(ret)
		{
			ret = pr.getRemoteReference().equals(((RemoteMethodInvocationHandler)obj)
				.getProxyReference().getRemoteReference());
		}
		return ret;
	}
	
	/**
	 *  Hash code.
	 */
	public int hashCode()
	{
		return 31 + pr.getRemoteReference().hashCode();
	}
}