package org.fosstrak.ale.server.llrp; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Properties; import org.apache.log4j.Logger; import org.fosstrak.ale.exception.DuplicateNameException; import org.fosstrak.ale.exception.NoSuchNameException; import org.fosstrak.ale.server.ALEApplicationContext; import org.fosstrak.ale.server.persistence.RemoveConfig; import org.fosstrak.ale.server.persistence.WriteConfig; import org.fosstrak.ale.server.persistence.type.PersistenceConfig; import org.fosstrak.ale.server.readers.LogicalReaderManager; import org.llrp.ltk.generated.messages.ADD_ACCESSSPEC; import org.llrp.ltk.generated.messages.ADD_ROSPEC; import org.llrp.ltk.generated.messages.DELETE_ROSPEC; import org.llrp.ltk.generated.messages.DISABLE_ROSPEC; import org.llrp.ltk.generated.messages.ENABLE_ACCESSSPEC; import org.llrp.ltk.generated.messages.ENABLE_ROSPEC; import org.llrp.ltk.generated.messages.START_ROSPEC; import org.llrp.ltk.generated.messages.STOP_ROSPEC; import org.llrp.ltk.generated.parameters.AccessSpec; import org.llrp.ltk.generated.parameters.ROSpec; import org.llrp.ltk.types.UnsignedInteger; import org.springframework.stereotype.Service; /** * ORANGE: This class manages the ROSPEC. * * @author wafa.soubra@orange.com */ @Service("llrpControllerManager") public class LLRPControllerManager { /** logger. */ private static final Logger LOG = Logger.getLogger(LLRPControllerManager.class.getName()); /** key = logical reader name, value = RoSpec */ private static HashMap<String, ROSpec> lrROSpecMap = new HashMap<String, ROSpec>(); /** key = logical reader name, value = physical reader*/ // TODO change the value to a list in case of a Composite Reader private static HashMap<String, String> lrPhysicalMap = new HashMap<String, String>(); /** key = physical reader name, value = logical reader name*/ private static HashMap<String, String> physicalLRMap = new HashMap<String, String>(); /** key = logical reader name, value = the LLRP thread */ // TODO change the value to a list in case of a Composite Reader private static HashMap <String, LLRPChecking> lrLLRPCheckMap= new HashMap<String, LLRPChecking>(); /** key = logical reader name, value = boolean, true if the LLRP connection is established */ private static HashMap <String, Boolean> physicalConnectedMap= new HashMap<String, Boolean>(); /** file containing the launching context of LLRP. */ private static final String LLRP_CONFIG_PROP_FILE="llrpConfig.properties"; /** the properties read from file. */ private static Properties props = null; /** flag to indicate if we wait for the acknowledge of the connection. */ private static boolean toWaitForConnection = true; /** key = logical reader name, value = AccessSpec */ private static HashMap<String, AccessSpec> lrAccessSpecMap = new HashMap<String, AccessSpec>(); /** * Add an ROSpec to a declared logical reader in the ALE and enable it. * @param lrSpecName the name of the logical reader * @param pathFile a file containing the description of the ADD_ROSPEC */ //* Note : if we define this method as a Web Method, JAXB fails at runtime //* because ADD_ROSPEC contains interfaces and JAXB cannot deserialize them. //* In our client, we call directly the "define(String lrSpecName, ADD_ROSPEC addRoSpec)" //* We can call the "define" webmethod in the LLRPControllerImpl which will call //* the "define" function below ==> MUST BE TESTED. public void define (String lrSpecName, String pathFile) throws DuplicateNameException, NoSuchNameException { ADD_ROSPEC addRoSpec = null; try { LOG.debug("pathfile of add_rospec is " + pathFile); addRoSpec = org.fosstrak.ale.util.DeserializerUtil.deserializeAddROSpec(pathFile); LOG.debug("ID of the deserialized add_rospec = " + addRoSpec.getROSpec().getROSpecID()); } catch (FileNotFoundException e) { LOG.error("add_rospec file not found " + pathFile, e); } catch (Exception e) { LOG.error("error to read add_rospec file " + pathFile, e); } define(lrSpecName, addRoSpec); } /** * Add a new RoSpec, enable it, launch the thread and persist the ADD_ROSPEC * @param lrSpecName the logical reader name * @param addRoSpec the ADD_ROSPEC object */ public void define(String lrSpecName, ADD_ROSPEC addRoSpec) throws DuplicateNameException, NoSuchNameException { if (addRoSpec != null) { LOG.debug("Define an ADD_ROSPEC for " + lrSpecName); // init the Connection and the LLRP context AdaptorMgmt.initializeLLRPContext(); String readerName= retrievePhysicalReader (lrSpecName); getLLRPConfiguration(); initClientConnection(readerName); // add ROSpec AdaptorMgmt.sendLLRPMessage(readerName, addRoSpec); // enable the ROSpec ENABLE_ROSPEC enableROSpec = new ENABLE_ROSPEC(); UnsignedInteger roSpecId = addRoSpec.getROSpec().getROSpecID(); enableROSpec.setROSpecID(roSpecId); AdaptorMgmt.sendLLRPMessage(readerName, enableROSpec); // init the internal data lrROSpecMap.put(lrSpecName, addRoSpec.getROSpec()); physicalLRMap.put(readerName, lrSpecName); //TODO: case of composite reader lrPhysicalMap.put(lrSpecName, readerName); //TODO: case of composite reader lrLLRPCheckMap.put(lrSpecName, new LLRPChecking(readerName)); // persistence ALEApplicationContext.getBean(WriteConfig.class).writeAddROSpec(lrSpecName, addRoSpec); LOG.debug("End Define an ADD_ROSPEC for " + lrSpecName); } else { LOG.error("ERROR !!!! ADD_ROSPEC is null for " + lrSpecName); } } /** * Delete the ROSpec defined on the logical reader, stop the thread and * remove the persisted file. * @param lrSpecName the name of the logical reader */ public void undefine(String lrSpecName) throws NoSuchNameException { LOG.debug("Undefine ROSPEC for " + lrSpecName); if (!lrROSpecMap.containsKey(lrSpecName)) { throw new NoSuchNameException("this logical reader doesn't exist"); } ROSpec roSpec = lrROSpecMap.get(lrSpecName); if (roSpec != null) { // stop the thread and remove it LLRPChecking llrpCheck = lrLLRPCheckMap.get(lrSpecName); llrpCheck.stop(); lrLLRPCheckMap.remove(lrSpecName); // delete the defined ROSpec and remove it DELETE_ROSPEC deleteRoSpec = new DELETE_ROSPEC(); deleteRoSpec.setROSpecID(roSpec.getROSpecID()); AdaptorMgmt.sendLLRPMessage(llrpCheck.getReaderName(), deleteRoSpec); // remove the lrSpecName from the HashMap lrROSpecMap.remove(lrSpecName); //persistence ALEApplicationContext.getBean(RemoveConfig.class).removeROSpec(lrSpecName); } LOG.debug("End Undefine ROSPEC for " + lrSpecName); } /** * Starts the RoSpec defined on the logical reader * @param lrSpecName the logical reader name */ public void start (String lrSpecName) throws NoSuchNameException { LOG.debug("Start ROSPEC for " + lrSpecName); if (!lrROSpecMap.containsKey(lrSpecName)) { throw new NoSuchNameException("this logical reader doesn't exist"); } ROSpec roSpec = lrROSpecMap.get(lrSpecName); String readerName = lrPhysicalMap.get(lrSpecName); if (roSpec != null && readerName != null) { START_ROSPEC startROSpec = new START_ROSPEC(); startROSpec.setROSpecID(roSpec.getROSpecID()); AdaptorMgmt.sendLLRPMessage(readerName, startROSpec); } LOG.debug("End Start ROSPEC for " + lrSpecName); } /** * Stop the RoSpec defined on the logical reader * @param lrSpecName the logical reader name */ public void stop(String lrSpecName) throws NoSuchNameException { LOG.debug("Stop ROSPEC for " + lrSpecName); if (!lrROSpecMap.containsKey(lrSpecName)) { throw new NoSuchNameException("this logical reader doesn't exist"); } ROSpec roSpec = lrROSpecMap.get(lrSpecName); String readerName = lrPhysicalMap.get(lrSpecName); if (roSpec != null && readerName != null) { STOP_ROSPEC stopROSpec = new STOP_ROSPEC(); stopROSpec.setROSpecID(roSpec.getROSpecID()); AdaptorMgmt.sendLLRPMessage(readerName, stopROSpec); } LOG.debug("End Stop ROSPEC for " + lrSpecName); } /** * Enable the RoSpec defined on the logical reader * @param lrSpecName the logical reader name */ public void enable(String lrSpecName) throws NoSuchNameException { LOG.debug("Enable ROSPEC for " + lrSpecName); if (!lrROSpecMap.containsKey(lrSpecName)) { throw new NoSuchNameException("this logical reader doesn't exist"); } ROSpec roSpec = lrROSpecMap.get(lrSpecName); String readerName = lrPhysicalMap.get(lrSpecName); if (roSpec != null && readerName != null) { ENABLE_ROSPEC enableROSpec = new ENABLE_ROSPEC(); enableROSpec.setROSpecID(roSpec.getROSpecID()); AdaptorMgmt.sendLLRPMessage(readerName, enableROSpec); } LOG.debug("End Enable ROSPEC for " + lrSpecName); } /** * Disable the RoSpec defined on the logical reader * @param lrSpecName the logical reader name */ public void disable(String lrSpecName) throws NoSuchNameException { LOG.debug("Disable ROSPEC for " + lrSpecName); if (!lrROSpecMap.containsKey(lrSpecName)) { throw new NoSuchNameException("this logical reader doesn't exist"); } ROSpec roSpec = lrROSpecMap.get(lrSpecName); String readerName = lrPhysicalMap.get(lrSpecName); if (roSpec != null && readerName != null) { DISABLE_ROSPEC disableROSpec = new DISABLE_ROSPEC(); disableROSpec.setROSpecID(roSpec.getROSpecID()); AdaptorMgmt.sendLLRPMessage(readerName, disableROSpec); } LOG.debug("End Disable ROSPEC for " + lrSpecName); } /** * Disable all defined RoSpec. */ public void disableAll() { LOG.debug("DisableAll ROSPEC on LLRP Readers"); for (String lrSpecName : lrROSpecMap.keySet()) { try { disable(lrSpecName); } catch (NoSuchNameException e) { LOG.error("try to stop lrSpec " + lrSpecName, e); } } LOG.debug("End DisableAll ROSPEC on LLRP Readers"); } /** * Add again the ROSpec and enable it. * @param readerName the physical reader name */ public void redefine (String readerName) { LOG.debug("Start Redefine for " + readerName); String logicalName = physicalLRMap.get(readerName); if (logicalName != null) { redefineROSpec (readerName,logicalName); redefineAccessSpec (readerName,logicalName); } else { LOG.error("Undefined logical reader for this physical reader " + readerName); } LOG.debug("End Redefine for " + readerName); } /** * Add again the ROSpec and enable it. * @param readerName the physical reader name * @param logicalName the logical reader name */ private void redefineROSpec (String readerName, String logicalName) { ROSpec roSpec = lrROSpecMap.get(logicalName); if (roSpec != null) { ADD_ROSPEC addRoSpec = new ADD_ROSPEC(); addRoSpec.setROSpec(roSpec); AdaptorMgmt.sendLLRPMessage(readerName, addRoSpec); ENABLE_ROSPEC enableROSpec = new ENABLE_ROSPEC(); enableROSpec.setROSpecID(roSpec.getROSpecID()); AdaptorMgmt.sendLLRPMessage(readerName, enableROSpec); } else { LOG.error("Undefined ROSpec for this physical reader " + readerName); } } /** * Set the connection of a reader * @param readerName the name of the physical reader * @param connected boolean if true the connection is established */ public void setReaderConnected (String readerName, boolean connected) { physicalConnectedMap.put(readerName, connected); } /** * Retrieves the name of the physical reader associated to the LR. * @param readerName the name of the physical reader * @return the physical reader name */ private String retrievePhysicalReader (String lrSpecName) throws DuplicateNameException, NoSuchNameException { if (!ALEApplicationContext.getBean(LogicalReaderManager.class).contains(lrSpecName)) { throw new NoSuchNameException("this logical reader doesn't exist"); } // Test if a LR with the given name already exists or // if we are adding another ROSpec to the same reader. if (lrROSpecMap.containsKey(lrSpecName) ) { throw new DuplicateNameException("This reader is already used"); } String readerName = null; try { readerName = ALEApplicationContext.getBean(LogicalReaderManager.class).getPropertyValue(lrSpecName, "PhysicalReaderName"); } catch (org.fosstrak.ale.exception.NoSuchNameException e) { LOG.error("Missing property PhysicalReaderName", e); } catch (org.fosstrak.ale.exception.ImplementationException e) { LOG.error("Error when trying to get property PhysicalReaderName", e); } catch (org.fosstrak.ale.exception.SecurityException e) { LOG.error("Error when trying to get property PhysicalReaderName", e); } return readerName; } /** * Get the launching configuration of LLRP. * 1) rifidiEmulator = true, when we test with the Rifidi Emulator. * The acknowledge of the connection "reader_event_connection" * is never sent to messageHandler in Fosstrak. * 2) waitConnection = false, if we don't want to wait for ACK of the connection. */ private void getLLRPConfiguration () { synchronized (LLRPControllerManager.class) { if (props == null) { props = new Properties(); // try to load the properties file try { FileInputStream fileInputStream = new FileInputStream(ALEApplicationContext.getBean(PersistenceConfig.class).getRealPathLLRPSpecDir() + LLRP_CONFIG_PROP_FILE); props.load(fileInputStream); Boolean rifidi = new Boolean(props.getProperty("rifidiEmulator")); Boolean wait = new Boolean (props.getProperty("waitConnection")); LOG.debug("rifidiEmulator " + rifidi); LOG.debug("waitConnection " + wait); if (rifidi || !wait) { toWaitForConnection=false; LOG.debug("toWaitForConnection " + toWaitForConnection); } } catch (FileNotFoundException e) { LOG.error("Config. file " + LLRP_CONFIG_PROP_FILE + " was not found: ", e); } catch (IOException e) { LOG.error("IO Exception when reading the config. file " + LLRP_CONFIG_PROP_FILE, e); } } } } /** * Wait until the LLRP connection between the client and the reader * is really established, and that to avoid sending several get_rospecs * messages from the LLRPChecking thread. * @param readerName the name of the physical reader */ private void initClientConnection (String readerName) { if (toWaitForConnection) { while (physicalConnectedMap.get(readerName)== null || !physicalConnectedMap.get(readerName)) { try { Thread.sleep(1000); } catch (InterruptedException e) { LOG.error("Error when init or waiting for the client connection ", e ); } } } } /**--------------------------------------------------------------------------------- * AccessSpec Methods * * --------------------------------------------------------------------------------- */ /** * ORANGE: Add a new AccessSpec * @param lrSpecName the logical reader name * @param addAccessSpec the ADD_ACCESSSPEC */ public void defineAccessSpec (String lrSpecName, ADD_ACCESSSPEC addAccessSpec) throws DuplicateNameException, NoSuchNameException { if (addAccessSpec != null) { LOG.debug("Define an ADD_ACCESSSPEC for " + lrSpecName); // init the Connection and the LLRP context : // not necessary because it has already be done by the ROSpec AdaptorMgmt.initializeLLRPContext(); String readerName= retrievePhysicalReader(lrSpecName); // add and enable the AccessSpec AdaptorMgmt.sendLLRPMessage(readerName, addAccessSpec); ENABLE_ACCESSSPEC enableAccessSpec = new ENABLE_ACCESSSPEC(); UnsignedInteger accessSpecId = addAccessSpec.getAccessSpec().getAccessSpecID(); enableAccessSpec.setAccessSpecID(accessSpecId); AdaptorMgmt.sendLLRPMessage(readerName, enableAccessSpec); // init the internal data lrAccessSpecMap.put(lrSpecName, addAccessSpec.getAccessSpec()); // persistence ALEApplicationContext.getBean(WriteConfig.class).writeAddAccessSpec(lrSpecName, addAccessSpec); LOG.info("End define an ADD_ACCESSSPEC for " + lrSpecName); } else { LOG.error("ERROR !!!! ADD_ACCESSSPEC is null for " + lrSpecName); } } /** * Add again if it exists the AccessSpec and enable it. * @param readerName the physical reader name * @param logicalName the logical reader name */ private void redefineAccessSpec (String readerName, String logicalName) { AccessSpec accessSpec = lrAccessSpecMap.get(logicalName); if (accessSpec != null) { ADD_ACCESSSPEC addAccessSpec = new ADD_ACCESSSPEC(); addAccessSpec.setAccessSpec(accessSpec); AdaptorMgmt.sendLLRPMessage(readerName, addAccessSpec); ENABLE_ACCESSSPEC enableAccessSpec = new ENABLE_ACCESSSPEC(); enableAccessSpec.setAccessSpecID(accessSpec.getAccessSpecID()); AdaptorMgmt.sendLLRPMessage(readerName, enableAccessSpec); } else { LOG.info("Undefined AccessSpec for this physical reader " + readerName); } } }