source: tmcsimulator/trunk/src/tmcsim/client/CADClientModel.java @ 445

Revision 445, 12.6 KB checked in by jdalbey, 7 years ago (diff)

Changed restart dialog in CADClientView to a non-modal one to fix #159. Shortened exception log messages in other client modules.

Line 
1package tmcsim.client;
2
3import java.io.EOFException;
4import java.io.IOException;
5import java.io.InputStream;
6import java.io.ObjectInputStream;
7import java.io.ObjectOutputStream;
8import java.io.OutputStream;
9import java.util.Observable;
10import java.util.logging.Level;
11import java.util.logging.Logger;
12
13import javax.xml.parsers.DocumentBuilderFactory;
14
15import org.w3c.dom.Document;
16import org.w3c.dom.Element;
17import org.w3c.dom.Node;
18
19import tmcsim.cadmodels.BlankScreenModel;
20import tmcsim.cadmodels.CADScreenModel;
21import tmcsim.cadmodels.IncidentBoardModel;
22import tmcsim.cadmodels.IncidentInquiryModel;
23import tmcsim.cadmodels.IncidentSummaryModel;
24import tmcsim.cadmodels.RoutedMessageModel;
25import tmcsim.common.ObserverMessage;
26import tmcsim.common.SimulationException;
27import tmcsim.common.CADProtocol.CAD_CLIENT_CMD;
28import tmcsim.common.CADProtocol.CAD_COMMANDS;
29import tmcsim.common.CADProtocol.CAD_SIMULATOR_CMD;
30import tmcsim.common.CADProtocol.DATA_TAGS;
31
32
33/**
34 * CADClientModel handles data transmission between the CAD Client and CAD
35 * Simulator.  Data is read from the input stream and parsed for message updates
36 * from the CAD Simulator.  These updates are described in the receiveObject()
37 * method description.  The transmit() method is called to send Document objects
38 * to the CAD Simulator.
39 *
40 * @author Matthew Cechini (mcechini@calpoly.edu)
41 * @version $Date: 2009/04/20 17:58:27 $ $Revision: 1.5 $
42 */
43public class CADClientModel extends Observable implements Runnable {
44
45    /** Error Logger. */
46    private Logger clientLogger = Logger.getLogger("tmcsim.client");
47   
48    /** Output stream for writing data to the CAD Simulator. */   
49    private ObjectOutputStream out = null;
50
51    /** Input Stream for reading data to the CAD Simulator. */
52    private ObjectInputStream in = null;   
53   
54    /** Boolean flag to designate if Runnable object is running. */
55    private boolean running = true;
56
57
58    /**
59     * Constructor.
60     */
61    public CADClientModel() {  }
62   
63    /**
64     * This method sets the streams that are used for communication
65     * to and from the CAD Simulator.
66     *
67     * @param theIS The input stream to read packets from.
68     * @param theOS The output stream to write packets to.
69     * @throws SimulationException if there is an exception in
70     * creating the Object(Input/Output)Streams.
71     */
72    public void initializeScreen(InputStream theIS,
73                                 OutputStream theOS) throws SimulationException {
74       
75        try  {
76            out = new ObjectOutputStream(theOS);
77            in  = new ObjectInputStream(theIS);
78        }
79        catch (Exception e) {
80            throw new SimulationException(SimulationException.CAD_SIM_COMM, e);
81        }
82   
83    }
84   
85    /**
86     * This method register this CAD Client with the CAD Simulator.  The client
87     * is registered with its CAD position number and user ID. 
88     *
89     * @param CADPosition CAD Position number.
90     * @param userID User ID.
91     * @throws SimulationException if there is an exception in registering the client.
92     */
93    public void register(int CADPosition, String userID) throws SimulationException {
94        try {
95            Document cmdDoc = DocumentBuilderFactory.newInstance()
96                    .newDocumentBuilder().newDocument();
97            Element cmdElem = cmdDoc.createElement(CAD_CLIENT_CMD.TERMINAL_REGISTER.type); 
98           
99            Element posElem = cmdDoc.createElement(DATA_TAGS.POSITION_NUM.tag);
100            posElem.appendChild(cmdDoc.createTextNode(String.valueOf(CADPosition)));
101            cmdElem.appendChild(posElem);
102           
103            Element userIDElem = cmdDoc.createElement(DATA_TAGS.USER_ID.tag);
104            userIDElem.appendChild(cmdDoc.createTextNode(userID));
105            cmdElem.appendChild(userIDElem);
106
107            cmdDoc.appendChild(cmdElem);
108
109            transmitCommand(cmdDoc);
110
111        } catch (Exception e) {
112            clientLogger.logp(Level.SEVERE, "CADClientModel", "register()", 
113                    "Exception in registering client.", e);
114            throw new SimulationException(SimulationException.REGISTER_ERROR, e);
115        }
116    }
117   
118    /**
119     * Run method that must be defined in Runnable interface. 
120     * This method continuously calls the receiveObject() method
121     * to check the input stream for data.  If an exception occurs
122     * reading from the input stream, the streams are closed and
123     * observers are notified with a null object that the model has
124     * disconnected.
125     */
126    public void run() {
127       
128        while(running)  {
129           
130            try {               
131                Thread.sleep(250);
132                receiveObject(in.readObject());                 
133            }
134/*            catch (EOFException eofe) {
135                clientLogger.logp(Level.SEVERE, "CADClientModel", "run()",
136                        "Exception in reading object from input stream.", eofe);
137            }*/
138            catch (Exception e) {
139                clientLogger.logp(Level.SEVERE, "CADClientModel", "run()", 
140                        "Exception in reading object from input stream. " +
141                        "Shutting down client.", e);
142               
143                running = false;
144               
145                closeStreams();
146               
147                setChanged();
148                notifyObservers();
149            }
150        }
151    }
152
153   
154    /**
155     * This method writes the parameter Document object to the
156     * ObjectOutputStream which is transmitted eo the CAD Simulator.
157     * If there is an Exception in writing to the Socket, the streams
158     * are closed and observers are notified with a null object to
159     * signify that the connect has been lost.
160     *
161     * @param command The Document being transmitted.
162     */
163    public void transmitCommand(Document command) {     
164       
165        try {
166            out.writeObject(command);
167            out.flush();
168        }
169        catch (IOException ioe) {
170            clientLogger.logp(Level.SEVERE, "CADClientModel", "transmitObject()", 
171                    "Exception in writing object to the input stream. " +
172                    "Shutting down client.", ioe);
173           
174            running = false;
175           
176            closeStreams();
177           
178            setChanged();
179            notifyObservers();
180        }
181    }
182   
183    /**
184     *<table cellpadding="2" cellspacing="2" border="1"
185     * style="text-align: left; width: 250px;">
186     *  <tbody>
187     *    <tr>
188     *      <th>CAD Protocol Command<br></th>
189     *      <th>Action Taken<br></th>
190     *    </tr>
191     *    <tr>
192     *      <td>UPDATE_SCREEN<br></td>
193     *      <td>A completely new window has been received.  Parse the received
194     *          data into an XML Document.  The root node is used to determine
195     *          which type of CAD Screen is being shown.  Construct the new
196     *          CADScreenModel for that CAD Screem amd notify the view observer with the new
197     *          screen type and model.<br></td>
198     *    </tr>
199     *    <tr>
200     *      <td>UPDATE_STATUS</td>
201     *      <td>Notify the view observer with the new screen update status value.<br></td>
202     *    </tr>
203     *    <tr>
204     *      <td>UPDATE_TIME</td>
205     *      <td>Notify the view observer with the new CAD Time value.<br> </td>
206     *    </tr>
207     *    <tr>
208     *      <td>UPDATE_MSG_COUNT</td>
209     *      <td>Notify the view observer with the new queued message count value.<br> </td>
210     *    </tr>
211     *    <tr>
212     *      <td>UPDATE_MSG_UNREAD</td>
213     *      <td>Notify the view observer with the new boolean unread messages value.<br> </td>
214     *    </tr>
215     *    <tr>
216     *      <td>CAD_INFO</td>
217     *      <td>Notify the view observer with the received informational message value.<br> </td>
218     *    </tr>
219     *  </tbody>
220     *</table>
221     *
222     */
223    private void receiveObject(Object rxData) throws IOException {
224       
225        try {
226           
227            CADScreenModel theCADScreenModel = null;
228           
229            Element root  = ((Document)rxData).getDocumentElement();
230       
231            switch(CAD_SIMULATOR_CMD.fromString(root.getNodeName())) {
232       
233                case UPDATE_SCREEN:
234                                           
235                    Node screenNode = root.getChildNodes().item(0);
236
237                    if(screenNode.getNodeName().equals(CAD_COMMANDS.INCIDENT_INQUIRY.fullName)) {
238                        theCADScreenModel = new IncidentInquiryModel(screenNode);               
239                       
240                        setChanged();
241                        notifyObservers(new ObserverMessage(ObserverMessage.messageType.INCIDENT_INQUIRY, theCADScreenModel)); 
242                    }
243                    else if(screenNode.getNodeName().equals(CAD_COMMANDS.INCIDENT_SUMMARY.fullName)) {                 
244                        theCADScreenModel = new IncidentSummaryModel(screenNode);
245                       
246                        setChanged();
247                        notifyObservers(new ObserverMessage(ObserverMessage.messageType.INCIDENT_SUMMARY, theCADScreenModel)); 
248           
249                    }
250                    else if(screenNode.getNodeName().equals(CAD_COMMANDS.INCIDENT_BOARD.fullName)) {
251                        theCADScreenModel = new IncidentBoardModel(screenNode);
252                       
253                        setChanged();
254                        notifyObservers(new ObserverMessage(ObserverMessage.messageType.INCIDENT_BOARD, theCADScreenModel)); 
255                    }   
256                    else if(screenNode.getNodeName().equals(CAD_COMMANDS.ROUTED_MESSAGE.fullName)) {
257                        theCADScreenModel = new RoutedMessageModel(screenNode);
258                       
259                        setChanged();
260                        notifyObservers(new ObserverMessage(ObserverMessage.messageType.ROUTED_MESSAGE, theCADScreenModel)); 
261                    }                       
262                    else if(screenNode.getNodeName().equals(CAD_COMMANDS.BLANK_SCREEN.fullName)) {
263                        theCADScreenModel = new BlankScreenModel(screenNode);
264                   
265                        setChanged();
266                        notifyObservers(new ObserverMessage(ObserverMessage.messageType.BLANK_SCREEN, theCADScreenModel)); 
267                    }
268                    break;   
269   
270                case UPDATE_STATUS:
271                    setChanged();
272                    notifyObservers(new ObserverMessage(ObserverMessage.messageType.SCREEN_UPDATE, 
273                            root.getTextContent()));
274                    break;
275               
276                case UPDATE_TIME:
277                    setChanged();
278                    notifyObservers(new ObserverMessage(ObserverMessage.messageType.TIME_UPDATE, 
279                            root.getTextContent()));
280                    break;
281               
282                case UPDATE_MSG_COUNT:
283                    setChanged();
284                    notifyObservers(new ObserverMessage(ObserverMessage.messageType.ROUTED_MESSAGE_COUNT_UPDATE, 
285                            Integer.parseInt(root.getTextContent())));
286                    break;
287               
288                case UPDATE_MSG_UNREAD:
289                    setChanged();
290                    notifyObservers(new ObserverMessage(ObserverMessage.messageType.ROUTED_MESSAGE_UNREAD_UPDATE, 
291                            Boolean.parseBoolean(root.getTextContent())));
292                    break;
293               
294                case CAD_INFO:
295                    setChanged();
296                    notifyObservers(new ObserverMessage(ObserverMessage.messageType.CAD_INFO_MESSAGE, 
297                            root.getTextContent()));
298                    break;
299                   
300                case APP_CLOSE:
301                    closeStreams();
302                    System.exit(0);
303                    break;
304            }           
305        } 
306        catch (Exception e) 
307        {
308            clientLogger.logp(Level.SEVERE, "CADClientModel", "receiveObject()", 
309                    "Exception in parsing xml object.", e);
310        }
311    }
312   
313    /**
314     * Close the ouput and input streams.
315     */
316    private void closeStreams() {
317       
318       
319        try {
320            out.close();
321        }
322        catch (Exception e) {
323            clientLogger.logp(Level.SEVERE, "CADClientModel", "closeStreams()", 
324                    "Exception in closing output stream.", e);
325        }
326       
327        try {
328            in.close();
329        }
330        catch (Exception e) {
331            clientLogger.logp(Level.SEVERE, "CADClientModel", "closeStreams()", 
332                    "Exception in closing input stream.", e);
333        }
334       
335    }
336}   
Note: See TracBrowser for help on using the repository browser.