package kr.ac.kaist.resl.ltk.net; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.log4j.Logger; import org.apache.mina.core.future.WriteFuture; import org.apache.mina.core.session.IoSession; import kr.ac.kaist.resl.ltk.generated.enumerations.ConnectionAttemptStatusType; import kr.ac.kaist.resl.ltk.generated.parameters.ConnectionAttemptEvent; import org.llrp.ltk.types.LLRPMessage; /** * LLRPConnection represents an abstract interface for an LLRP connection at a LLRP reader or client. * The actual implementation differ depending on whether it is a self-initiated connection * or a remotely initiated connection. */ public abstract class LLRPConnection { public static final int CONNECT_TIMEOUT = 10000; public static final String SYNC_MESSAGE_ANSWER = "synchronousMessageAnswer"; protected LLRPEndpoint endpoint; protected LLRPIoHandlerAdapter handler; protected IoSession session; private Logger log = Logger.getLogger(LLRPConnection.class); public LLRPConnection(){ handler = new LLRPIoHandlerAdapterImpl(this); } /** * check whether ConnectionAttemptStatus in READER_NOTIFICATION message was set by reader * to 'Success'. * * @param timeout the wait time before reader replies with a status report * @throws LLRPConnectionAttemptFailedException */ protected void checkLLRPConnectionAttemptStatus(long timeout)throws LLRPConnectionAttemptFailedException{ try{ BlockingQueue<ConnectionAttemptEvent> connectionAttemptEventQueue = handler.getConnectionAttemptEventQueue(); ConnectionAttemptEvent connectionAttemptEvent = connectionAttemptEventQueue.poll(timeout, TimeUnit.MILLISECONDS); if(connectionAttemptEvent != null){ ConnectionAttemptStatusType status = connectionAttemptEvent.getStatus(); if(status.intValue() == ConnectionAttemptStatusType.Success){ log.info("LLRP reader reported successfull connection attempt (ConnectionAttemptEvent.Status = " + status.toString() + ")"); }else{ log.info("LLRP reader reported failed connection attempt (ConnectionAttemptStatus = " + status.toString() + ")"); throw new LLRPConnectionAttemptFailedException(status.toString()); } } else{ throw new LLRPConnectionAttemptFailedException("Connection request timed out after " + timeout + " ms."); } }catch(InterruptedException e){ e.printStackTrace(); throw new LLRPConnectionAttemptFailedException(e.getMessage()); } } /** * reconnect to existing connection * * @return boolean indicating failure (false) or success (true) */ public abstract boolean reconnect(); /** * sends an LLRP message without waiting for a response message. * * @param message LLRP message to be sent */ public void send(LLRPMessage message){ if (session == null){ log.warn("session is not yet established"); endpoint.errorOccured("session is not yet established"); return; } if(!session.isConnected()){ if(reconnect()){ session.write(message); }else{ log.info("session is not yet connected"); endpoint.errorOccured("session is not yet connected"); } }else{ session.write(message); } } /** * sends an LLRP message and returns the response message as defined in the * LLRP specification. * * @param message LLRP message to be sent * @return message LLRP response message */ public LLRPMessage transact(LLRPMessage message) throws TimeoutException{ return transact(message,0); } /** * sends an LLRP message and returns the response message as defined in the * LLRP specification timing out after the time interval specified. * * @param message LLRP message to be sent * @param transactionTimeout timeout * @return message LLRP response message */ public LLRPMessage transact(LLRPMessage message,long transactionTimeout) throws TimeoutException{ String returnMessageType = message.getResponseType(); if (returnMessageType.equals("")){ endpoint.errorOccured("message does not expect return message"); return null; } if (session == null){ log.warn("session is not yet established"); endpoint.errorOccured("session is not yet established"); return null; } session.setAttribute(SYNC_MESSAGE_ANSWER, returnMessageType); LLRPMessage returnMessage = null; if (!session.isConnected()){ if(!reconnect()){//reconnect failed log.info("session is not yet connected"); endpoint.errorOccured("session is not yet connected"); return null; } } WriteFuture writeFuture = session.write(message); log.info(message.getName() + " transact ...."); writeFuture.join(); // Wait until a message is received. try { BlockingQueue<LLRPMessage> synMessageQueue = handler.getSynMessageQueue(); returnMessage = transactionTimeout==0?synMessageQueue.take():synMessageQueue.poll(transactionTimeout, TimeUnit.MILLISECONDS); // if message received was not expected message, wait for next message (restart timer) while(returnMessage!=null && !returnMessage.getName().equals(returnMessageType)){ returnMessage = transactionTimeout==0?synMessageQueue.take():synMessageQueue.poll(transactionTimeout, TimeUnit.MILLISECONDS); } session.removeAttribute(SYNC_MESSAGE_ANSWER); if (returnMessage == null){ throw new TimeoutException("Request timed out after " + transactionTimeout + " ms."); } } catch (InterruptedException e) { e.printStackTrace(); } return returnMessage; } /** * returns the endpoint which receives incoming LLRPMessages * * @return the endpoint */ public LLRPEndpoint getEndpoint() { return endpoint; } /** * sets the endpoint which receives incoming LLRPMessages * * @param endpoint the endpoint to set */ public void setEndpoint(LLRPEndpoint endpoint) { this.endpoint = endpoint; } /** * returns the handler that handles incoming LLRPMessages and forwards them to LLRPEndpoint registered. * * @return the handler */ public LLRPIoHandlerAdapter getHandler() { return handler; } /** * sets the handler that handles incoming LLRPMessages and forwards them to LLRPEndpoint registered. * * @param handler the handler to set */ public void setHandler(LLRPIoHandlerAdapter handler) { this.handler = handler; } }