package kr.ac.kaist.resl.ltk.net;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.log4j.Logger;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.filter.executor.OrderedThreadPoolExecutor;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
/**
* LLRPAcceptor implements a remotely initiated LLRP connection.
*
* Here is a simple code example:
* <p>
* <code> LLRPAcceptor c = new LLRPAcceptor(endpoint); </code> <p>
* <code> c.bind(); </code> <p>
* <code> // wait for incoming reader initiated connection ..... </code> <p>
* <code> // send message asynchronously </code> <p>
* <code> c.send(llrpmessage); </code> <p>
* <code> // asynchronously LLRP messages arrive via LLRPEndpoint.messageReceived</code> <p>
* <code> // send message synchronously </code> <p>
* <code> LLRPMessage m = c.transact(llrpmessage); </code>
*
* @author Basil Gasser - ETH Zurich
* @author Christian Floerkemeier - MIT
*
*/
public class LLRPAcceptor extends LLRPConnection {
public static final int IDLE_TIME = 20;
private static final Logger log = Logger.getLogger(LLRPAcceptor.class);
private int port = 5084;
private IoAcceptor acceptor;
private InetSocketAddress socketAddress;
public LLRPAcceptor() {
super();
}
/**
* creates a remotely initiated LLRP connection on default PORT 5084
* and uses LLRPIoHandlerAdapterImpl by default
*
* @param endpoint that handles incoming, asynchronous LLRP messages
*/
public LLRPAcceptor(LLRPEndpoint endpoint){
this.endpoint = endpoint;
}
/**
* creates a remotely initiated LLRP connection and uses LLRPIoHandlerAdapterImpl by default
*
* @param endpoint that handles incoming, asynchronous LLRP messages
* @param port on which LLRPAcceptor is waiting for incoming connections
*/
public LLRPAcceptor(LLRPEndpoint endpoint, int port){
this.endpoint = endpoint;
this.port = port;
}
/**
* creates a remotely initiated LLRP connection and uses LLRPIoHandlerAdapterImpl by default
*
* @param endpoint that handles incoming, asynchronous LLRP messages
* @param port on which LLRPAcceptor is waiting for incoming connections
* @param handler which handles incoming LLRP messages
*/
public LLRPAcceptor(LLRPEndpoint endpoint, int port, LLRPIoHandlerAdapter handler){
super.endpoint = endpoint;
this.port = port;
super.handler = handler;
}
/**
* creates a remotely initiated LLRP connection on default PORT 5084
*
* @param endpoint that handles incoming, asynchronous LLRP messages
* @param handler which handles incoming LLRP messages
*/
public LLRPAcceptor(LLRPEndpoint endpoint, LLRPIoHandlerAdapter handler){
super.endpoint = endpoint;
super.handler = handler;
}
/**
* binds the LLRPIOHandler registered to the port specified. It
* does not wait for an incoming READER_NOTIFICATION message with a successful
* ConnectionAttemptEvent. Use the bind method where you can specify a timeout instead.
*/
public void bind() throws LLRPConnectionAttemptFailedException{
bind(0);
}
/**
* binds the LLRPIOHandler registered to the port specified. The bind method
* waits for an incoming READER_NOTIFICATION message with a successful
* ConnectionAttemptEvent for the timeout specified. If the timeout is set to zero,
* the bind method will not wait for an incoming READER_NOTIFICATION message.
*
* @param timeout time in ms
* @throws LLRPConnectionAttemptFailedException if ConnectionAttemptStatus 'Success' in READER_NOTIFICATION
* message is not received within time interval specified by timeout
*/
public void bind(long timeout) throws LLRPConnectionAttemptFailedException{
ExecutorService executor = new OrderedThreadPoolExecutor();
acceptor = new NioSocketAcceptor(Runtime.getRuntime().availableProcessors());
acceptor.getFilterChain().addLast("executor", new ExecutorFilter(executor));
acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new LLRPProtocolCodecFactory(LLRPProtocolCodecFactory.BINARY_ENCODING)));
// MINA 2.0
acceptor.setHandler(handler);
acceptor.getSessionConfig().setReadBufferSize( 2048 );
acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, IDLE_TIME );
// MINA 1.1
//SocketAcceptorConfig cfg = new SocketAcceptorConfig();
//cfg.getSessionConfig().setReceiveBufferSize(2048);
try {
socketAddress = new InetSocketAddress(port);
acceptor.bind(socketAddress);//, handler);
log.info("server listening on port "+port);
} catch (IOException e) {
log.error(e.getMessage());
throw new LLRPConnectionAttemptFailedException(e.getMessage());
}
//check if llrp reader reply with a status report to indicate connection success.
//the client shall not send any information to the reader until this status report message is received
if (timeout>0) {
checkLLRPConnectionAttemptStatus(timeout);
}
}
/**
* close acceptor socket.
*
**/
public void close(){
acceptor.unbind(socketAddress);
}
/**
* reconnect method. currently not implemented. always returns false.
*
**/
public boolean reconnect(){
return false;
}
/**
* get host address of reader device.
*
* @return the port
*/
public int getPort() {
return port;
}
/**
* @param port the port to set
*/
public void setPort(int port) {
this.port = port;
}
}