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

jadex.platform.service.remote.commands.RemoteMethodInvocationCommand Maven / Gradle / Ivy

Go to download

The Jadex platform package contains implementations of platform services as well as the platform component itself.

There is a newer version: 3.0.117
Show newest version
package jadex.platform.service.remote.commands;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.ServiceCall;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.component.impl.IInternalExecutionFeature;
import jadex.bridge.service.IServiceIdentifier;
import jadex.bridge.service.annotation.Security;
import jadex.bridge.service.component.interceptors.CallAccess;
import jadex.bridge.service.search.SServiceProvider;
import jadex.commons.SReflect;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.ExceptionDelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IFutureCommandResultListener;
import jadex.commons.future.IIntermediateFuture;
import jadex.commons.future.IIntermediateFutureCommandResultListener;
import jadex.commons.future.ITerminableFuture;
import jadex.commons.future.IntermediateFuture;
import jadex.commons.transformation.annotations.Alias;
import jadex.platform.service.remote.IRemoteCommand;
import jadex.platform.service.remote.RemoteReference;
import jadex.platform.service.remote.RemoteReferenceModule;
import jadex.platform.service.remote.RemoteServiceManagementService;

/**
 *  Command for executing a remote method.
 */
@Alias("jadex.base.service.remote.commands.RemoteMethodInvocationCommand")
public class RemoteMethodInvocationCommand extends AbstractRemoteCommand
{
	//-------- attributes --------
	
	/** The remote reference. */
	protected RemoteReference rr;
	
	/** The method. */
	// Is not transferred, only used for preprocessing
	protected Method method;
	
	/** The methodname. */
	protected String methodname;
	
	/** The parameter types. */
	protected Class[] parametertypes;
	
	/** The parameter values. */
	protected Object[] parametervalues;
		
	/** The declared reference flag for the return value. */
	protected boolean returnisref;
	
	/** The call identifier. */
	protected String callid;
	
	/** The security level (set by postprocessing). */
	protected String securitylevel;
	
	/** The target object (set by postprocessing). */
	protected Object target;
	
	/** The caller. */
	protected IComponentIdentifier caller;
	
	//-------- constructors --------
	
	/**
	 *  Create a new remote method invocation command.
	 */
	public RemoteMethodInvocationCommand()
	{
	}
	
	/**
	 *  Create a new remote method invocation command. 
	 */
	public RemoteMethodInvocationCommand(RemoteReference rr, Method method, 
		Object[] parametervalues, String callid, IComponentIdentifier caller, Map nonfunc)
	{
		super(nonfunc);
//		if(method.getName().equals("secMethod"))
//			System.out.println("caller: "+caller);
		
		this.rr = rr;
		this.method = method;
		this.methodname = method.getName();
		this.parametertypes = method.getParameterTypes();
		this.parametervalues = parametervalues!=null? parametervalues.clone(): null;
		this.callid = callid;
		this.caller	= caller;
//		this.timeout = timeout;
//		System.out.println("rmi on client: "+callid+" "+methodname);
	}
	
	//-------- methods --------
	
	/**
	 *  Get the security level of the request.
	 */
	public String	getSecurityLevel()
	{
		return securitylevel;
	}

	/**
	 *  Preprocess command and replace if they are remote references.
	 */
	public IFuture	preprocessCommand(IInternalAccess component, final RemoteReferenceModule rrm, final IComponentIdentifier target)
	{
		Future	ret	= new Future();
		super.preprocessCommand(component, rrm, target)
			.addResultListener(new DelegationResultListener(ret)
		{
			public void customResultAvailable(Void result)
			{
				// Do we still need this code? Is done via post processor during marshalling.
//				if(parametertypes.length>0)
//				{
//					RMIPreProcessor preproc = new RMIPreProcessor(rrm);
//					boolean[] refs = SServiceProvider.getRemoteReferenceInfo(method, false);
//					WriteContext context = new WriteContext(null, new Object[]{target, null}, null, null);
//					for(int i=0; i	postprocessCommand(IInternalAccess component, RemoteReferenceModule rrm, final IComponentIdentifier target)
	{
		final Future ret = new Future();
		
		rrm.getTargetObject(getRemoteReference())
			.addResultListener(component.getComponentFeature(IExecutionFeature.class).createResultListener(new ExceptionDelegationResultListener(ret)
		{
			public void customResultAvailable(Object result)
			{
				try
				{
					RemoteMethodInvocationCommand.this.target	= result;
					method = result.getClass().getMethod(methodname, parametertypes);
					
					// Try to find security level.
					Security	sec	= null;
					List>	classes	= new ArrayList>();
					classes.add(result.getClass());
					for(int i=0; sec==null && i	clazz	= classes.get(i);
						try
						{
							Method	m	= clazz.getMethod(methodname, parametertypes);
							sec	= m.getAnnotation(Security.class);
						}
						catch(Exception e)
						{
						}
						
						if(sec==null)
						{
							sec	= clazz.getAnnotation(Security.class);
							if(sec==null)
							{
								classes.addAll(Arrays.asList((Class[])clazz.getInterfaces()));
								if(clazz.getSuperclass()!=null)
								{
									classes.add(clazz.getSuperclass());
								}
							}
						}
					}
					// Default to max security if not found.
					securitylevel	= sec!=null ? sec.value() : Security.PASSWORD;
					
					ret.setResult(null);
				}
				catch(Exception e)
				{
					super.exceptionOccurred(e);
				}
			}
		}));
		
		return ret;
	}

	/**
	 *  Execute the command.
	 *  @param lrms The local remote management service.
	 *  @return An optional result command that will be 
	 *  sent back to the command origin. 
	 */
	public IIntermediateFuture execute(IExternalAccess component, RemoteServiceManagementService rsms)
	{
		final IntermediateFuture ret = new IntermediateFuture();
		
//		if(caller==null && getMethodName().equals("status"))
//		{
//			System.out.println("dglkysfi");
//			Thread.dumpStack();
//		}
		
		// todo: non-functional props
		
		// RMS acts as representative of remote caller.
		IInternalAccess	ada	= IInternalExecutionFeature.LOCAL.get();
		IComponentIdentifier.LOCAL.set(caller);
		IInternalExecutionFeature.LOCAL.set(null);	// No adapter for remote component.
		Map props = getNonFunctionalProperties();
		
//		props.put("method3", method.getName());

//		if(ServiceCall.getInvocation0()!=null)
//		{
//			System.out.println("lsdjgho");
//		}
		
		ServiceCall.getOrCreateNextInvocation(props);
		
		invokeMethod(ret, rsms);
		
		CallAccess.resetNextInvocation();
		
		IComponentIdentifier.LOCAL.set(component.getComponentIdentifier());
		IInternalExecutionFeature.LOCAL.set(ada);
		
		return ret;
	}

	/**
	 *  Invoke remote method.
	 *  @param targetName The target object.
	 *  @param ret The result future.
	 */
	public void invokeMethod(final IntermediateFuture ret, final RemoteServiceManagementService rsms)
	{
//		final IntermediateFuture ret = new IntermediateFuture();
		
//		System.out.println("remote invoke: "+methodname);
		
//		if(methodname.indexOf("destroy")!=-1)
//			System.out.println("remote destroyComp");
		
		final IComponentIdentifier ridcom = getRealReceiver();
		
		try
		{
			final boolean terminable = SReflect.isSupertype(ITerminableFuture.class, method.getReturnType());
			
//			System.out.println("invoke: "+m);
			
			// Necessary due to Java inner class bug 4071957
			if(target.getClass().isAnonymousClass())
				method.setAccessible(true);

//			if(method.getName().indexOf("method")!=-1)
//			{
//				System.out.println("hhh: "+ServiceCall.getCurrentInvocation());
//				System.out.println("ggg: "+ServiceCall.getNextInvocation());
//			}
			
			final Object res = method.invoke(target, parametervalues);
			
//			if(methodname.indexOf("method")!=-1)
//				System.out.println("gggg");
			
//			Map nfunc = nonfunc;
//			ServiceCall sc = ServiceCall.getOrCreateNextInvocation(); // hmm has not been switched during call to last
//			ServiceCall sc = ServiceCall.getCurrentInvocation();
//			if(sc!=null)
//				nfunc = sc.getProperties();
			
			handleResultFuture(terminable, rsms, callid, res, terminable, methodname, ridcom, ret);
			
//			// Remember invocation for termination invocation
//			if(terminable) // or pullable
//			{
//				rsms.putProcessingCall(callid, res);
//				List cmds = rsms.removeFutureCommands(callid);
//				if(cmds!=null)
//				{
//					for(Runnable cmd: cmds)
//					{
//						cmd.run();
//					}
//				}
//			}
//			
//			if(res instanceof IIntermediateFuture)
//			{
//				((IIntermediateFuture)res).addResultListener(new IIntermediateFutureCommandResultListener()
//				{
//					int cnt = 0;
//					public void intermediateResultAvailable(Object result)
//					{
////						System.out.println("inter: "+result);
//						ret.addIntermediateResult(new RemoteIntermediateResultCommand(ridcom, result, callid, 
//							returnisref, methodname, false, getNonFunctionalProperties(), (IFuture)res, cnt++));
//					}
//					
//					public void finished()
//					{
////						System.out.println("fin");
//						ret.addIntermediateResult(new RemoteIntermediateResultCommand(ridcom, null, callid, 
//							returnisref, methodname, true, getNonFunctionalProperties(), (IFuture)res, cnt));
//						ret.setFinished();
//						rsms.removeProcessingCall(callid);
//					}
//					
//					public void resultAvailable(Object result)
//					{
////						System.out.println("ra");
//						ret.addIntermediateResult(new RemoteResultCommand(ridcom, result, null, callid, 
//							returnisref, methodname, getNonFunctionalProperties()));
//						ret.setFinished();
//						rsms.removeProcessingCall(callid);
//					}
//					
//					public void resultAvailable(Collection result)
//					{
////						System.out.println("ra");
//						ret.addIntermediateResult(new RemoteResultCommand(ridcom, result, null, callid, 
//							returnisref, methodname, getNonFunctionalProperties()));
//						ret.setFinished();
//						rsms.removeProcessingCall(callid);
//					}
//					
//					public void exceptionOccurred(Exception exception)
//					{
////						System.out.println("ex: "+exception);
//						ret.addIntermediateResult(new RemoteResultCommand(ridcom, null, exception, callid, 
//							false, methodname, getNonFunctionalProperties()));
//						ret.setFinished();
//						rsms.removeProcessingCall(callid);
//					}
//					public void commandAvailable(Type command)
//					{
//						ret.addIntermediateResult(new RemoteFutureSourceCommand(ridcom, command, callid, 
//							returnisref, methodname, getNonFunctionalProperties()));
//					}
//				});
//			}
//			else if(res instanceof IFuture)
//			{
//				((IFuture)res).addResultListener(new IFutureCommandResultListener()
//				{
//					public void resultAvailable(Object result)
//					{
//						ret.addIntermediateResult(new RemoteResultCommand(ridcom, result, null, callid, 
//							returnisref, methodname, getNonFunctionalProperties()));
//						ret.setFinished();
//						rsms.removeProcessingCall(callid);
//					}
//					
//					public void exceptionOccurred(Exception exception)
//					{
//						ret.addIntermediateResult(new RemoteResultCommand(ridcom, null, exception, callid, 
//							false, methodname, getNonFunctionalProperties()));
//						ret.setFinished();
//						rsms.removeProcessingCall(callid);
//					}
//					
//					public void commandAvailable(Type command)
//					{
//						ret.addIntermediateResult(new RemoteFutureSourceCommand(ridcom, command, callid, 
//							returnisref, methodname, getNonFunctionalProperties()));
//					}
//				});
//			}
//			else
//			{
//				ret.addIntermediateResult(new RemoteResultCommand(ridcom, res, null, callid, 
//					returnisref, methodname, getNonFunctionalProperties()));
//				ret.setFinished();
//				rsms.removeProcessingCall(callid);
//			}
		}
		catch(Exception exception)
		{
			if(exception instanceof InvocationTargetException
				&& ((InvocationTargetException)exception).getTargetException() instanceof Exception)
			{
				exception	= (Exception)((InvocationTargetException)exception).getTargetException();
			}
			ret.addIntermediateResult(new RemoteResultCommand(ridcom, null, exception, callid, 
				false, methodname, getNonFunctionalProperties()));
			ret.setFinished();
			rsms.removeProcessingCall(callid);
		}
		
//		return ret;
	}
	
	//-------- getter/setter methods --------

	/**
	 *  Get the methodname.
	 *  @return the methodname.
	 */
	public String getMethodName()
	{
		return methodname;
	}

	/**
	 *  Set the methodname.
	 *  @param methodname The methodname to set.
	 */
	public void setMethodName(String methodname)
	{
		this.methodname = methodname;
	}
	
	/**
	 *  Get the parametertypes.
	 *  @return the parametertypes.
	 */
	public Class[] getParameterTypes()
	{
		return parametertypes;
	}
	
	/**
	 *  Set the parametertypes.
	 *  @param parametertypes The parametertypes to set.
	 */
	public void setParameterTypes(Class[] parametertypes)
	{
		this.parametertypes = parametertypes.clone();
	}

	/**
	 *  Get the parametervalues.
	 *  @return the parametervalues.
	 */
	public Object[] getParameterValues()
	{
		return parametervalues;
	}

	/**
	 *  Set the parametervalues.
	 *  @param parametervalues The parametervalues to set.
	 */
	public void setParameterValues(Object[] parametervalues)
	{
		this.parametervalues = parametervalues.clone();
	}

	/**
	 *  Get the callid.
	 *  @return the callid.
	 */
	public String getCallId()
	{
		return callid;
	}

	/**
	 *  Set the callid.
	 *  @param callid The callid to set.
	 */
	public void setCallId(String callid)
	{
//		System.out.println("rmi on server: "+callid);
		this.callid = callid;
	}

	/**
	 *  Get the caller.
	 *  @return the caller.
	 */
	public IComponentIdentifier getCaller()
	{
		return caller;
	}

	/**
	 *  Set the caller.
	 *  @param caller The caller to set.
	 */
	public void setCaller(IComponentIdentifier caller)
	{
		this.caller = caller;
	}

	/**
	 *  Get the remote reference.
	 *  @return The remote reference.
	 */
	public RemoteReference getRemoteReference()
	{
		return rr;
	}

	/**
	 *  Set the remote reference.
	 *  @param rr The remote reference to set.
	 */
	public void setRemoteReference(RemoteReference rr)
	{
		this.rr = rr;
	}
	
	/**
	 *  Get the returnisref.
	 *  @return the returnisref.
	 */
	public boolean isReturnValueReference()
	{
		return returnisref;
	}

	/**
	 *  Set the returnisref.
	 *  @param returnisref The returnisref to set.
	 */
	public void setReturnValueReference(boolean returnisref)
	{
		this.returnisref = returnisref;
	}

	/**
	 *  Get the receiver component (if other than rms).
	 *  @return the real receiver.
	 */
	public IComponentIdentifier getSender()
	{
		return caller;
	}
	
	/**
	 *  Get the real receiver (other than rms).
	 *  @return the real receiver.
	 */
	public IComponentIdentifier getRealReceiver()
	{
		IComponentIdentifier ret = null;
		Object ti = getRemoteReference().getTargetIdentifier();
		if(ti instanceof IComponentIdentifier)
			ret = (IComponentIdentifier)ti;
		else if(ti instanceof IServiceIdentifier)
			ret = ((IServiceIdentifier)ti).getProviderId();
		
		return ret;
	}
	
	/**
	 *  Get the string representation.
	 */
	public String toString()
	{
		return "RemoteMethodInvocationCommand(remote reference=" + rr + ", methodname="
			+ methodname + ", callid=" + callid + ")";
	}
	
	/**
	 *  Handle the result future by checking what future it is and
	 *  sending intermediate results as commands. 
	 */
	public void handleResultFuture(boolean terminable, final RemoteServiceManagementService rsms, final String callid, final Object res,
		final boolean returnisref, final String methodname, final IComponentIdentifier rec, final IntermediateFuture ret)
//		final Map nonfunc)
	{
		// Remember invocation for termination invocation
		if(terminable) // or pullable
		{
			rsms.putProcessingCall(callid, res);
			List cmds = rsms.removeFutureCommands(callid);
			if(cmds!=null)
			{
				for(Runnable cmd: cmds)
				{
					cmd.run();
				}
			}
		}
		
		if(res instanceof IIntermediateFuture)
		{
			((IIntermediateFuture)res).addResultListener(new IIntermediateFutureCommandResultListener()
			{
				int cnt = 0;
				public void intermediateResultAvailable(Object result)
				{
//					System.out.println("inter: "+result);
					ret.addIntermediateResult(new RemoteIntermediateResultCommand(rec, result, callid, 
						returnisref, methodname, false, getNFProps(true), (IFuture)res, cnt++));
				}
				
				public void finished()
				{
//					System.out.println("fin");
					ret.addIntermediateResult(new RemoteIntermediateResultCommand(rec, null, callid, 
						returnisref, methodname, true, getNFProps(false), (IFuture)res, cnt));
					ret.setFinished();
					rsms.removeProcessingCall(callid);
				}
				
				public void resultAvailable(Object result)
				{
//					System.out.println("ra");
					ret.addIntermediateResult(new RemoteResultCommand(rec, result, null, callid, 
						returnisref, methodname, getNFProps(false)));
					ret.setFinished();
					rsms.removeProcessingCall(callid);
				}
				
				public void resultAvailable(Collection result)
				{
//					System.out.println("ra");
					ret.addIntermediateResult(new RemoteResultCommand(rec, result, null, callid, 
						returnisref, methodname, getNFProps(false)));
					ret.setFinished();
					rsms.removeProcessingCall(callid);
				}
				
				public void exceptionOccurred(Exception exception)
				{
//					System.out.println("ex: "+exception);
					ret.addIntermediateResult(new RemoteResultCommand(rec, null, exception, callid, 
						false, methodname, getNFProps(false)));
					ret.setFinished();
					rsms.removeProcessingCall(callid);
				}
				
				public void commandAvailable(Object command)
				{
					ret.addIntermediateResult(new RemoteFutureSourceCommand(rec, command, callid, 
						returnisref, methodname, getNFProps(true)));
				}
			});
		}
		else if(res instanceof IFuture)
		{
			((IFuture)res).addResultListener(new IFutureCommandResultListener()
			{
				public void resultAvailable(Object result)
				{
					ret.addIntermediateResult(new RemoteResultCommand(rec, result, null, callid, 
						returnisref, methodname, getNFProps(false)));
					ret.setFinished();
					rsms.removeProcessingCall(callid);
				}
				
				public void exceptionOccurred(Exception exception)
				{
					ret.addIntermediateResult(new RemoteResultCommand(rec, null, exception, callid, 
						false, methodname, getNFProps(false)));
					ret.setFinished();
					rsms.removeProcessingCall(callid);
				}
				
				public void commandAvailable(Object command)
				{
					ret.addIntermediateResult(new RemoteFutureSourceCommand(rec, command, callid, 
						returnisref, methodname, getNFProps(true)));
				}
			});
		}
		else
		{
			ret.addIntermediateResult(new RemoteResultCommand(rec, res, null, callid, 
				returnisref, methodname, getNFProps(false)));
			ret.setFinished();
			rsms.removeProcessingCall(callid);
		}
	}
	
	/**
	 *  Get the non functional props from the executed call.
	 *  @return The call props.
	 */
	protected Map getNFProps(boolean intermediate)
	{
//		if(method.getName().indexOf("method")!=-1)
//			System.out.println("aas");
		Map ret = nonfunc;
		// During intermediate results the call is still running and nf vals must be fetched from current invoc
		ServiceCall sc = intermediate? ServiceCall.getCurrentInvocation(): ServiceCall.getLastInvocation();
		if(sc!=null)
			ret = sc.getProperties();
		return ret;
	}
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy