org.rifidi.emulator.reader.command.controller.abstract_.AbstractCommandController.java Source code

Java tutorial

Introduction

Here is the source code for org.rifidi.emulator.reader.command.controller.abstract_.AbstractCommandController.java

Source

/*
 *  @(#)AbstractCommandController.java
 *
 *  Created:   Sep 18, 2006
 *  Project:   RiFidi Emulator - A Software Simulation Tool for RFID Devices
 *              http://www.rifidi.org
 *              http://rifidi.sourceforge.net
 *  Copyright:   Pramari LLC and the Rifidi Project
 *  License:   Lesser GNU Public License (LGPL)
 *              http://www.opensource.org/licenses/lgpl-license.html
 */

package org.rifidi.emulator.reader.command.controller.abstract_;

import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rifidi.emulator.common.ControlSignal;
import org.rifidi.emulator.io.comm.Communication;
import org.rifidi.emulator.reader.command.controller.CommandController;
import org.rifidi.emulator.reader.command.controller.CommandControllerException;
import org.rifidi.emulator.reader.command.controller.CommandControllerPowerState;
import org.rifidi.emulator.reader.module.abstract_.AbstractPowerModule;

/**
 * An AbstractCommandController defines the basic relationships which a
 * CommandController has. It contains a Communication to send command responses
 * through. It has a current CommandControllerOperatingState and current
 * CommandControllerPowerState which are used to dictate the functionality of
 * the processCommand method. This class implements the shuttling of data
 * between the Communication, but does not incorporate any private methods for
 * aiding state.
 * 
 * @author John Olender - john@pramari.com
 * @since <$INITIAL_VERSION$>
 * @version <$CURRENT_VERSION$>
 * 
 */
public abstract class AbstractCommandController extends AbstractPowerModule implements CommandController, Observer {

    /**
     * The log4j logger for this class.
     */
    private static Log logger = LogFactory.getLog(AbstractCommandController.class);

    /**
     * A constant command which is called when a connection event is handled.
     */
    public static final byte[] CONNECTION_COMMAND = "connect".getBytes();

    /**
     * A control signal which this controller will observe for changes which
     * relates to the connection of the communication is using. The abstract
     * controller will take appropriate action based on these changes.
     */
    private ControlSignal<Boolean> connectionControlSignal;

    /**
     * The current CommunicationChannel this is monitoring.
     */
    private Communication curCommunication;

    /**
     * The current command processor operating state.
     */
    private AbstractCommandControllerOperatingState curOperatingState;

    /**
     * The initial command processor operating state. When a logical reset of
     * the controller takes place, this is the state which it will initially
     * hold.
     */
    private AbstractCommandControllerOperatingState initialOperatingState;

    /**
     * Interruption flag for wait actions.
     */
    private boolean interrupted;

    /**
     * Suspension flag for wait actions.
     */
    private boolean suspended;

    /**
     * The lock for the suspension and interruption flags.
     */
    private Object suspensionLock;

    /**
     * Creates a new AbstractCommandController object with passed initial power
     * and operating states, along with a CommunicationChannel object to send
     * processed command responses to.
     * 
     * @param initialPowerState
     *            The initial power state to place this controller in.
     * @param initialOperatingState
     *            The initial operating state to place this controller in.
     * @param powerControlSignal
     *            The power control signal for this AbstractCommandController to
     *            observe. If <i>null</i> is passed, this will not observe a
     *            power signal.
     * @param connectionControlSignal
     *            The connection control signal for this
     *            AbstractCommandController to observe. If <i>null</i> is
     *            passed, this will not observe a connection signal.
     * @param communication
     *            The Communication which this controller interacts with.
     */
    public AbstractCommandController(CommandControllerPowerState initialPowerState,
            AbstractCommandControllerOperatingState initialOperatingState,
            ControlSignal<Boolean> powerControlSignal, ControlSignal<Boolean> connectionControlSignal,
            Communication communication) {
        /* Call the AbstractPowerModule's constructor */
        super(initialPowerState, powerControlSignal);

        logger.debug("powerstate: " + initialPowerState);
        logger.debug("cur power state: " + super.getPowerState());

        /* Assign instance variables */
        this.initialOperatingState = initialOperatingState;
        this.curOperatingState = initialOperatingState;
        this.curCommunication = communication;
        this.connectionControlSignal = connectionControlSignal;

        /* Register as connection observer */
        if (this.connectionControlSignal != null) {
            this.connectionControlSignal.addObserver(this);

        }

        /* Set wait variables to defaults */
        this.suspensionLock = new Object();
        this.interrupted = false;
        this.suspended = false;

        /* Synchronize on the passed processor's suspension lock */
        Object lock = this.getSuspensionLock();
        synchronized (lock) {
            /* Turn on interruption status */
            this.setInterrupted(true);

            /* Notify anything waiting */
            lock.notifyAll();

        }

    }

    /**
     * Changes the current operating state to the passed operating state.
     * 
     * @param newState
     *            The new operating state to set.
     */
    protected void changeCommandControllerOperatingState(AbstractCommandControllerOperatingState newState) {
        this.curOperatingState = newState;

    }

    /**
     * Changes the current power state to the passed power state.
     * 
     * @param newState
     *            The new power state to set.
     */
    protected void changeCommandControllerPowerState(CommandControllerPowerState newState) {
        /* Invoke AbstractPowerModule's implementation */
        super.changePowerState(newState);

    }

    /**
     * Returns the curCommunication.
     * 
     * @return Returns the curCommunication.
     */
    protected Communication getCurCommunication() {
        return this.curCommunication;
    }

    /**
     * Set the curCommunication. (Used for LLRPReader)
     * 
     * @param curCommunication
     */
    public void setCurCommunication(Communication curCommunication) {
        this.curCommunication = curCommunication;
    }

    /**
     * Returns the curOperatingState. []
     * 
     * @return Returns the curOperatingState.
     */
    protected AbstractCommandControllerOperatingState getCurOperatingState() {
        return this.curOperatingState;
    }

    /**
     * Returns the initialOperatingState.
     * 
     * @return Returns the initialOperatingState.
     */
    protected AbstractCommandControllerOperatingState getInitialOperatingState() {
        return this.initialOperatingState;

    }

    /**
     * Returns the suspensionLock.
     * 
     * @return Returns the suspensionLock.
     */
    protected Object getSuspensionLock() {
        return this.suspensionLock;
    }

    /**
     * Returns the interrupted flag. Callers of this method should be sure to be
     * synchonized on the suspensionLock before calling this.
     * 
     * @return Returns the interrupted.
     */
    protected boolean isInterrupted() {
        return this.interrupted;
    }

    /**
     * Returns the suspended flag. Callers of this method should be sure to be
     * synchonized on the suspensionLock before calling this.
     * 
     * @return Returns the suspended.
     */
    protected boolean isSuspended() {
        return this.suspended;
    }

    /**
     * Processes the passed command and returns a response.
     * 
     * @param command
     *            The command to process.
     * @return A response message for the command.
     * @throws CommandControllerException
     *             If this method is called an the processCommand cannot be
     *             completed.
     */
    public ArrayList<Object> processCommand(byte[] command) throws CommandControllerException {
        /* Call the current power state's corresponding method */
        return ((CommandControllerPowerState) this.getPowerState()).processCommand(command, this);

    }

    /**
     * Sets interrupted to the passed parameter, interrupted. Callers of this
     * method should be sure to be synchonized on the suspensionLock before
     * calling this.
     * 
     * @param interrupted
     *            The interrupted to set.
     */
    protected void setInterrupted(boolean interrupted) {
        this.interrupted = interrupted;
    }

    /**
     * Sets suspended to the passed parameter, suspended. Callers of this method
     * should be sure to be synchonized on the suspensionLock before calling
     * this.
     * 
     * @param suspended
     *            The suspended to set.
     */
    protected void setSuspended(boolean suspended) {
        this.suspended = suspended;
    }

    /**
     * An abstract implementation of the update method. Checks the source of the
     * update before proceeding. If the source is the connectionControlSignal,
     * turns this controller on/off and connects/disconnects the communication.
     * 
     * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    @Override
    public void update(Observable o, Object arg) {
        /* Call AbstractPowerModule's implementation first */
        super.update(o, arg);
        /* Now, check for a connection signal update */
        if (o == this.connectionControlSignal) {
            /* If a connection turns on, turn this on */
            if (this.connectionControlSignal.getControlVariableValue()) {
                /* Only turn this thing on if the power control variable is on */
                if (this.getPowerControlSignal().getControlVariableValue()) {

                    logger.debug("connection is turing on because connection signal changed to true");

                    /* Connect */
                    this.getCurCommunication().connect();

                    /*
                     * This block turns on the object based on if there is extra
                     * information or not in the object.
                     */
                    if (this.connectionControlSignal.getExtraInformation() != null) {
                        /* Turn on with the command to execute */
                        this.turnOn(this.connectionControlSignal.getExtraInformation());
                    } else {
                        /* Turn on */
                        this.turnOn();
                    }

                    // certain operating states, such as the loginUnconnected,
                    // need to do something as soon as a new connection is made
                    if (this.connectionControlSignal.getExtraInformation() == null) {
                        this.getCurOperatingState().initialize(this, this.getCurCommunication());
                    }

                }

            } else {
                /* Disconnection signal... turn this off and disconnect. */
                logger.debug(
                        "abstract command controller is turing off and disconnecting because connection signal changed to false");
                this.turnOff();
                this.getCurCommunication().disconnect();

            }

        }

    }

}