Warning: Can't use blame annotator:
svn blame failed on trunk/src/tmcsim/cadsimulator/CADClientConnector.java: ("Can't find a temporary directory: Internal error", 20014)

source: tmcsimulator/trunk/src/tmcsim/cadsimulator/CADClientConnector.java @ 123

Revision 123, 17.0 KB checked in by jdalbey, 9 years ago (diff)

Multiple renaming of classes to improve clarity. Remove check for Paramics running before starting sim.

RevLine 
1package tmcsim.cadsimulator;
2
3import java.io.IOException;
4import java.io.ObjectInputStream;
5import java.io.ObjectOutputStream;
6import java.net.Socket;
7import java.util.Observable;
8import java.util.Observer;
9import java.util.logging.Level;
10import java.util.logging.Logger;
11
12import javax.xml.parsers.DocumentBuilderFactory;
13
14import org.w3c.dom.Document;
15import org.w3c.dom.Element;
16import org.w3c.dom.Node;
17
18import tmcsim.common.CADProtocol;
19import tmcsim.common.ObserverMessage;
20import tmcsim.common.CADEnums.CAD_KEYS;
21import tmcsim.common.CADProtocol.CAD_CLIENT_CMD;
22import tmcsim.common.CADProtocol.CAD_COMMANDS;
23import tmcsim.common.CADProtocol.CAD_SIMULATOR_CMD;
24
25
26/**
27 * CADClientConnector handles communication between the CAD Simulator and
28 * remote CAD Clients.  Each instance of this class communicates with
29 * a CAD Client through a socket.  The run() method continuously checks to see
30 * if data has been received from the client.  If there is data, it is parsed,
31 * and the resulting action is performed by the CADScreenManager.  See the
32 * receiveObject() method description for more information.  The
33 * CADSimulatorClient is set up as an Observer of the CADScreenManager to listen
34 * for ObserverMessage objects.  For each object received, the appropriate
35 * action is taken, resulting in data being transmitted to the CAD Client.
36 * See the update() method description for more information.  The
37 * CADScreenManager is set up as an observer of the Coordinator to listen
38 * for simulation data updates.
39 *
40 * @author Matthew Cechini (mcechini@calpoly.edu)
41 * @version $Date: 2006/06/14 00:12:38 $ $Revision: 1.5 $
42 */
43public class CADClientConnector extends Thread implements Observer {
44   
45    /** Error Logger. */
46    private static Logger cadLogger = Logger.getLogger("tmcsim.cadsimulator");
47   
48    /** CADScreenManager object containing the data for managing the CAD Client's view information. */
49    private CADScreenManager screenManager;
50   
51    /** Socket used for communication with the CAD Client. */
52    private Socket theSocket;
53   
54    /** ObjectOutputStream for writing objects to the socket. */
55    private ObjectOutputStream out;
56   
57    /** ObjectInputStream for reading objects from the socket. */
58    private ObjectInputStream in;
59   
60    /**
61     * Constructor.  A CADScreenManager is instantiated to manage the output
62     * transmitted to the remote CAD Client.  This object is set up as an
63     * observer to that manager to listen for data that will be transmitted
64     * across the socket.  The CADScreenManager is set up as an observer
65     * of the Coordinator.  At construction, streams are created to handle
66     * reading and writing to the Socket.  When complete, the sendScreenRefresh()
67     * method is called to initialize the client.
68     *
69     *
70     * @param newSocket The socket to use for data transmission
71     * @throws IOException if there is an error in getting the output or input streams
72     * from the socket.
73     */
74    CADClientConnector(Socket newSocket) throws IOException{
75       
76        screenManager = new CADScreenManager(CADServer.theCoordinator);     
77        CADServer.theCoordinator.addObserver(screenManager);
78        screenManager.addObserver(this);
79       
80       
81        theSocket = newSocket;       
82        out       = new ObjectOutputStream(theSocket.getOutputStream());
83        in        = new ObjectInputStream(theSocket.getInputStream());   
84   
85        //initialize the CAD client
86        sendScreenRefresh();
87    }
88   
89    /**
90     * Method declaration for the Thread.run() method.  While the thread is not
91     * interrupted, read Objects from the socket and call the receiveObject()
92     * method to parse the data.  If there is an IOException in communicating
93     * with the client, interrupt this thread and close the streams and Socket.
94     */
95    public void run() {
96       
97        try { 
98       
99            while(!isInterrupted()) {
100                receiveObject(in.readObject());         
101            }
102        } 
103        catch (ClassCastException cce) {
104            cce.printStackTrace();
105        }
106        catch (ClassNotFoundException cnfe) {
107            cnfe.printStackTrace();
108        }
109        catch (IOException ioe) {                   
110            cadLogger.logp(Level.SEVERE, "CADSimulatorClient", "run", 
111                    "Error in reading from Client socket: " + 
112                    theSocket.getInetAddress() + ", proceeding.\n", ioe);
113           
114            //disconnectClient();
115        }
116    }
117   
118    /**
119     * This method is called to disconnect from the remote CAD Client.
120     * This object's thread is interrupted and the streams and socket
121     * are closed.  This object is removed as an observer of the
122     * CADScreenManager and the CADScreenManager is removed as an
123     * observer of the Coordinator.  The viewer is then notified
124     * of a disconnecting client.
125     */
126    protected void disconnectClient() {
127        this.interrupt();
128       
129        try { out.close(); } catch (Exception e) {}
130        try { in.close(); } catch (Exception e) {}
131        try { theSocket.close(); } catch (Exception e) {}
132
133        screenManager.deleteObserver(this);
134        CADServer.theCoordinator.removeObserver(screenManager);
135        //CADSimulator.theViewer.disconnectClient();
136    }
137   
138   
139
140    /**
141     * Observer method.  The update argument is cast to an ObserverMessage
142     * object and the message type is used to define the action taken by the
143     * CADSimulatorClient.  Command messages are created in the form of XML
144     * Document. The root Element name is value from the CAD_SIMULATOR_CMD
145     * enumeration.  The root text content is the value Object from the
146     * received Observer argument.
147     *
148     * The following table describes the messages sent for the ObserverMessage
149     * types.<br>
150     *
151     *<table cellpadding="2" cellspacing="2" border="1"
152    * style="text-align: left; width: 250px;">
153    *  <tbody>
154    *    <tr>
155    *      <th>Observer Message Type<br></th>
156    *      <th>Command Message Type<br></th>
157    *      <th>Data Content<br></th>
158    *    </tr>
159    *    <tr>
160    *      <td>SCREEN_UPDATE<br></td>
161    *      <td>UPDATE_STATUS</td>
162    *      <td>Screen update map String.</td>
163    *    </tr>
164    *    <tr>
165    *      <td>TIME_UPDATE<br></td>
166    *      <td>UPDATE_TIME</td>
167    *      <td>CAD time String.  (HHMM)</td>
168    *    </tr>
169    *    <tr>
170    *      <td>ROUTED_MESSAGE<br></td>
171    *      <td>UPDATE_MSG_COUNT</td>
172    *      <td>Number of messages.</td>
173    *    </tr>
174    *    <tr>
175    *      <td><br></td>
176    *      <td>UPDATE_MSG_UNREAD</td>
177    *      <td>Boolean flag to designate unread messages.</td>
178    *    </tr>
179    *    <tr>
180    *      <td>CAD_INFO_MESSAGE<br></td>
181    *      <td>CAD_INFO</td>
182    *      <td></td>
183    *    </tr>
184    *    <tr>
185    *      <td>REFRESH_VIEW<br></td>
186    *      <td>UPDATE_SCREEN</td>
187    *      <td>Current CAD model XML data.</td>
188    *    </tr>   
189    *  </tbody>
190    *</table>
191     *
192     * @see ObserverMessage
193     * @see CAD_SIMULATOR_CMD
194     */ 
195    public void update(Observable o, Object arg) {
196       
197        ObserverMessage oMessage = (ObserverMessage)arg;
198        CAD_SIMULATOR_CMD simCmd = null;
199       
200        switch(oMessage.type) {
201            case SCREEN_UPDATE:
202                simCmd = CAD_SIMULATOR_CMD.UPDATE_STATUS;
203                break;
204                       
205            case TIME_UPDATE:
206                simCmd = CAD_SIMULATOR_CMD.UPDATE_TIME;
207                break;
208               
209            case ROUTED_MESSAGE:
210                sendRoutedMessageUpdate();
211                break;
212               
213            case CAD_INFO_MESSAGE:
214                simCmd = CAD_SIMULATOR_CMD.CAD_INFO;
215                break;     
216               
217            case REFRESH_VIEW:
218                sendScreenRefresh();
219                break;
220        }
221       
222
223        if(simCmd != null) {
224            try {
225               
226                Document cmdDoc = DocumentBuilderFactory.newInstance()
227                        .newDocumentBuilder().newDocument();
228                cmdDoc.appendChild(cmdDoc.createElement(
229                        simCmd.type));
230                cmdDoc.getDocumentElement().appendChild(
231                        cmdDoc.createTextNode(oMessage.value.toString()));
232                transmitCommand(cmdDoc);
233   
234            } catch (Exception e) {
235                cadLogger.logp(Level.SEVERE, "CADSimulatorClient", "update", 
236                        "Error in transmitting a command to client.", e);
237            }           
238        }
239       
240    }
241   
242    /**
243     * This method acts as a helper method to create a XML Document
244     * update messages with the number of routed messages and
245     * whether there are unread messages for this client.  These
246     * two messages are sent separately due to the defined
247     * command protocol.
248     */
249    private void sendRoutedMessageUpdate() {
250
251        try {           
252            Document cmdDoc = DocumentBuilderFactory.newInstance()
253                .newDocumentBuilder().newDocument();
254            Element docElem = cmdDoc.createElement(
255                    CAD_SIMULATOR_CMD.UPDATE_MSG_COUNT.type);
256            docElem.appendChild(cmdDoc
257                    .createTextNode(String.valueOf(screenManager
258                            .getCurrentCADModel().numberRoutedMessages)));
259            cmdDoc.appendChild(docElem);
260            transmitCommand(cmdDoc);
261           
262
263            cmdDoc = DocumentBuilderFactory.newInstance()
264                .newDocumentBuilder().newDocument();
265            docElem = cmdDoc.createElement(
266                    CAD_SIMULATOR_CMD.UPDATE_MSG_UNREAD.type);
267            docElem.appendChild(cmdDoc
268                    .createTextNode(String.valueOf(screenManager
269                            .getCurrentCADModel().unreadMessages)));
270            cmdDoc.appendChild(docElem);
271            transmitCommand(cmdDoc);           
272
273        } catch (Exception e) {
274            cadLogger.logp(Level.SEVERE, "CADSimulatorClient", 
275                    "sendRoutedMessageUpdate", 
276                    "Error in transmitting a command to client.", e);
277        }   
278    }
279   
280    /**
281     * This method acts as a helper method to create an XML Document
282     * update message with the current CAD Model's XML information.
283     */
284    private void sendScreenRefresh() {
285       
286        try {           
287            Document cmdDoc = DocumentBuilderFactory.newInstance()
288                    .newDocumentBuilder().newDocument();
289            Element docElem = cmdDoc.createElement(
290                    CAD_SIMULATOR_CMD.UPDATE_SCREEN.type);
291           
292            screenManager.getCurrentCADModel().toXML(docElem);
293           
294            cmdDoc.appendChild(docElem);
295            transmitCommand(cmdDoc);
296
297        } catch (Exception e) {
298            cadLogger.logp(Level.SEVERE, "CADSimulatorClient", 
299                    "sendScreenRefresh", 
300                    "Error in transmitting a command to client.", e);
301        }               
302    }
303   
304    /**
305     * This method parses the data that has been received on the socket.  The
306     * Data is cast to an XML Document and the root element determines the
307     * data content.  The possible root elements and the corresponding action
308     * are explained below. <br>
309     * <code>
310     * -----------<br>
311     * TERMINAL_REGISTER<br>
312     *
313     * The CAD position and user ID are parsed from the Element and these
314     * values are sent to the CADScreenManager for use.<br>
315     * -----------<br>
316     * SAVE_COMMAND_LINE<br>
317     *
318     * The current command line text is parsed from the Element and sent
319     * to the CADScreenManager for user.
320     * <br>
321     * -----------<br>
322     * TERMINAL_CMD_LINE<br>
323     * The CAD command is parsed from the Element and converted to a
324     * CAD_CLIENT_CMD enumeration that is used to call the correct
325     * method in the CADScreenManager to perform the command.
326     * <br>
327     * -----------<br>
328     * TERMINAL_FUNCTION<br>
329     *
330     * The key value is parsed from the Element and converted to a CAD_KEYS
331     * enumeration that is sent to the CADScreenManager to perform the
332     * associated action.
333     * <br>
334     * -----------<br>
335     * TERMINATE<br>
336     *
337     * <br>
338     * -----------<br>
339     * </code>
340     * @param receivedData String of data received on the socket.
341     *
342     * @see CADProtocol
343     */
344    private void receiveObject(Object rxData) throws IOException {
345       
346        try {   
347           
348            Element root  = ((Document)rxData).getDocumentElement();
349       
350            switch(CAD_CLIENT_CMD.fromString(root.getNodeName())) {
351           
352                case TERMINAL_REGISTER:
353                    Node positionNode = root.getChildNodes().item(0);
354                    screenManager.setCADPosition(Integer.parseInt(positionNode.getTextContent()));
355                   
356                    Node userIDNode   = root.getChildNodes().item(1);
357                    screenManager.setCADUserID(userIDNode.getTextContent());                           
358                    break;         
359                 
360                case SAVE_COMMAND_LINE:
361                    screenManager.receiveCommandLine(root.getTextContent());
362                    break;
363                case TERMINAL_CMD_LINE:
364                   
365                    Node commandNode = root.getChildNodes().item(0);
366
367                    switch(CAD_COMMANDS.fromFullName(commandNode.getNodeName())) {
368                        case INCIDENT_BOARD:
369                            screenManager.incidentBoardRequest((Element)commandNode);
370                            break;
371                        case INCIDENT_UPDATE:       
372                            screenManager.incidentUpdateRequest((Element)commandNode);
373                            break;
374                        case INCIDENT_INQUIRY:                 
375                            screenManager.incidentInquiryRequest((Element)commandNode);
376                            break;
377                        case INCIDENT_SUMMARY:             
378                            screenManager.incidentSummaryRequest((Element)commandNode);
379                            break;
380                        case ROUTED_MESSAGE:           
381                            screenManager.routedMessageRequest((Element)commandNode);
382                            break;
383                        case ENTER_INCIDENT:           
384                            screenManager.enterIncidentRequest((Element)commandNode);
385                            break;
386                        case TERMINAL_OFF:             
387                            screenManager.terminalOffRequest();
388                            break;
389                        case APP_CLOSE:             
390                           
391                            try {
392                                Document cmdDoc = DocumentBuilderFactory.newInstance()
393                                        .newDocumentBuilder().newDocument();
394                                cmdDoc.appendChild(cmdDoc.createElement(CAD_SIMULATOR_CMD.
395                                        APP_CLOSE.type));                               transmitCommand(cmdDoc);
396                   
397                            } catch (Exception e) {
398                                cadLogger.logp(Level.SEVERE, "CADSimulatorClient", "update", 
399                                        "Error in transmitting a command to client.", e);
400                            }   
401
402                            //disconnectClient();
403                            break;
404                        case UNKNOWN:
405                            //TODO
406                            break;
407                    }
408                    break;
409           
410                case TERMINAL_FUNCTION:             
411                    screenManager.receiveCommand(CAD_KEYS.fromValue(
412                            root.getTextContent().substring(
413                                    0, root.getTextContent().indexOf(":")),                         
414                            new Integer(root.getTextContent().substring(
415                                    root.getTextContent().indexOf(":") + 1))));
416                    break;
417            }     
418        }
419        catch (ClassCastException cce) {
420            cadLogger.logp(Level.SEVERE, "CADSimulatorClient", 
421                    "receiveObject", 
422                    "Incorrect object received from client.", cce);
423        }
424    }   
425   
426    /**
427     * This method transmits the Document command message to the remote
428     * CAD Client.  If an exception occurs in writing to the socket, an
429     * Exception is thrown and socket communication is closed.
430     *
431     * @param data The data being transmitted
432     * @throws IOException if there is an exception in writing to the socket.
433     */
434    private void transmitCommand(Document data) throws IOException {
435 
436        try {
437            out.writeObject(data);
438            out.flush();
439        } catch (IOException ioe) {
440            cadLogger.logp(Level.SEVERE, "CADSimulatorClient", 
441                    "transmitCommand",  "Error writing to Client socket: " + 
442                    theSocket.getInetAddress() + ", continuing.\n", ioe);
443
444            //disconnectClient();
445        }
446           
447    }
448} 
Note: See TracBrowser for help on using the repository browser.