org.accada.hal.impl.sim.SimulatorController.java Source code

Java tutorial

Introduction

Here is the source code for org.accada.hal.impl.sim.SimulatorController.java

Source

/*
 * Copyright (C) 2007 ETH Zurich
 *
 * This file is part of Accada (www.accada.org).
 *
 * Accada is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software Foundation.
 *
 * Accada 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Accada; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

/*
 * Created on 2005
 */
package org.accada.hal.impl.sim;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import org.accada.hal.AsynchronousIdentifyListener;
import org.accada.hal.ControllerProperties;
import org.accada.hal.HardwareAbstraction;
import org.accada.hal.HardwareException;
import org.accada.hal.MemoryBankDescriptor;
import org.accada.hal.MemoryDescriptor;
import org.accada.hal.Observation;
import org.accada.hal.ReadPointNotFoundException;
import org.accada.hal.TagDescriptor;
import org.accada.hal.Trigger;
import org.accada.hal.UnsignedByteArray;
import org.accada.hal.UnsupportedOperationException;
import org.accada.hal.transponder.EPCTransponderModel;
import org.accada.hal.transponder.IDType;
import org.accada.hal.util.ByteBlock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.xml.DOMConfigurator;

/**
 * The SimulatorController is a HAL controller that enables the implementation
 * of different kinds of RFID reader simulators/emulators.
 * 
 * From the HAL point of view the SimulatorController supports 
 * the same functionality as hardware controllers. Additionally it 
 * provides methods that allow a Simulator (i.e. SimulatorEngine) to 
 * (virtually) add and remove RFID tags. 
 * 
 * @author Roland Schneider
 */

public class SimulatorController implements HardwareAbstraction {

    /**
     * The logger.
     */
    private static Log log = LogFactory.getLog(SimulatorController.class);

    //------ Controller fields --------

    /**
     * The name of the HAL.
     */
    private String halName;

    /**
     * The properties file.
     */
    private String defaultPropFile = "/props/SimulatorController_default.xml";
    private String propFile;

    /**
     * The names of all available read points connected to this reader.
     */
    private String[] readPointNames;

    private int nOfReadPoints = 0;

    //----- Properties ----------------

    /**
     * props instance which encapulates all the methods responsible for parameter updates.
     * 
     * @uml.property name="props"
     * @uml.associationEnd multiplicity="(0 1)"
     */
    private ControllerProperties props = null;

    //----------- Simulator fields -----------------------

    /**
     * Java type of simulator to be loaded.
     */
    private String simType;

    /**
     * Properties file for simulator to be loaded and transponder models.
     */
    private String simTypePropFile;
    private String epcTransponderModelsConfig;

    /**
     * The Simulator.
     * 
     * @uml.property name="simulator"
     * @uml.associationEnd multiplicity="(0 1)"
     */
    private SimulatorEngine simulator;

    /**
     * This <code>HashMap</code> has an entry for each read point (antenna).
     * Entry: Key: readPoint (String)  Value: readpoint/antenna content (HashSet)
     */
    private HashMap reader;

    /**
     * Contains the names of all read points that are ready.
     */
    private Vector<String> readyReadPoints;

    /**
     * Contains the names of all read points whose next identify-operation will
     * fail.
     */
    public Vector<String> identifyError = new Vector<String>();

    /**
     * Contains the names of all read points whose next read-operation will
     * fail.
     */
    public Vector<String> readError = new Vector<String>();

    /**
     * Contains the names of all read points whose next write-operation will
     * fail.
     */
    public Vector<String> writeError = new Vector<String>();

    /**
     * Contains the names of all read points whose next kill-operation will
     * fail.
     */
    public Vector<String> killError = new Vector<String>();

    /**
     * Contains the names of all read points whose identify-operations will
     * always fail.
     */
    public Vector<String> continuousIdentifyErrors = new Vector<String>();

    /**
     * Contains the names of all read points whose read-operations will always
     * fail.
     */
    public Vector<String> continuousReadErrors = new Vector<String>();

    /**
     * Contains the names of all read points whose write-operations will always
     * fail.
     */
    public Vector<String> continuousWriteErrors = new Vector<String>();

    /**
     * Contains the names of all read points whose kill-operations will always
     * fail.
     */
    public Vector<String> continuousKillErrors = new Vector<String>();

    public SimulatorController(String halName, String propFile) {
        this.halName = halName;
        this.propFile = propFile;
        this.initialize();

        log.debug("Simulator: " + simType);
        reader = new HashMap();

        for (int i = 0; i < nOfReadPoints; i++) {
            reader.put(readPointNames[i], new HashSet());
        }

        try {
            //Dynamic class loading
            //1.) The full package path 
            Class clazz = Class.forName(simType);
            //2.) State the types of the constructors arguments. here: only one argument, of type String
            java.lang.reflect.Constructor co = clazz.getConstructor(new Class[] {});
            //3.) Create new instance with the argument's values
            simulator = (SimulatorEngine) co.newInstance(null);
            simulator.initialize(this, simTypePropFile);
        } catch (ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
            System.exit(1);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    /**
     * Initialize a reader.
     */
    public void initialize() {

        this.props = new ControllerProperties(propFile, defaultPropFile);

        //sets the parameters according to the properties file
        try {
            simType = props.getParameter("simType");
            simTypePropFile = props.getParameter("simTypePropFile");
            epcTransponderModelsConfig = props.getParameter("epcTransponderModelsConfig");

            nOfReadPoints = Integer.parseInt(props.getParameter("numberOfReadPoints"));
            readPointNames = new String[nOfReadPoints];
            readyReadPoints = new Vector<String>();
            for (int i = 0; i < nOfReadPoints; i++) {
                readPointNames[i] = this.props.getParameter("readPoint_" + (i + 1));
                readyReadPoints.add(readPointNames[i]);
            }
        } catch (Exception e) {
            String message = "Couldn't initialize the reader:" + e.getMessage();
            log.debug(message);
            e.printStackTrace();
        }
    }

    //-------------------- SimulatorEngine access methods ----------------------------
    /**
     * 
     * To move a certain tag to a certain antenna.
     * 
     * @param readPointName The name of the read point to which the tag should be added.
     * @param tag The tag object to be added to the antenna / read point.
     * 
     * @return Returns true if tag has been added. False if tag with same TagID already is in this antenna.
     */
    public boolean add(String readPointName, Tag tag) {
        log.info("'" + tag.getTagID() + "' ENTER the range of antenna '" + readPointName + "'");
        return ((Set) reader.get(readPointName)).add(tag);
    }

    /**
     * To move a certain tag to a certain antenna.
     * 
     * @param readPointName The name of the read point to which the tag should be added.
     * @param tagId The ID of a tag to be added to the antenna / read point. A new (empty) tag object with ID tagId will be generated.
     * 
     * @return Returns true if tag has been added. False if tag with same TagID already is in this antenna.
     */
    public boolean add(String readPointName, String tagId) {
        Tag t = new Tag(tagId);
        return add(readPointName, t);
    }

    /**
     * To remove a certain tag from a certain antenna.
     * 
     * @param readPointName The name of the read point from which the tag should be removed.
     * @param tag The tag object to be removed from the antenna / read point.
     * 
     * @return Returns true if tag has been removed. False if no such tag existed in this antenna.
     */
    public boolean remove(String readPointName, Tag tag) {
        log.info("'" + tag.getTagID() + "' EXIT the range of antenna '" + readPointName + "'");
        return ((Set) reader.get(readPointName)).remove(tag);
    }

    /**
     * To remove a certain tag from a certain antenna.
     * 
     * @param readPointName The name of the read point from which the tag should be removed.
     * @param tagId The ID of a tag to be removed from the antenna / read point.
     * 
     * @return Returns true if tag has been removed. False if no such tag existed in this antenna.
     */
    public boolean remove(String readPointName, String tagId) {
        Tag t = new Tag(tagId);
        return remove(readPointName, t);
    }

    /**
     * 
     * To find out whether a certain tag is situated on a certain antenna.
     * 
     * @param readPointName The name of the read point
     * @param tag The tag.
     * 
     * @return Returns true if such a tag is on this antenna. False if no such tag existed in this antenna.
     */
    public boolean contains(String readPointName, Tag tag) {
        return ((Set) reader.get(readPointName)).contains(tag);
    }

    /**
     * To find out whether a certain tag is situated on a certain antenna.
     * 
     * @param readPointName The name of the read point
     * @param tagId The ID of a tag.
     * 
     * @return Returns true if a tag with ID tagId is on this antenna. False if no such tag existed in this antenna.
     */
    public boolean contains(String readPointName, String tagId) {
        Tag t = new Tag(tagId);
        return contains(readPointName, t);
    }

    /**
     * To get a set of all tags situated on a certain antenna.
     * 
     * @param readPointName The name of the read point
     * @return Returns a Set containing a copy of all tags currently on this read point.
     */
    public Set getTagsFromReadPoint(String readPointName) {
        Iterator it = ((Set) reader.get(readPointName)).iterator();
        Set setCopy = new HashSet();

        while (it.hasNext()) {
            setCopy.add(it.next());
        }
        return setCopy;
    }

    //-------------------- HAL interface methods  ------------------------------------

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#getHalName()
     */
    public String getHALName() {
        return halName;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#identify(java.lang.String[])
     */
    public Observation[] identify(String[] readPointNames) throws HardwareException {
        // Each read point gets its own Observation
        Observation[] observations = new Observation[readPointNames.length];

        for (int i = 0; i < readPointNames.length; i++) {

            observations[i] = new Observation();
            observations[i].setHalName(this.halName);
            observations[i].setReadPointName(readPointNames[i]);

            //Get the tag IDs on this antenna
            Vector<String> v = new Vector<String>();
            Iterator it = ((HashSet) reader.get(readPointNames[i])).iterator();
            while (it.hasNext()) {
                Tag t = (Tag) it.next();
                v.add(t.getTagID());
            }

            int len = v.size();
            String v_arr[] = new String[len];
            v_arr = v.toArray(v_arr);
            TagDescriptor[] td_arr = new TagDescriptor[v_arr.length];
            String idTConf;
            try {
                idTConf = props.getParameter("idTypesConfig");
            } catch (Exception e) {
                idTConf = null;
            }
            for (int j = 0; j < td_arr.length; j++) {
                IDType idType = IDType.getIdType("EPC", idTConf);
                byte[] accada_sim_tid_bytes = ByteBlock.hexStringToByteArray("E2FFF000");
                EPCTransponderModel tagModel = EPCTransponderModel.getEpcTrasponderModel(accada_sim_tid_bytes,
                        epcTransponderModelsConfig);
                MemoryBankDescriptor[] memoryBankDescriptors = new MemoryBankDescriptor[4];
                memoryBankDescriptors[0] = new MemoryBankDescriptor(tagModel.getReservedSize(),
                        tagModel.getReservedReadable(), tagModel.getReservedWriteable());
                memoryBankDescriptors[1] = new MemoryBankDescriptor(tagModel.getEpcSize(),
                        tagModel.getEpcReadable(), tagModel.getEpcWriteable());
                memoryBankDescriptors[2] = new MemoryBankDescriptor(tagModel.getTidSize(),
                        tagModel.getTidReadable(), tagModel.getTidWriteable());
                memoryBankDescriptors[3] = new MemoryBankDescriptor(tagModel.getUserSize(),
                        tagModel.getUserReadable(), tagModel.getUserWriteable());
                MemoryDescriptor memoryDescriptor = new MemoryDescriptor(memoryBankDescriptors);
                td_arr[j] = new TagDescriptor(idType, memoryDescriptor);
            }
            observations[i].setTagDescriptors(td_arr);
            observations[i].setIds(v_arr);
            observations[i].setTimestamp(System.currentTimeMillis());

            if (!readyReadPoints.contains(readPointNames[i])) {
                log.error("Read point \"" + readPointNames[i] + "\" is not ready.");
                observations[i].setIds(new String[0]);
                observations[i].setTagDescriptors(new TagDescriptor[0]);
                observations[i].successful = false;
            } else if (continuousIdentifyErrors.contains(readPointNames[i])) {
                observations[i].successful = false;
            } else if (identifyError.contains(readPointNames[i])) {
                observations[i].successful = false;
                identifyError.remove(readPointNames[i]);
            } else {
                observations[i].successful = true;
            }

            log.debug(observations[i].toString());
        }
        return observations;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#startAsynchronousIdentify(java.lang.String[], org.accada.hal.AsynchronousIdentifyListener, java.lang.String, java.lang.String)
     */
    public void startAsynchronousIdentify(String[] readPointNames, Trigger trigger)
            throws HardwareException, UnsupportedOperationException {
        throw new HardwareException("HAL not ready.");
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#stopAsynchronousIdentify(org.accada.hal.AsynchronousIdentifyListener)
     */
    public void stopAsynchronousIdentify() throws HardwareException, UnsupportedOperationException {
        throw new HardwareException("HAL not ready.");
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#isAsynchronousIdentifyRunning(org.accada.hal.AsynchronousIdentifyListener)
     */
    public boolean isAsynchronousIdentifyRunning() throws HardwareException, UnsupportedOperationException {
        throw new HardwareException("HAL not ready.");
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#addAsynchronousIdentifyListener(org.accada.hal.AsynchronousIdentifyListener)
     */
    public void addAsynchronousIdentifyListener(AsynchronousIdentifyListener listener)
            throws HardwareException, UnsupportedOperationException {
        throw new HardwareException("HAL not ready.");
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#removeAsynchronousIdentifyListener(org.accada.hal.AsynchronousIdentifyListener)
     */
    public void removeAsynchronousIdentifyListener(AsynchronousIdentifyListener listener)
            throws HardwareException, UnsupportedOperationException {
        throw new HardwareException("HAL not ready.");
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsAsynchronousIdentify()
     */
    public boolean supportsAsynchronousIdentify() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#readBytes(java.lang.String, java.lang.String, int, int, int, java.lang.String[])
     */
    public UnsignedByteArray readBytes(String readPointName, String id, int memoryBank, int offset, int length,
            String[] passwords) throws HardwareException, UnsupportedOperationException {
        if (readyReadPoints.contains(readPointName)) {

            if (continuousReadErrors.contains(readPointName)) {
                throw new HardwareException();
            } else if (readError.contains(readPointName)) {
                readError.remove(readPointName);
                throw new HardwareException();
            }

            UnsignedByteArray byteData;
            Tag tag = null;
            if (contains(readPointName, id)) {
                Iterator it = ((HashSet) reader.get(readPointName)).iterator();
                while (it.hasNext()) {
                    Tag curTag = (Tag) it.next();
                    if (curTag.getTagID().equalsIgnoreCase(id)) {
                        tag = curTag;
                        break;
                    }
                }
            }

            if (tag != null) {
                byteData = new UnsignedByteArray(tag.readData(memoryBank, offset, length));
            } else {
                String message = "Specified tag not in range";
                throw new HardwareException(message);
            }

            return byteData;
        } else {
            throw new HardwareException("Read point is not ready.");
        }
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#writeBytes(java.lang.String, java.lang.String, int, int, byte[], java.lang.String[])
     */
    public void writeBytes(String readPointName, String id, int memoryBank, int offset, UnsignedByteArray data,
            String[] passwords) throws HardwareException, UnsupportedOperationException {
        if (readyReadPoints.contains(readPointName)) {

            if (continuousWriteErrors.contains(readPointName)) {
                throw new HardwareException();
            } else if (writeError.contains(readPointName)) {
                writeError.remove(readPointName);
                throw new HardwareException();
            }

            Tag tag = null;
            if (contains(readPointName, id)) {
                Iterator it = ((HashSet) reader.get(readPointName)).iterator();
                while (it.hasNext()) {
                    Tag curTag = (Tag) it.next();
                    if (curTag.getTagID().equalsIgnoreCase(id)) {
                        tag = curTag;
                        break;
                    }
                }
            }

            if (tag != null) {
                tag.writeData(memoryBank, offset, data.toByteArray());
            } else {
                String message = "Specified tag not in range";
                throw new HardwareException(message);
            }
        } else {
            throw new HardwareException("Read point is not ready.");
        }
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#writeId(java.lang.String, java.lang.String, java.lang.String[])
     */
    public void writeId(String readPointName, String id, String[] passwords)
            throws ReadPointNotFoundException, HardwareException, UnsupportedOperationException {
        throw new HardwareException("HAL not ready.");
        // TODO: implement
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsWriteId()
     */
    public boolean supportsWriteId() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#getReadPointNames()
     */
    public String[] getReadPointNames() {
        return readPointNames;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#setParameter(java.lang.String, java.lang.String)
     */
    public void setParameter(String param, String value) throws HardwareException, UnsupportedOperationException {
        // TODO: implement
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#getAllParameterNames()
     */
    public String[] getAllParameterNames() throws HardwareException, UnsupportedOperationException {
        try {
            return this.props.getParameterNames();
        } catch (Exception e) {
            throw new HardwareException(e.getMessage());
        }
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#getParameter(java.lang.String)
     */
    public String getParameter(String param) throws HardwareException, UnsupportedOperationException {
        try {
            return this.props.getParameter(param);
        } catch (Exception e) {
            e.printStackTrace();
            throw new HardwareException(e.getMessage());
        }
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsParameters()
     */
    public boolean supportsParameters() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#programId(java.lang.String, java.lang.String[])
     */
    public void programId(String id, String[] passwords) throws HardwareException, UnsupportedOperationException {
        throw new HardwareException("HAL not ready.");
        // TODO: implement
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#reset()
     */
    public void reset() throws HardwareException {
        // TODO: implement
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#kill(java.lang.String, java.lang.String[])
     */
    public void kill(String readPointName, String id, String[] passwords)
            throws HardwareException, UnsupportedOperationException {
        throw new HardwareException("HAL not ready.");
        // TODO: implement
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsReadBytes()
     */
    public boolean supportsReadBytes() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsWriteBytes()
     */
    public boolean supportsWriteBytes() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsProgramId()
     */
    public boolean supportsProgramId() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsKill()
     */
    public boolean supportsKill() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsReset()
     */
    public boolean supportsReset() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#getReadPointPowerLevel(java.lang.String, boolean)
     */
    public int getReadPointPowerLevel(String readPointName, boolean normalize) {
        // TODO: implement
        return 0;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsGetReadPointPowerLevel()
     */
    public boolean supportsGetReadPointPowerLevel() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#getReadPointNoiseLevel(java.lang.String, boolean)
     */
    public int getReadPointNoiseLevel(String readPointName, boolean normalize) {
        // TODO: implement
        return 0;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsGetReadPointNoiseLevel()
     */
    public boolean supportsGetReadPointNoiseLevel() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#startUpReadPoint(java.lang.String)
     */
    public void startUpReadPoint(String readPointName) {
        if (!readyReadPoints.contains(readPointName)) {
            readyReadPoints.add(readPointName);
        }
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsStartUpReadPoint()
     */
    public boolean supportsStartUpReadPoint() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#shutDownReadPoint(java.lang.String)
     */
    public void shutDownReadPoint(String readPointName) {
        if (readyReadPoints.contains(readPointName)) {
            readyReadPoints.remove(readPointName);
        }
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsShutDownReadPoint()
     */
    public boolean supportsShutDownReadPoint() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#isReadPointReady(java.lang.String)
     */
    public boolean isReadPointReady(String readPointName) {
        return readyReadPoints.contains(readPointName);
    }

    /* (non-Javadoc)
     * @see org.accada.hal.HardwareAbstraction#supportsIsReadPointReady()
     */
    public boolean supportsIsReadPointReady() {
        return true;
    }

    /**
     * For debugging.
     * 
     * @param args
     *            No arguments
     */
    public static void main(String[] args) {
        DOMConfigurator.configure("./props/log4j.xml");
        new SimulatorController("SimulatorController", "/props/SimulatorController.xml");
    }
}