package jadex.standalone.transport.niotcpmtp;
import jadex.commons.SUtil;
import jadex.standalone.transport.MessageEnvelope;
import jadex.standalone.transport.codecs.CodecFactory;
import jadex.standalone.transport.codecs.IEncoder;
import jadex.standalone.transport.niotcpmtp.NIOTCPTransport.Cleaner;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
/**
* NIO-TCP output connection for sending messages to a specific target address.
*/
class NIOTCPOutputConnection
{
//-------- constants --------
/** 5 sec timeout. */
public static final int TIMEOUT = 5000;
/** 2MB as message buffer. */
public static final int BUFFER_SIZE = 2* 1024 * 1024;
//-------- attributes --------
/** The client socket for sending data. */
protected SocketChannel sc;
/** The buffer. */
// protected ByteBuffer buffer;
/** The dead connection time. */
protected long deadtime;
/** The codec factory. */
protected CodecFactory codecfac;
/** The cleaner. */
protected Cleaner cleaner;
/** The classloader. */
protected ClassLoader classloader;
//-------- constructors --------
/**
* Create a new tcp connection for sending data.
* @param iaddr
* @param iport
* @throws IOException
*/
public NIOTCPOutputConnection(InetAddress iaddr, int iport, CodecFactory codecfac,
Cleaner cleaner, ClassLoader classloader) throws IOException
{
this.codecfac = codecfac;
this.cleaner = cleaner;
this.classloader = classloader;
// Create a non-blocking socket channel
this.sc = SocketChannel.open();
// todo: perform sending asynchronous to caller thread
//this.sc.configureBlocking(false);
// try
// {
// System.out.println("NIOTCP Connection: "+iaddr+":"+iport);
// Kick off connection establishment
// this.sc.connect(new InetSocketAddress(iaddr, iport)); // Requires this for non blocking (what about timeouts?)
sc.socket().connect(new InetSocketAddress(iaddr, iport) , TIMEOUT); // Doesn't work for non blocking.
// System.out.println("NIOTCP Connection: "+iaddr+":"+iport+" established");
// }
// catch(IOException e)
// {
// System.out.println("NIOTCP Connection: "+iaddr+":"+iport+" failed");
//// e.printStackTrace();
// throw e;
// }
// this.buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
//address = SMTransport.SERVICE_SCHEMA+iaddr.getHostAddress()+":"+iport;
}
//-------- methods --------
/**
* Send a message.
* @param msg The message.
* Sending is done synchronously on caller thread.
* (todo: relax synchronization by performing sends
* on extra sender thread of transport, only needed
* if message service is used in synchronous mode.)
*/
public synchronized void send(MessageEnvelope msg) throws IOException
{
// Code using preallocated buffer
// IEncoder enc = codecfac.getDefaultEncoder();
// byte codec_id = codecfac.getCodecId(enc.getClass());
// byte[] enc_msg = enc.encode(msg, classloader);
// int size = enc_msg.length+NIOTCPTransport.PROLOG_SIZE;
// buffer.put(codec_id);
// buffer.putInt(size);
// buffer.put(enc_msg);
// buffer.flip();
// sc.write(buffer);
// buffer.clear();
// cleaner.refresh();
// Code using new buffers
IEncoder enc = codecfac.getDefaultEncoder();
byte codec_id = codecfac.getCodecId(enc.getClass());
byte[] enc_msg = enc.encode(msg, classloader);
byte[] buffer = new byte[enc_msg.length+NIOTCPTransport.PROLOG_SIZE];
System.arraycopy(enc_msg, 0, buffer, NIOTCPTransport.PROLOG_SIZE, enc_msg.length);
System.arraycopy(SUtil.intToBytes(buffer.length), 0, buffer, 1, 4);
buffer[0] = codec_id;
sc.write(ByteBuffer.wrap(buffer));
cleaner.refresh();
}
/**
* Close the connection.
*/
public void close()
{
try
{
sc.close();
}
catch(IOException e)
{
//e.printStackTrace();
}
cleaner.remove();
}
}