/* * * Fosstrak LLRP Commander (www.fosstrak.org) * * Copyright (C) 2014 KAIST * @author Janggwan Im <limg00n@kaist.ac.kr> * * Copyright (C) 2008 ETH Zurich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> * */ package kr.ac.kaist.resl.fosstrak.ale; import java.util.LinkedList; import org.fosstrak.llrp.adaptor.queue.QueueEntry; import org.fosstrak.llrp.client.LLRPExceptionHandlerTypeMap; import org.fosstrak.llrp.adaptor.exception.LLRPRuntimeException; import org.llrp.ltk.exceptions.InvalidLLRPMessageException; /** * an LLRPAdaptorWorker holds an Adaptor and a callback. the worker * enqueues messages and dispatches them to the corresponding reader. * through the callback it can retrieve messages that then will be * dispatched to the MessageRepository. * @author sawielan * */ public class AdaptorWorker implements Runnable { /** the worker does not accept more messages in the queue than this threshold. */ public static final int QUEUE_THRESHOLD = 100; /** the callback for asynchronous message retrieval. */ private AdaptorCallback callback = null; /** the adaptor holding the connection to the readers. */ private Adaptor adaptor = null; /** the queue holding messages to be sent to readers. */ private LinkedList<QueueEntry> outQueue = new LinkedList<QueueEntry> (); /** as long as this value is set to true the worker will accept and process messages. */ private boolean isRunning = true; /** the ip address of this adaptor. if its the local adaptor it returns null. */ private String adaptorIpAddress = null; /** * the number of connection failures. The initial value is chosen in * such a way that upon startup erroneous adaptors get cleaned out. * */ private int connFailures = 2; /** the number of allowed connection failures between adaptor and client. */ public static final int MAX_CONN_FAILURES = 3; /** * creates a new LLRPAdaptorWorker. * @param callback the callback for asynchronous message retrieval. * @param adaptor the adaptor holding the connection to the readers. */ public AdaptorWorker(AdaptorCallback callback, Adaptor adaptor) { this.callback = callback; callback.setWorker(this); this.adaptor = adaptor; } public void run() { while (isRunning) { try { QueueEntry entry = null; synchronized (outQueue) { // if the outQueue is empty we put this thread to sleep. // when someone posts a new message to the queue to // poster has to call the notifyAll() method and by // that awake this thread. while (outQueue.isEmpty()) outQueue.wait(); // the thread has been awakened and is now able to // process the first element in the queue. entry = outQueue.removeFirst(); process(entry); } } catch (InterruptedException e) { e.printStackTrace(); } } } /** * call this method if you want to stop the worker thread. */ public void tearDown() { // set isRunning to false. isRunning = false; // wakeup the thread to let it stop. synchronized (outQueue) { outQueue.notifyAll(); } } /** * send a queued element through the adaptor to the reader. * @param entry the queued element to be sent. */ private void process(QueueEntry entry) { try { getAdaptor().sendLLRPMessage(entry.getReaderName(), entry.getMessage().encodeBinary()); } catch (LLRPRuntimeException e) { AdaptorManagement.getInstance().postException(new LLRPRuntimeException(e.getMessage()), LLRPExceptionHandlerTypeMap.EXCEPTION_MSG_SENDING_ERROR, entry.getAdaptorName(), entry.getReaderName()); } catch (InvalidLLRPMessageException e) { AdaptorManagement.getInstance().postException(new LLRPRuntimeException(e.getMessage()), LLRPExceptionHandlerTypeMap.EXCEPTION_MSG_SYNTAX_ERROR, entry.getAdaptorName(), entry.getReaderName()); } catch (Exception e) { AdaptorManagement.getInstance().postException(new LLRPRuntimeException(e.getMessage()), LLRPExceptionHandlerTypeMap.EXCEPTION_MSG_SENDING_ERROR, entry.getAdaptorName(), entry.getReaderName()); } } /** * returns the callback for asynchronous message retrieval. * @return the callback for asynchronous message retrieval. */ public AdaptorCallback getCallback() { return callback; } /** * sets the callback for asynchronous message retrieval. * @param callback the callback for asynchronous message retrieval. */ public void setCallback(AdaptorCallback callback) { this.callback = callback; } /** * the adaptor holding the connection to the readers. * @return the adaptor holding the connection to the readers. */ public Adaptor getAdaptor() { return adaptor; } /** * sets the adaptor holding the connection to the readers. * @param adaptor the adaptor holding the connection to the readers. */ public void setAdaptor(Adaptor adaptor) { this.adaptor = adaptor; } /** * signals whether this worker is ready to accept messages. * @return true if ok, else otherwise. */ public boolean isReady() { if (outQueue.size() >= QUEUE_THRESHOLD) { return false; } return true; } /** * enqueues a message to be sent. * @param e the queue element holding the message. * @throws LLRPRuntimeException when worker is not ready or queue is full */ public void enqueue(QueueEntry e) throws LLRPRuntimeException { if (!isReady()) { throw new LLRPRuntimeException("Queue is full or worker not ready."); } synchronized (outQueue) { outQueue.add(e); outQueue.notifyAll(); } } /** * returns the ip address of this adaptor. if its the local adaptor it returns null. * @return null if local adaptor else the address of the adaptor. */ public String getAdaptorIpAddress() { return adaptorIpAddress; } /** * sets the address of this adaptor. if its the local adaptor set null. * @param adaptorIpAddress the address of the adaptor. */ public void setAdaptorIpAddress(String adaptorIpAddress) { this.adaptorIpAddress = adaptorIpAddress; } /** * increases the connection failure counter by one. */ public void reportConnFailure() { connFailures++; } /** * resets the connection failure counter to zero. */ public void cleanConnFailure() { connFailures = 0; } /** * @return true if connection to adaptor is alright, false otherwise. */ public boolean ok() { return (connFailures < MAX_CONN_FAILURES); } }