/* * * 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.rmi.AlreadyBoundException; import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Logger; import org.fosstrak.llrp.adaptor.Constants; import org.fosstrak.llrp.adaptor.config.AdaptorConfiguration; import org.fosstrak.llrp.adaptor.config.ConfigurationLoader; import org.fosstrak.llrp.adaptor.config.ReaderConfiguration; import org.fosstrak.llrp.adaptor.exception.LLRPDuplicateNameException; import org.fosstrak.llrp.adaptor.exception.LLRPRuntimeException; import org.fosstrak.llrp.adaptor.queue.QueueEntry; import org.fosstrak.llrp.client.LLRPExceptionHandler; import org.fosstrak.llrp.client.LLRPExceptionHandlerTypeMap; import org.fosstrak.llrp.client.MessageHandler; import org.llrp.ltk.types.LLRPMessage; /** * The AdaptorManagement handles your adaptors, enqueues LLRPMessages, handles * errors from the reader site and notifies you about incoming LLRPMessages.<br/> * <br/> * There are some common pitfalls when using the AdaptorManagement: * <ul> * <li>you must specify the repository where the messages shall be logged to (see example)</li> * <li>you must register an exception handler (see example)</li> * <li>you must shutdown the AdaptorManagement through the provided * shutdown method. Otherwise the reader connections don't get shutdown properly (see example)</li> * </ul> * <br/> * Below there is some sample-code, how you can use the AdaptorManagement: * <p> * <code>// create a message handler</code><br/> * <code>MessageHandler msgHandler = new MessageHandler();</code><br/> * <br/> * <code>// create an exception handler</code><br/> * <code>ExceptionHandler handler = new ExceptionHandler();</code><br/> * <br/> * <code>// run the initializer method</code><br/> * <code>String readConfig = Utility.findWithFullPath("/readerDefaultConfig.properties");</code><br/> * <code>String writeConfig = readConfig;</code><br/> * <code>boolean commitChanges = true;</code><br/> * <code>AdaptorManagement.getInstance().initialize(</code><br/> * <code>    readConfig, storeConfig, commitChanges, handler, msgHandler);</code><br/> * <br/> * <code>// now the management should be initialized and ready to be used</code><br/> * <br/> * <code>// create an adaptor</code><br/> * <code>String adaptorName = "myAdaptor";</code><br/> * <code>AdaptorManagement.getInstance().define(adaptorName, "localhost");</code><br/> * <br/> * <code>// create a reader</code><br/> * <code>String readerName = "myReader";</code><br/> * <code>Adaptor adaptor = AdaptorManagement.getAdaptor(adaptorName);</code><br/> * <code>adaptor.define(readerName, "192.168.1.23", 5084, true, true);</code><br/> * <br/> * <code>//Enqueue some LLRPMessage on the adaptor</code><br/> * <code>AdaptorManagement.enqueueLLRPMessage(adaptorName, readerName, message);</code><br/> * <br/> * <code>// when you shutdown your application call the shutdown method</code><br/> * <code>AdaptorManagement.getInstance().shutdown();</code><br/> * </p> * @author sawielan * */ public class AdaptorManagement { /** the name for the default local adaptor. */ public static final String DEFAULT_ADAPTOR_NAME = "DEFAULT"; /** the logger. */ private static Logger log = Logger.getLogger(AdaptorManagement.class); /** the exception handler. */ private LLRPExceptionHandler exceptionHandler = null; /** * if storeConfig is set and commitChanges is true then all * the changes to the AdaptorManagement are committed to storeConfig. */ private boolean commitChanges = true; /** where the configuration shall be read from. */ private String readConfig = null; /** where the configuration shall be written to (if changes happen). */ private String storeConfig = null; /** * flags whether the AdaptorManagement has been initialized or not. * you cannot initialize it twice!. */ private boolean initialized = false; /** internal state keeper. if set to true, the first local adaptor gets exported by rmi. */ private boolean export = false; /** if there is a severe error in the adaptorManagement this is set to true */ private static boolean error = false; /** the exception that discribes the error condition. */ private static LLRPRuntimeException errorException = null; /** the error code for the exception handler. */ private static LLRPExceptionHandlerTypeMap errorType = null; /** if the configuration is load from file we can use this loader to read/write it */ private ConfigurationLoader configLoader = new ConfigurationLoader(); // we need to distinguish between local and remote adaptors as // for local adaptors we want to be able to store the configuration // at all the time. /** all the worker threads running an adaptor held by the management (local and remote adaptors). */ private Map<String, AdaptorWorker> workers = new ConcurrentHashMap<String, AdaptorWorker> (); /** all the worker threads running an adaptor held by the management (local adaptors). */ private Map<String, AdaptorWorker> localWorkers = new ConcurrentHashMap<String, AdaptorWorker> (); /** all the worker threads running an adaptor held by the management (remote adaptors). */ private Map<String, AdaptorWorker> remoteWorkers = new ConcurrentHashMap<String, AdaptorWorker> (); /** a list of handlers that like to receive all the LLRP messages. */ private LinkedList<MessageHandler> fullHandlers = new LinkedList<MessageHandler> (); /** these handlers would like to receive only certain LLRP Messages. */ private Map<Class, LinkedList<MessageHandler> > partialHandlers = new HashMap<Class, LinkedList<MessageHandler> > (); // ------------------------------- initialization ------------------------------- /** * initializes the AdaptorManagement. * @param readConfig where the configuration shall be read from. * @param storeConfig where the configuration shall be written to (if changes happen). * @param commitChanges if storeConfig is set and commitChanges is true then all * the changes to the AdaptorManagement are committed to storeConfig. * @param exceptionHandler the exception handler from the GUI. * @param handler a handler to dispatch the LLRP messages (can be set to null). * @throws LLRPRuntimeException whenever the AdaptorManagement could not be loaded. * @return returns * <ul> * <li>true if initialization has been performed</li> * <li>false if initialization has already been performed and therefore the * process was aborted</li> * </ul>. */ public boolean initialize( String readConfig, String storeConfig, boolean commitChanges, LLRPExceptionHandler exceptionHandler, MessageHandler handler) throws LLRPRuntimeException { return initialize(readConfig, storeConfig, commitChanges, exceptionHandler, handler, false); } /** * ATTENTION: initializes the AdaptorManagement.DO NOT USE THIS METHOD as long as you know * what you are doing (this method instructs with export=true to export the * first local adaptor as a server adaptor. * @param readConfig where the configuration shall be read from. * @param storeConfig where the configuration shall be written to (if changes happen). * @param commitChanges if storeConfig is set and commitChanges is true then all * the changes to the AdaptorManagement are committed to storeConfig. * @param exceptionHandler the exception handler from the GUI. * @param handler a handler to dispatch the LLRP messages (can be set to null). * @param export if the first local adaptor is to be exported by RMI or not. * @throws LLRPRuntimeException whenever the AdaptorManagement could not be loaded. * @return returns * <ul> * <li>true if initialization has been performed</li> * <li>false if initialization has already been performed and therefore the * process was aborted</li> * </ul>. */ public boolean initialize( String readConfig, String storeConfig, boolean commitChanges, LLRPExceptionHandler exceptionHandler, MessageHandler handler, boolean export) throws LLRPRuntimeException { if (initialized) { log.error("You cannot initialize the AdaptorManagement twice!\n" + "use the getters/setters to perform the requested changes!\n" + "we will abort now!!!"); return false; } this.export = export; this.readConfig = readConfig; this.storeConfig = storeConfig; this.commitChanges = commitChanges; this.exceptionHandler = exceptionHandler; if (null != handler) { registerFullHandler(handler); } load(); initialized = true; return true; } /** * flags whether the AdaptorManagement has already been initialized. * @return whether the AdaptorManagement has already been initialized. */ public boolean isInitialized() { return initialized; } /** * resets the management to initial state. * @throws LLRPRuntimeException if an error occurs during reset. */ public synchronized void reset() throws LLRPRuntimeException { if (!initialized) { throw new LLRPRuntimeException("AdaptorManagement is not initialized"); } clearWorkers(); // drop all the handlers synchronized (fullHandlers) { fullHandlers.clear(); } synchronized (partialHandlers) { partialHandlers.clear(); } load(); log.debug("finished reset"); } /** * loads the whole AdaptorManagement. * @throws LLRPRuntimeException when the configuration could not be loaded from file. */ private void load() throws LLRPRuntimeException { try { loadFromFile(); } catch (LLRPRuntimeException e) { setStatus(true, e, LLRPExceptionHandlerTypeMap.EXCEPTION_ADAPTOR_MANAGEMENT_NOT_INITIALIZED); throw e; } } /** * commits the configuration to the properties file. */ public void commit() { if (isCommitChanges()) { try { storeToFile(); } catch (LLRPRuntimeException e) { log.debug("could not commit the changes to the configuration file"); setStatus(true, e, LLRPExceptionHandlerTypeMap.EXCEPTION_ADAPTOR_MANAGEMENT_NOT_INITIALIZED); } } } /** * check whether the AdaptorManagement is ok or not. * if not, an exception is thrown and reported to the exception handler. */ public void checkStatus() throws LLRPRuntimeException { if (error) { postException(errorException, errorType, "", ""); throw errorException; } } /** * sets the status of the adaptorManagement. */ private void setStatus( boolean error, LLRPRuntimeException errorException, LLRPExceptionHandlerTypeMap errorType) { this.error = error; this.errorException = errorException; this.errorType = errorType; } /** * the client leaves the adaptor management. the management makes the * cleanup. */ public synchronized void shutdown() { log.debug("shutting AdaptorManagement down."); // first disconnect the local readers. disconnectReaders(); // remove the remote readers. synchronized (AdaptorManagement.class) { synchronized (workers) { synchronized (localWorkers) { synchronized (remoteWorkers) { for (AdaptorWorker worker : workers.values()) { // stop all the workers. worker.tearDown(); } // deregister the asynchronous callbacks for (AdaptorWorker worker : remoteWorkers.values()) { // stop all the workers. try { worker.getAdaptor().deregisterFromAsynchronous(worker.getCallback()); } catch (RemoteException e) { log.error("an error occured when deregistering from remote adaptor: " + e.getMessage()); } } } // synchronized remoteWorkers } // synchronized localWorkers } // synchronized workers } // synchronized adaptorManagement } // --------------------------- adaptor handling --------------------------- /** * remove all the adaptors before loading the new adaptors from configuration file. * @throws LLRPRuntimeException */ private synchronized void clearWorkers() throws LLRPRuntimeException { synchronized (workers) { synchronized (localWorkers) { synchronized (remoteWorkers) { // remove the workers. for (AdaptorWorker worker : workers.values()) { try { if (worker.getAdaptorIpAddress() == null) { // if it is a local adaptor undefine the readers worker.getAdaptor().undefineAll(); } undefine(worker.getAdaptor().getAdaptorName()); } catch (RemoteException e) { e.printStackTrace(); } } // erase all existing adaptors remoteWorkers.clear(); localWorkers.clear(); workers.clear(); } } } } /** * disconnectReaders shuts down all local readers. */ public void disconnectReaders() { synchronized (workers) { synchronized (localWorkers) { for (AdaptorWorker worker : localWorkers.values()) { try { worker.getAdaptor().disconnectAll(); } catch (RemoteException e) { e.printStackTrace(); } catch (LLRPRuntimeException e) { e.printStackTrace(); } } } } } /** * tells whether an adaptorName already exists. * @param adaptorName the name of the adaptor to check. * @throws LLRPRuntimeException whever something goes wrong ... * @return true if adaptor exists else false. */ public boolean containsAdaptor(String adaptorName) throws LLRPRuntimeException { checkStatus(); return workers.containsKey(adaptorName); } /** * checks, whether a given adapter is a local adapter or not. * @param adapterName the name of the adapter to check. * @return true if the adapter is local, false otherwise. * @throws LLRPRuntimeException whenever something goes wrong... */ public boolean isLocalAdapter(String adapterName) throws LLRPRuntimeException { checkStatus(); return localWorkers.containsKey(adapterName); } /** * adds a new adaptor to the adaptor list. * @param adaptorName the name of the new adaptor. * @param address if you are using a client adaptor you have to provide the address of the server stub. * @throws LLRPRuntimeException when either name already exists or when there occurs an error in adaptor creation. * @throws RemoteException when there is an error during transmition. * @throws NotBoundException when there is no registry available. */ public synchronized String define(String adaptorName, String address) throws LLRPRuntimeException, RemoteException, NotBoundException { checkStatus(); synchronized (workers) { synchronized (localWorkers) { synchronized (remoteWorkers) { Adaptor adaptor = null; if (address != null) { // try to get the instance from the remote // adaptor. int registryPort = 5001; Registry registry = LocateRegistry.getRegistry(address, Constants.registryPort); //Registry registry = LocateRegistry.getRegistry(address, registryPort); adaptor = (Adaptor) registry.lookup(Constants.adaptorNameInRegistry); // server adaptor always keeps its name. therefore // we rename the adaptor log.debug(String.format("adaptor is remote. therefore renaming %s to %s.", adaptorName, adaptor.getAdaptorName())); adaptorName = adaptor.getAdaptorName(); } // tests whether there exists already a adaptor of this name if (containsAdaptor(adaptorName)) { log.error("Adaptor '" + adaptorName + "' already exists!"); LLRPDuplicateNameException e = new LLRPDuplicateNameException(adaptorName, "Adaptor '" + adaptorName + "' already exists!"); postException( e, LLRPExceptionHandlerTypeMap.EXCEPTION_ADAPTOR_ALREADY_EXISTS, adaptorName, ""); throw e; } AdaptorCallback cb = null; AdaptorWorker worker = null; if (address == null) { // determine the special hopefully unique server adaptor name if (export) { // change the name of the adaptor to the ip of the current machine. String HOST_NAME_PREFIX = "server adaptor - "; String HOST_ADDRESS = String.format("unknown ip %d", System.currentTimeMillis()); try { java.net.InetAddress localMachine = java.net.InetAddress.getLocalHost(); HOST_ADDRESS = localMachine.getHostAddress(); } catch (java.net.UnknownHostException uhe) { log.debug("hmmm, what happened? " + "This should not occur here :-)."); } adaptorName = HOST_NAME_PREFIX + HOST_ADDRESS; } // local case adaptor = new AdaptorImpl(adaptorName); ((AdaptorImpl)adaptor).setAdaptorManagement(this); cb = new AdaptorCallback(false); worker = new AdaptorWorker(cb, adaptor); worker.setAdaptorIpAddress(null); localWorkers.put(adaptorName, worker); log.debug("created a new local adaptor '" + adaptorName + "'."); } else { // remote case cb = new AdaptorCallback(true); worker = new AdaptorWorker(cb, adaptor); // store the ip address of the remote adaptor. worker.setAdaptorIpAddress(address); remoteWorkers.put(adaptorName, worker); log.debug("created a new client adaptor '" + adaptorName + "' with url '" + address + "'."); } // register the callback. try { adaptor.registerForAsynchronous(cb); } catch (RemoteException e) { e.printStackTrace(); } // register the thread. workers.put(adaptorName, worker); // start the thread new Thread(worker).start(); // if the user requests an export of the adaptor we do this... // the adaptor HAS to be local! if ((export) && (address == null)) { // now export the adaptor // create the new registry log.debug("create a registry for the export of the local adaptor."); LocateRegistry.createRegistry(Constants.registryPort); Registry registry = LocateRegistry.getRegistry(Constants.registryPort); //int registryPort = 5001; //LocateRegistry.createRegistry(registryPort); //Registry registry = LocateRegistry.getRegistry(registryPort); log.debug("bind the adaptor to the registry"); try { registry.bind(Constants.adaptorNameInRegistry, adaptor); } catch (AlreadyBoundException e) { // this exception should NEVER occur as we destroy the // registry when we register the new adaptor. log.error("THERE WAS A SEVERE ERROR THAT SHOULD NEVER OCCUR!!!"); e.printStackTrace(); } } } } commit(); } return adaptorName; } /** * removes an adaptor from the adaptor list. * @param adaptorName the name of the adaptor to remove. * @throws LLRPRuntimeException when either the name does not exist or when an internal runtime error occurs. */ public synchronized void undefine(String adaptorName) throws LLRPRuntimeException { checkStatus(); synchronized (workers) { synchronized (localWorkers) { synchronized (remoteWorkers) { if (!containsAdaptor(adaptorName)) { log.error("Adaptor '" + adaptorName + "' does not exist!"); LLRPRuntimeException e = new LLRPRuntimeException("Adaptor '" + adaptorName + "' does not exist!"); postException( e, LLRPExceptionHandlerTypeMap.EXCEPTION_ADAPTER_NOT_EXIST, adaptorName, ""); throw e; } localWorkers.remove(adaptorName); remoteWorkers.remove(adaptorName); // remove the adaptor AdaptorWorker worker = workers.remove(adaptorName); try { worker.getAdaptor().deregisterFromAsynchronous(worker.getCallback()); // stop the worker. worker.tearDown(); } catch (RemoteException e) { e.printStackTrace(); } } } } commit(); } /** * returns a list of all the available adaptor names. * @return a list of all the available adaptor names. */ public List<String> getAdaptorNames() throws LLRPRuntimeException { checkStatus(); ArrayList<String> adaptorNames = new ArrayList<String> (); // make a deep copy (no leakage) for (AdaptorWorker worker : workers.values()) { try { adaptorNames.add(worker.getAdaptor().getAdaptorName()); worker.cleanConnFailure(); } catch (RemoteException e) { worker.reportConnFailure(); log.error("could not connect to remote adaptor: " + e.getMessage()); } } checkWorkers(); return adaptorNames; } /** * returns an adaptor to a given adaptorName. * @param adaptorName the name of the requested adaptor. * @return an adaptor to a given adaptorName. * @throws LLRPRuntimeException when the adaptor does not exist. */ public Adaptor getAdaptor(String adaptorName) throws LLRPRuntimeException { checkStatus(); if (!containsAdaptor(adaptorName)) { log.error("Adaptor '" + adaptorName + "' does not exist!"); LLRPRuntimeException e = new LLRPRuntimeException("Adaptor '" + adaptorName + "' does not exist!"); postException( e, LLRPExceptionHandlerTypeMap.EXCEPTION_ADAPTER_NOT_EXIST, adaptorName, ""); throw e; } return workers.get(adaptorName).getAdaptor(); } /** * helper to access the default local adaptor more convenient. * @return the default local adaptor. * @throws LLRPRuntimeException this should never occur! */ public AdaptorImpl getDefaultAdaptor() throws LLRPRuntimeException { checkStatus(); if (!workers.containsKey(DEFAULT_ADAPTOR_NAME)) { // create the default adaptor try { define(DEFAULT_ADAPTOR_NAME, null); } catch (Exception e) { // these two exceptions only occur in remote adaptors. // therefore we can safely ignore them log.debug("hmmm, what happened? This should not occur here :-)."); } } return (AdaptorImpl)getAdaptor(DEFAULT_ADAPTOR_NAME); } /** * you can check whether an adaptor is ready to accept messages. * @param adaptorName the name of the adaptor to check. * @return true when ok, else false. */ public boolean isReady(String adaptorName) throws LLRPRuntimeException { checkStatus(); if (!containsAdaptor(adaptorName)) { log.error("Adaptor '" + adaptorName + "' does not exist!"); LLRPRuntimeException e = new LLRPRuntimeException("Adaptor '" + adaptorName + "' does not exist!"); postException( e, LLRPExceptionHandlerTypeMap.EXCEPTION_ADAPTER_NOT_EXIST, adaptorName, ""); throw e; } return workers.get(adaptorName).isReady(); } // --------------------------- message and error handling --------------------------- /** * enqueue an LLRPMessage to be sent to a llrp reader. the adaptor will * process the message when ready. * @param adaptorName the name of the adaptor holding the llrp reader. * @param readerName the name of the llrp reader. * @param message the LLRPMessage. * @throws LLRPRuntimeException when the queue of the adaptor is full. */ public void enqueueLLRPMessage(String adaptorName, String readerName, LLRPMessage message) throws LLRPRuntimeException { checkStatus(); synchronized (workers) { AdaptorWorker theWorker = null; if (!workers.containsKey(adaptorName)) { postException(new LLRPRuntimeException("Adaptor does not exist"), LLRPExceptionHandlerTypeMap.EXCEPTION_ADAPTER_NOT_EXIST, adaptorName, readerName); } else { theWorker = workers.get(adaptorName); } if (!theWorker.isReady()) { LLRPRuntimeException e = new LLRPRuntimeException("Queue is full"); postException(e, LLRPExceptionHandlerTypeMap.EXCEPTION_READER_LOST, "AdaptorManagement", readerName); throw e; } log.debug("enqueueLLRPMessage(" + adaptorName + ", " + readerName + ")"); theWorker.enqueue(new QueueEntry(message, readerName, adaptorName)); } } /** * register a handler that will receive all the incoming messages. * @param handler the handler. */ public void registerFullHandler(MessageHandler handler) { synchronized (fullHandlers) { fullHandlers.add(handler); } } /** * remove a handler from the full handler list. * @param handler the handler to be removed. */ public void deregisterFullHandler(MessageHandler handler) { synchronized (fullHandlers) { fullHandlers.remove(handler); } } /** * tests whether a given handler is already registered or not. * @param handler the handler to check for. * @return true if the handler is present, false otherwise. */ public boolean hasFullHandler(MessageHandler handler) { synchronized (fullHandlers) { return fullHandlers.contains(handler); } } /** * register a handler that will receive only a restricted set of messages. * @param handler the handler. * @param clzz the type of messages that the handler likes to receive (example KEEPALIVE.class). */ public void registerPartialHandler(MessageHandler handler, Class clzz) { synchronized (partialHandlers) { LinkedList<MessageHandler> handlers = partialHandlers.get(clzz); if (null == handlers) { handlers = new LinkedList<MessageHandler> (); partialHandlers.put(clzz, handlers); } handlers.add(handler); } } /** * remove a handler from the handlers list. * @param handler the handler to remove. * @param clzz the class where the handler is registered. */ public void deregisterPartialHandler(MessageHandler handler, Class clzz) { synchronized (partialHandlers) { LinkedList<MessageHandler> handlers = partialHandlers.get(clzz); if (null != handlers) { synchronized (handlers) { handlers.remove(handler); } } } } /** * checks whether a given handler is registered at a given selector class. * @param handler the handler to check. * @param clzz the class where to search for the handler. * @return true if the handler is present, false otherwise. */ public boolean hasPartialHandler(MessageHandler handler, Class clzz) { synchronized (partialHandlers) { LinkedList<MessageHandler> handlers = partialHandlers.get(clzz); if (null != handlers) { synchronized (handlers) { return handlers.contains(handler); } } } return false; } /** * dispatches an LLRP message to all the registered full handlers. All the * handlers that have interest into the class of the message will be * informed as well. * @param adaptorName the name of the adapter that received the message. * @param readerName the reader that received the message. * @param message the LLRP message itself. */ public void dispatchHandlers(String adaptorName, String readerName, LLRPMessage message) { // handle full handlers... synchronized (fullHandlers) { for (MessageHandler handler : fullHandlers) { handler.handle(adaptorName, readerName, message); } } // handle partial handlers synchronized (partialHandlers) { LinkedList<MessageHandler> handlers = partialHandlers.get(message.getClass()); if (null != handlers) { synchronized (handlers) { for (MessageHandler handler : handlers) { handler.handle(adaptorName, readerName, message); } } } } } /** * posts an exception the the exception handler. * @param exceptionType the type of the exception. see {@link LLRPExceptionHandler} for more details. * @param adapterName the name of the adaptor that caused the exception. * @param readerName the name of the reader that caused the exception. * @param e the exception itself. */ public void postException( LLRPRuntimeException e, LLRPExceptionHandlerTypeMap exceptionType, String adapterName, String readerName) { if (exceptionHandler == null) { log.error("ExceptionHandler not set!!!"); e.printStackTrace(); return; } log.debug(String.format("Received error call on callback from '%s'.\nException:\n%s", readerName, e.getMessage())); exceptionHandler.postExceptionToGUI(exceptionType, e, adapterName, readerName); } // ------------------------------- singleton handling ------------------------------- /** private constructor for singleton. */ private AdaptorManagement() {} /** the instance of the singleton. */ private static AdaptorManagement instance = new AdaptorManagement(); /** * returns the singleton of the AdaptorManagement. * @return the singleton of the AdaptorManagement. */ public static AdaptorManagement getInstance() { return instance; } // ------------------------------- default config ------------------------------- private synchronized void createDefaultConfiguration() throws LLRPRuntimeException { // do not store this configuration storeConfig = null; // no config -> no changes to commit setCommitChanges(false); // clear the workers clearWorkers(); // create a default adaptor try { define(DEFAULT_ADAPTOR_NAME, null); } catch (RemoteException e) { e.printStackTrace(); } catch (NotBoundException e) { e.printStackTrace(); } } // ------------------------------- load and store ------------------------------- /** * loads the adaptorManagement configuration from file (holds the adaptors and the readers for the local adaptor). * all the adaptors defined currently get removed!!! the action is atomic, this means that depending on your * setting, the client might get blocked for a short moment! * @throws LLRPRuntimeException whenever there is an exception during restoring. */ public synchronized void loadFromFile() throws LLRPRuntimeException { if (readConfig == null) { // if the config cannot be read, then we inform the user about that // issue but then just use a default configuration log.info("config not specified -> create a default configuration"); createDefaultConfiguration(); return; } // store the commit mode. boolean commitMode = isCommitChanges(); setCommitChanges(false); boolean isExported = false; synchronized (AdaptorManagement.class) { synchronized (workers) { synchronized (localWorkers) { synchronized (remoteWorkers) { // clear out all available adaptors clearWorkers(); List<AdaptorConfiguration> configurations = null; try { configurations = configLoader.getConfiguration(readConfig); } catch (LLRPRuntimeException e) { log.info("could not read the config -> create a default configuration"); createDefaultConfiguration(); return; } for (AdaptorConfiguration adaptorConfiguration : configurations) { String adaptorName = adaptorConfiguration.getAdaptorName(); String adaptorIP = adaptorConfiguration.getIp(); if (adaptorConfiguration.isLocal()) { log.debug("Load local Adaptor"); adaptorIP = null; } else { log.debug(String.format("Load Remote Adaptor: '%s' on '%s'", adaptorName, adaptorConfiguration.getIp())); } boolean adaptorCreated = false; try { if ((export) && (isExported)) { // only export the first adaptor isExported = true; define(adaptorName, adaptorIP); } adaptorName = define(adaptorName, adaptorIP); adaptorCreated = true; log.debug(String.format("adaptor '%s' successfully created", adaptorName)); } catch (Exception e) { log.error(String.format("could not create adaptor '%s': %s", adaptorName, e.getMessage())); } // only create the readers when the adaptor has been created successfully // and if the adaptor is remote, we just retrieve the readers. if ((adaptorCreated) && (adaptorConfiguration.isLocal())) { // get a handle of the adaptor and register all the readers. Adaptor adaptor = getAdaptor(adaptorName); if (adaptorConfiguration.getReaderPrototypes() != null) { for (ReaderConfiguration readerConfiguration : adaptorConfiguration.getReaderPrototypes()) { String readerName = readerConfiguration.getReaderName(); String readerIp = readerConfiguration.getReaderIp(); int readerPort = readerConfiguration.getReaderPort(); boolean readerClientInitiated = readerConfiguration.isReaderClientInitiated(); boolean connectImmediately = readerConfiguration.isConnectImmediately(); log.debug(String.format("Load llrp reader: '%s' on '%s:%d', clientInitiatedConnection: %b, connectImmediately: %b", readerName, readerIp, readerPort, readerClientInitiated, connectImmediately)); // create the reader try { // try to establish the connection immediately adaptor.define(readerName, readerIp, readerPort, readerClientInitiated, connectImmediately); log.debug(String.format("reader '%s' successfully created", readerName)); } catch (RemoteException e) { log.error(String.format("could not create reader '%s'", readerName)); e.printStackTrace(); } } } } } } // synchronized remoteWorkers } // synchronized localWorkers } // synchronized workers } // synchronized adaptorManagement // restore the commit mode. setCommitChanges(commitMode); } /** * stores the configuration of the adaptor management to file. the remote adaptors get stored and for * the local adaptor all readers get stored as well. * @throws LLRPRuntimeException whenever there occurs an error during storage. */ public synchronized void storeToFile() throws LLRPRuntimeException { if (storeConfig == null) { log.info("Store config not specified, not storing the configuration."); return; } synchronized (AdaptorManagement.class) { synchronized (workers) { synchronized (localWorkers) { synchronized (remoteWorkers) { List<AdaptorConfiguration> configurations = new LinkedList<AdaptorConfiguration>(); for (String adaptorName : workers.keySet()) { String ip = workers.get(adaptorName).getAdaptorIpAddress(); boolean isLocal = false; if (ip == null) { isLocal = true; } configurations.add( new AdaptorConfiguration( adaptorName, ip, isLocal, null)); } for (AdaptorConfiguration configuration : configurations) { if (configuration.isLocal()) { List<ReaderConfiguration> readerConfigurations = new LinkedList<ReaderConfiguration> (); configuration.setReaderConfigurations(readerConfigurations); // get a handle on the adaptor Adaptor adaptor = getAdaptor(configuration.getAdaptorName()); try { for (String readerName : adaptor.getReaderNames()) { Reader reader = adaptor.getReader(readerName); boolean connectImmed = false; // somehow this causes bugs with MINA, if we start the reader at startup. boolean clientInit = reader.isClientInitiated(); String ip = reader.getReaderAddress(); int port = reader.getPort(); readerConfigurations.add(new ReaderConfiguration( readerName, ip, port, clientInit, connectImmed ) ); } } catch (RemoteException e) { // local configuration therefore we can ignore the remote exception. e.printStackTrace(); } } } try { configLoader.writeConfiguration(configurations, storeConfig); } catch (LLRPRuntimeException e) { postException(e, LLRPExceptionHandlerTypeMap.EXCEPTION_ADAPTOR_MANAGEMENT_CONFIG_NOT_STORABLE, "", ""); } } // synchronized remoteWorkers } // synchronized localWorkers } // synchronized workers } // synchronized adaptorManagement } // ------------------------------- getter and setter ------------------------------- /** * returns the exception handler. * @return the exception handler. */ public LLRPExceptionHandler getExceptionHandler() { return exceptionHandler; } /** * sets the exception handler. * @param exceptionHandler the exception handler. */ public void setExceptionHandler(LLRPExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; } /** * flags whether all changes to the AdaptorManagement get reflected to the * configuration file. * @return true if yes, false otherwise. */ public boolean isCommitChanges() { return commitChanges; } /** * sets whether all changes to the AdaptorManagement get reflected to the * configuration file. * @param commitChanges * <ul> * <li>true then the changes get stored back to the configuration immediately</li> * <li>false the changes are not stored back</li> * </ul> */ public void setCommitChanges(boolean commitChanges) { this.commitChanges = commitChanges; } /** * returns the configuration file where to read the settings. * @return the configuration file where to read the settings. */ public String getReadConfig() { return readConfig; } /** * sets the configuration file. * @param readConfig the configuration file. */ public void setReadConfig(String readConfig) { this.readConfig = readConfig; } /** * returns the configuration file where to store changes. * @return the configuration file where to store changes. */ public String getStoreConfig() { return storeConfig; } /** * sets the configuration file where to store changes. * @param storeConfig the configuration file where to store changes. */ public void setStoreConfig(String storeConfig) { this.storeConfig = storeConfig; } private synchronized void checkWorkers() { LinkedList<AdaptorWorker> error = new LinkedList<AdaptorWorker> (); synchronized (workers) { synchronized (localWorkers) { synchronized (remoteWorkers) { for (AdaptorWorker worker : workers.values()) { if (!worker.ok()) { error.add(worker); } } // remove the erroneous for (AdaptorWorker worker : error) { // remove from all the workers. workers.remove(worker); remoteWorkers.remove(worker); localWorkers.remove(worker); } } } } commit(); } }