/************************************************
* Columbia University CS Department
* Systems and Security Group
*
* Open and Survivable Embedded Systems (OASES)
*
* Michael E. Locasto
*
* Protocol For Code Exchange
*  in Survivable Embedded Systems (PCXSES)
*
* This software is provided as is without any
* warranty or guarantee of merchantibility
* or fitness for a particular purpose. This
* software is released under the terms of the
* GNU General Public License (GPL).
*
* Last updated: November 19, 2002
*
***********************************************/

package locasto.pcxses.protocol;


import java.util.Hashtable;

/**
* <p>
* An interface specifying the actions a developer
* can ask the PCXClient implementation to perform.
* </p>
* <p>
* The class that implements this interface will
* also extend some class that can perform the
* loading of class definitions into the current
* Virtual Machine.
* </p>
* <p>
* To hide this functionality, a PCXClientFactory
* should be statically instantiated and then
* made to produce an instance of an object that
* implements this class:
* </p>
* <pre>
	PCXClient pcxClient = PCXClientFactory.newInstance().createPCXClient();
	Hashtable env = ...;
	pcxClient.configure( env );
* </pre>
* The client may then be used like so:
* <pre>
*   pcxClient.init();
*   //optional send() calls
*   pcxClient.updateState( s );
*   pcxClient.shutDown();
* </pre>
* <p>
* Note especially that there is no receive() method.
* When the PCXClient is initialized, it will create
* a thread that is a client of the network specified
* in its supplied environment. It will automatically
* join the federation supplied in its environment.
* Subsequent calls to <code>joinFederation()</code>
* will simply return true until <code>leaveFederation()
* </code> is called. The <code>leaveFederation()</code>
* method is useful because the set of <code>AreaController
* </code>s will need to be informed of a clean and
* purposeful shutdown. If the <code>joinFederation()</code>
* method is subsequently called, it will attempt to rejoin
* the federation indicated by its current environment.
* Currently, there is no way besides another call to
* <code>init()</code> to &quot;join&quot; another federation.
* </p>
* <p>
* The thread may send both HELLO and STATE messages. If the
* client is operating in JOINED_MODE, it will silently ignore
* requests to the <code>sendStateMessage()</code> method. It
* will continue to send HELLO messages with the LKGS. If the
* LKGS matches the cached state, a lite HELLO message will be
* sent. If the client is operating in SPLIT_MODE, the client
* will send lite HELLO messages according to the parameters
* negotiated with the <code>AreaController</code>. The client
* will only send STATE messages when an explicite call is made
* to the <code>sendStateMessage()</code> method.
* </p>
* <p>
* By using this library, the device developer gives implicit
* permission for the underlying thread to load a new computation
* into its memory space and start the new computation in a new
* thread. The underlying thread may be implemented
* to &quot;take over the device&quot; by wiping out the other
* threads to make space for the new computation. The default
* implementation does not do this. It creates a new thread. Note,
* however, this new thread may hog the resources of the device, even
* if it does not replace any current processes on the device.
* </p>
*
* @author locasto@cs.columbia.edu
*/
public interface PCXClient{

	/** Specifies that the client will send both STATE and HELLO messages. */
	public static final int SPLIT_MODE = 110;

	/** Specifies that the client will send <b>only</b> HELLO messages. */
	public static final int JOINED_MODE = 225;

	/** The default TCP port for the protocol. */
	public static final int DEFAULT_PORT = 3780;

	/** The default number of seconds between HELLO messages */
	public static final int DEFAULT_HELLO_INTERVAL = 3000;

	/** The default number of hello intervals before the client is declared dead. */
	public static final int DEFAULT_DEAD_INTERVAL = 3;

	/**
	 * Configure this client with the information in the
	 * <code>env</code> parameter. Parameters other than those
	 * listed below are allowable, but it is up to the implementation
	 * to interpret them.
	 *
	 * @param Hashtable env - contains the environment variables
	 *    needed by this client for normal operation. The variables
	 *    are specified by the following list and are required:
	 *   <ul>
	 *     <li> <code>pcxses.ac.ip</code> - the IP address of the primary AreaController</li>
	 *     <li> <code>pcxses.ac.port</code> - the port to communicate on. </li>
	 *     <li> <code>pcxses.client.name</code> - the unique name of this client. </li>
	 *     <li> <code>pcxses.client.mode</code> - the mode of operation, either
	 *              SPLIT_MODE or JOINED_MODE. </li>
	 *     <li> <code>pcxses.client.hellointerval</code> - the client-specific hello interval
	 *             (in milliseconds)...-1 forces none and forces deadinterval to -1. A zero value
	 *             is meaningless and will be overwritten by the server.</li>
	 *     <li> <code>pcxses.client.deadinterval</code> - the client-specific dead interval
	 *             (in number of hellointerval cycles) -1 disables. A zero value is meaningless
	 *             and will be overwritten by the server.</li>
	 *   </ul>
	 *
	 *
	 * @throws PCXException - if the client cannot be initialized
	 *    with the supplied information, or a network error has
	 *    occurred.
	 *
	*/
	public void configure( Hashtable env ) throws PCXException;

	/**
	 * Leave the current federation, if any, and initialize
	 * this client with the information provided to the <code>
	 * configure()</code> method. This method starts the client
	 * protocol thread (including joining the specified federation)
	 * and then returns. The class implementing this interface is
	 * left the details of federation joining: third party
	 * libraries may be employed.
	 *
	 * Contract of the init method:
	 *  <ol>
	 *   <li> call the <code>sendGoodByeMessage()</code> method, if involved with
	 *          an <code>AreaController</code>
	 *   <li> leave the current federation, if any (<code>leaveFederation()</code>)
	 *   <li> start the underlying client recieve protocol thread. This will:
	 *          contact the <code>AreaController</code> specified in the environment variables
	 *          by opening a Socket to the AC and calling
	 *          the <code>sendGoodMorningMessage()</code> method.
	 *          The AC will respond with a GOOD_MORNING message specifying some network variables.
	 *          The receive thread will receive this message and then begin to send HELLO messages.
	 *   </li>
	 *   <li>
	 * </ol>
	 *
	 * @throws PCXException - if the client cannot be initialized
	 *    with the current information, or a network error has
	 *    occurred (the client cannot contact the federation or
	 *    the client cannot begin the protocol dialougue).
	 *
	*/
	public void init() throws PCXException;

	/**
	 * Rejoin the federation specified by the current environment
	 * variables. The <code>init()</code> method calls this
	 * method internally. Subsequent calls to this method (without
	 * a prior call to <code>leaveFederation()</code> will merely
	 * return a <code>true</code> value with no other effect.
	*/
	public boolean joinFederation() throws PCXException;

	/**
	 * Notify the current federation that you are leaving.
	 * in a proper manner so that the federation
	 * does not consider you a failed device.
	 * <p>
	 * The implementation of this method <b>MUST</b> guarantee
	 * that it has severed all connections with the current
	 * federation, even if an <code>Exception</code> occurs.
	 * The Exception should be handled and disconnection must
	 * continue. The Exception <b>SHOULD</b> then be rethrown.
	 * <p>
	 *
	*/
	public boolean leaveFederation();


	/**
	 * The <code>init()</code> method will call this method
	 * implicitely to begin negotiation with the <code>
	 * AreaController</code>.
	 * <p>
	 * The "GOOD MORNING" phase of the protocol is a bootstrap
	 * method to join a federation. It may be used with or without
	 * a federation, but the choice is ultimately up to the
	 * implementor of this interface. This discovery phase can be
	 * done without joining a federation; essentially, a federation
	 * consisting of the <code>AreaController</code> and this client
	 * is set up once the "GOOD MORNING" exchange is completed.
	 * <p>
	 * Joining a federation is considered a lower-level action than
	 * the "GOOD MORNING" phase. Therefore, this phase of the protocol
	 * can be run regardless whether or not an underlying network federation
	 * is actually present. However, only one call to this method may be
	 * made per session with the <code>AreaController</code>. After the
	 * first call to this method, subsequent calls will merely return without
	 * sending any messages. To renegotiate session parameters, the client
	 * will have to call <code>sendGoodByeMessage( Bottle message )</code>
	 * and then call this method. This may be done without &quot;leaving&quot;
	 * the federation.
	 *
	 *
	*/
	public void sendGoodMorningMessage( Bottle message ) throws PCXException;

	/** Send a HELLO message to the <code>AreaController</code>.
	 * <p>
	 * This allows the device programmer to explicitly request the
	 * underlying thread to send another HELLO message regardless of
	 * the cycle. The thread will automatically be sending HELLO messages.
	 * Calling this method amounts to inserting another HELLO message in
	 * the outgoing queue.
	 * </p>
	 * <p>
	 * The underlying thread will examine the currently cached state and
	 * see if it differs from the LKGS that was sent. If not, the underlying
	 * thread will set the STATE_CHANGED flag to false and send a lite HELLO.
	 * </p>
	 * <p>
	 * New State information may be provided by calling the <code>update(
	 * State currentState )</code> method or by including that object as
	 * part of the <code>Bottle</code> parameter to this method.
	 *
	 *
	 *
	*/
	public void sendHelloMessage( Bottle message );

	/** Send a STATE message to the <code>AreaController</code>.
	 * <p>
	 * Has the effect of adding the specified <code>Bottle</code> to
	 * the outgoing queue.
	 * If the MODE flag is set to JOINED_MODE, calling this method will
	 * have no effect. In particular, it will <b>not</b> throw an
	 * exception.
	 * </p>
	*/
	public void sendStateMessage( Bottle message );

	/**
	 * Notify the current <code>AreaController</code> that this
	 * client is leaving so the AC
	 * does not consider you a failed device.
	 * <p>
	 * This method should be called before the <code>leaveFederation()</code>
	 * method is called.
	*/
	public void sendGoodByeMessage( Bottle message ) throws PCXException;

	/**
	 * Update the state information to be sent out in the next
	 * HELLO or STATE message. Note that access to this method is
	 * unsynchronized - if several external threads make calls to
	 * this method, access should be synchronized externally.
	 *
	 * @param State [] currentState - the LKGS of this device. It should
	 * be transmitted within the next HELLO_INTERVAL.
	 *
	*/
	public boolean updateState( State currentState );

	/**
	 * The alternate version of updating state is not implemented
	 * in the default client class. This method is provided to
	 * those who are implementing their own client and wish the
	 * client to pull state information from the device rather than
	 * having the device push state information via the <code>
	 * updateState( State s )</code> method.
	 *
	*/
	public boolean updateState() throws PCXException;

	/**
	 * A call to this method will call the
	 * <code>sendGoodByeMessage()</code> and
	 * the <code>leaveFederation()</code> methods and
	 * terminate the underlying thread.
	*/
	public void shutDown();

}

