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

jadex.platform.service.message.AbstractSendTask 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.message;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jadex.bridge.IComponentIdentifier;
import jadex.bridge.ITransportComponentIdentifier;
import jadex.bridge.MessageFailureException;
import jadex.bridge.service.types.message.ICodec;
import jadex.bridge.service.types.message.IEncodingContext;
import jadex.bridge.service.types.message.MessageType;
import jadex.commons.IResultCommand;
import jadex.commons.SUtil;
import jadex.commons.Tuple2;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IResultListener;
import jadex.platform.service.message.transport.ITransport;

/**
 *  Abstract base class for sending a message with the message service.
 */
public abstract class AbstractSendTask implements ISendTask
{
	//-------- attributes --------
	
	/** The encoded message envelope. */
	protected volatile byte[] data;

	/** The message prolog. */
	protected volatile byte[] prolog;

	
	/** The codecids. */
	protected byte[] codecids;
	
	/** The codecs. */
	protected ICodec[] codecs;
	
	/** The encoding context */
	protected IEncodingContext encodingcontext;
	
	/** The managed receivers. */
	protected ITransportComponentIdentifier[] receivers;

	/** The transports to be tried. */
	protected List transports;
	
	/** The non-functional properties. */
	protected Map nonfunc;
	

	/** The future for the sending result. */
	protected Future	future;
	
	/** Is some transport interested in the task? */
	protected int	interest;
	
	/** True, if the token is acquired. */
	protected boolean	acquired;
	
	/** The list of waiting transports. */
	protected List, Void>>	waiting;

	//-------- constructors --------
	
	/**
	 *  Create a new task.
	 */
	public AbstractSendTask(ITransportComponentIdentifier[] receivers, 
		ITransport[] transports, ICodec[] codecs, Map nonfunc)
	{
		codecs = codecs==null? new ICodec[0]: codecs;

		for(int i=0; i(Arrays.asList(transports));
		this.codecs	= codecs.clone();
		this.nonfunc = nonfunc;
		this.future	= new Future();
	}
	
	/**
	 *  Shallow copy a task.
	 */
	public AbstractSendTask(AbstractSendTask task)
	{
		this.data	= task.data;
		this.prolog	= task.prolog;
		this.codecids	= task.codecids;
		this.codecs	= task.codecs;
		this.receivers	= task.receivers;
		this.transports	= task.transports;
		
		this.future	= new Future();
	}
	
	//-------- methods --------
	
	/**
	 *  Get the messagetype.
	 *  @return the messagetype.
	 */
	public abstract MessageType getMessageType();
	
	/**
	 *  Get the message.
	 *  @return the message.
	 */
	public abstract Object getMessage();
	
	/**
	 *  Get the receivers.
	 *  @return the receivers.
	 */
	public IComponentIdentifier[] getReceivers()
	{
		return receivers;
	}
	
	/**
	 *  Get the transports.
	 *  @return the transports.
	 */
	public List getTransports()
	{
		return transports;
	}
	
	/**
	 *  Get the future.
	 */
	public Future	getFuture()
	{
		return future;
	}
	
	/**
	 *  Get the encoded message.
	 *  Saves the message to avoid multiple encoding with different transports.
	 */
	public byte[] getData()
	{
		if(data==null)
		{
			synchronized(this)
			{
				if(data==null)
				{
					data = fetchData();
				}
			}
		}
		return data;
	}

	/**
	 *  Provide the data as a byte array.
	 */
	protected abstract byte[]	fetchData();
	
//	/**
//	 *  Set the data.
//	 *  @param data The data to set.
//	 */
//	public void setData(byte[] data)
//	{
//		this.data = data;
//	}
	
	/**
	 *  Get the prolog bytes.
	 *  Separated from data to avoid array copies.
	 *  Message service expects messages to be delivered in the form {prolog}{data}. 
	 *  @return The prolog bytes.
	 */
	public byte[] getProlog()
	{
		if(prolog==null)
		{
			synchronized(this)
			{
				if(prolog==null)
				{
					prolog = fetchProlog();
				}
			}
		}
		return prolog;
	}

	/**
	 *  Provide the prolog as a byte array.
	 */
	protected abstract byte[]	fetchProlog();
	
	/**
	 *  Get the non-functional requirements.
	 *  @return The non-functional properties.
	 */
	public Map getNonFunctionalProperties()
	{
//		System.out.println("nonfunc: "+nonfunc);
		return nonfunc;
	}

	/**
	 *  Use transports to send the message.
	 */
	public void doSendMessage()
	{
		// Fetch all addresses
		Set	addresses	= new LinkedHashSet();
		for(int i=0; i>	sendpairs	= new ArrayList>();
		for(int i=0; i(transport, address));
				}
			}
		}
		
		if(sendpairs.isEmpty())
		{
//			if(getMessage().toString().indexOf("IAutoTerminateService.subscribe()")!=-1)
//			{
//				System.out.println(hashCode()+": No transports available for sending message: "+ SUtil.arrayToString(receivers)+", "+SUtil.arrayToString(receivers[0].getAddresses())+", "+SUtil.arrayToString(getTransports()));
//			}

			getFuture().setException(new MessageFailureException(getMessage(), getMessageType(), receivers, 
				"No transports available for sending message: "+ SUtil.arrayToString(receivers)+", "+SUtil.arrayToString(receivers[0].getAddresses())+", "+SUtil.arrayToString(getTransports())));								
		}
		else
		{
			// For debug viewing which transports are used
//			if(this instanceof MapSendTask)
//				System.out.println("map sendoptions: "+sendpairs);
//			else
//				System.out.println("stream sendoptions: "+sendpairs);
			
			for(Tuple2 sendpair: sendpairs)
			{
				sendpair.getFirstEntity().sendMessage(sendpair.getSecondEntity(), this);
			}
		}
	}
	
	//--------- methods used by transports ---------
	
	/**
	 *  Called by the transport when is is ready to send the message,
	 *  i.e. when a connection is established.
	 *  @param send	The code to be executed to send the message.
	 */
	public void ready(IResultCommand, Void> send)
	{
//		if(getMessage().toString().indexOf("IAutoTerminateService.subscribe()")!=-1)
//		{
//			System.out.println(hashCode()+": ready: "+send);
//		}

		boolean	dosend;
		synchronized(this)
		{
			dosend	= !acquired && !future.isDone();
			acquired	= true;
			if(!dosend && !future.isDone())
			{
				if(waiting==null)
				{
					waiting	= new LinkedList, Void>>();
				}
				waiting.add(send);
			}
		}
		if(dosend)
		{
//			if(getMessage().toString().indexOf("IAutoTerminateService.subscribe()")!=-1)
//			{
//				System.out.println(hashCode()+": do send: "+send);
//			}

			try
			{
				send.execute(null).addResultListener(new IResultListener()
				{
					public void resultAvailable(Void result)
					{
						done(null);
					}
					
					public void exceptionOccurred(Exception exception)
					{
//						exception.printStackTrace();
						done(exception);
					}
				});
			}
			catch(Exception e)
			{
				done(e);
			}
		}
	}
	
	/**
	 *  The message sending is done. 
	 *  @param e	The exception (if any). Null denotes successful sending.
	 */
	protected void done(Exception e)
	{
//		if(getMessage().toString().indexOf("IAutoTerminateService.subscribe()")!=-1)
//		{
//			System.out.println(hashCode()+": sent: "+e);
//		}
		
		if(e!=null)
		{
			IResultCommand, Void>	next	= null;
			boolean	nointerest;
			synchronized(this)
			{
				interest--;
				nointerest	= interest==0;
				acquired	= false;
				if(waiting!=null && !waiting.isEmpty())
				{
					next	= waiting.remove(0);
				}
			}
			if(next!=null)
			{
				ready(next);
			}
			else if(nointerest)
			{
				future.setException(e);
			}
		}
		else
		{
			future.setResult(null);
		}
	}
	
	/**
	 *  Encode the object with the codecs.
	 */
	protected byte[] encode(Object obj, IEncodingContext context)
	{
		Object enc_msg = obj;
		for(int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy