package tmcsim.client; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.Observable; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import tmcsim.cadmodels.BlankScreenModel; import tmcsim.cadmodels.CADScreenModel; import tmcsim.cadmodels.IncidentBoardModel; import tmcsim.cadmodels.IncidentInquiryModel; import tmcsim.cadmodels.IncidentSummaryModel; import tmcsim.cadmodels.RoutedMessageModel; import tmcsim.common.ObserverMessage; import tmcsim.common.SimulationException; import tmcsim.common.CADProtocol.CAD_CLIENT_CMD; import tmcsim.common.CADProtocol.CAD_COMMANDS; import tmcsim.common.CADProtocol.CAD_SIMULATOR_CMD; import tmcsim.common.CADProtocol.DATA_TAGS; /** * CADClientModel handles data transmission between the CAD Client and CAD * Simulator. Data is read from the input stream and parsed for message updates * from the CAD Simulator. These updates are described in the receiveObject() * method description. The transmit() method is called to send Document objects * to the CAD Simulator. * * @author Matthew Cechini (mcechini@calpoly.edu) * @version $Date: 2009/04/20 17:58:27 $ $Revision: 1.5 $ */ public class CADClientModel extends Observable implements Runnable { /** Error Logger. */ private Logger clientLogger = Logger.getLogger("tmcsim.client"); /** Output stream for writing data to the CAD Simulator. */ private ObjectOutputStream out = null; /** Input Stream for reading data to the CAD Simulator. */ private ObjectInputStream in = null; /** Boolean flag to designate if Runnable object is running. */ private boolean running = true; /** * Constructor. */ public CADClientModel() { } /** * This method sets the streams that are used for communication * to and from the CAD Simulator. * * @param theIS The input stream to read packets from. * @param theOS The output stream to write packets to. * @throws SimulationException if there is an exception in * creating the Object(Input/Output)Streams. */ public void initializeScreen(InputStream theIS, OutputStream theOS) throws SimulationException { try { out = new ObjectOutputStream(theOS); in = new ObjectInputStream(theIS); } catch (Exception e) { throw new SimulationException(SimulationException.CAD_SIM_COMM, e); } } /** * This method register this CAD Client with the CAD Simulator. The client * is registered with its CAD position number and user ID. * * @param CADPosition CAD Position number. * @param userID User ID. * @throws SimulationException if there is an exception in registering the client. */ public void register(int CADPosition, String userID) throws SimulationException { try { Document cmdDoc = DocumentBuilderFactory.newInstance() .newDocumentBuilder().newDocument(); Element cmdElem = cmdDoc.createElement(CAD_CLIENT_CMD.TERMINAL_REGISTER.type); Element posElem = cmdDoc.createElement(DATA_TAGS.POSITION_NUM.tag); posElem.appendChild(cmdDoc.createTextNode(String.valueOf(CADPosition))); cmdElem.appendChild(posElem); Element userIDElem = cmdDoc.createElement(DATA_TAGS.USER_ID.tag); userIDElem.appendChild(cmdDoc.createTextNode(userID)); cmdElem.appendChild(userIDElem); cmdDoc.appendChild(cmdElem); transmitCommand(cmdDoc); } catch (Exception e) { clientLogger.logp(Level.SEVERE, "CADClientModel", "register()", "Exception in registering client.", e); throw new SimulationException(SimulationException.REGISTER_ERROR, e); } } /** * Run method that must be defined in Runnable interface. * This method continuously calls the receiveObject() method * to check the input stream for data. If an exception occurs * reading from the input stream, the streams are closed and * observers are notified with a null object that the model has * disconnected. */ public void run() { while(running) { try { Thread.sleep(250); receiveObject(in.readObject()); } /* catch (EOFException eofe) { clientLogger.logp(Level.SEVERE, "CADClientModel", "run()", "Exception in reading object from input stream.", eofe); }*/ catch (Exception e) { clientLogger.logp(Level.SEVERE, "CADClientModel", "run()", "Exception in reading object from input stream. " + "Shutting down client.", e); running = false; closeStreams(); setChanged(); notifyObservers(); } } } /** * This method writes the parameter Document object to the * ObjectOutputStream which is transmitted eo the CAD Simulator. * If there is an Exception in writing to the Socket, the streams * are closed and observers are notified with a null object to * signify that the connect has been lost. * * @param command The Document being transmitted. */ public void transmitCommand(Document command) { try { out.writeObject(command); out.flush(); } catch (IOException ioe) { clientLogger.logp(Level.SEVERE, "CADClientModel", "transmitObject()", "Exception in writing object to the input stream. " + "Shutting down client.", ioe); running = false; closeStreams(); setChanged(); notifyObservers(); } } /** *
| CAD Protocol Command |
* Action Taken |
*
|---|---|
| UPDATE_SCREEN |
* A completely new window has been received. Parse the received
* data into an XML Document. The root node is used to determine
* which type of CAD Screen is being shown. Construct the new
* CADScreenModel for that CAD Screem amd notify the view observer with the new
* screen type and model. |
*
| UPDATE_STATUS | *Notify the view observer with the new screen update status value. |
*
| UPDATE_TIME | *Notify the view observer with the new CAD Time value. |
*
| UPDATE_MSG_COUNT | *Notify the view observer with the new queued message count value. |
*
| UPDATE_MSG_UNREAD | *Notify the view observer with the new boolean unread messages value. |
*
| CAD_INFO | *Notify the view observer with the received informational message value. |
*