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

source: tmcsimulator/trunk/src/tmcsim/paramicscommunicator/ParamicsCommunicator.java @ 26

Revision 26, 17.9 KB checked in by jdalbey, 10 years ago (diff)

CADSimulatorNetworkTest added, modifed ParamicsCommunicator? to check for a property if it should run without a GUI (for testing).

RevLine 
1package tmcsim.paramicscommunicator;
2
3import java.awt.event.WindowEvent;
4import java.awt.event.WindowListener;
5import java.io.EOFException;
6import java.io.File;
7import java.io.FileInputStream;
8import java.io.FileOutputStream;
9import java.io.IOException;
10import java.io.ObjectInputStream;
11import java.io.ObjectOutputStream;
12import java.net.ServerSocket;
13import java.net.Socket;
14import java.net.SocketTimeoutException;
15import java.util.Observable;
16import java.util.Observer;
17import java.util.Properties;
18import java.util.TreeMap;
19import java.util.logging.Level;
20import java.util.logging.Logger;
21import javax.swing.JOptionPane;
22import javax.swing.UIManager;
23import org.w3c.dom.Document;
24import org.w3c.dom.Element;
25import tmcsim.common.CADProtocol.PARAMICS_ACTIONS;
26import tmcsim.common.CADProtocol.PARAMICS_COMM_TAGS;
27import tmcsim.paramicscommunicator.FileIOUpdate.IO_TYPE;
28import tmcsim.paramicscommunicator.FileRegUpdate.REG_TYPE;
29import tmcsim.paramicscommunicator.gui.ParamicsCommunicatorGUI;
30
31/**
32 * ParamicsCommunicator is the main class for this module. The Paramics
33 * Communicator is used to provide communication between the CAD Simulator and
34 * the Paramics traffic modeler. While the application is running, data is
35 * received on a socket from the CAD Simulator. Transmitted data are XML
36 * documents containing information and action commands. The CAD Simulator
37 * registers readers and writers with the ParamicsCommunicator. Any data read by
38 * a ParamicsReader is sent back to the CAD Simulator. All data to be written by
39 * a ParamicsWriter is received through the socket.<br><br>
40 * The properties file for the ParamicsCommunicator class contains the following
41 * data.<br>
42 * <code>
43 * -----------------------------------------------------------------------------<br>
44 * Socket Port The port number to use for socket communication.<br>
45 * Working Directory The working directory use for Paramics file
46 * communication.<br>
47 * Error File The target file to use for error logging.<br>
48 * -----------------------------------------------------------------------------<br>
49 * Example File: <br>
50 * SocketPort = 4450 <br>
51 * WorkingDirectory = c:\\tmc_simulator\\ <br>
52 * ErrorFile = sim_mgr_error.xml <br>
53 * -----------------------------------------------------------------------------<br>
54 * </code>
55 *
56 * @author Matthew Cechini (mcechini@calpoly.edu)
57 * @version $Date: 2009/04/17 16:27:46 $ $Revision: 1.7
58 */
59public class ParamicsCommunicator extends Observable implements Observer, Runnable
60{
61
62    /**
63     * Error logger.
64     */
65    private static Logger paramLogger = Logger.getLogger("tmcsim.paramicscommunicator");
66
67    /**
68     * Enumeration containing property names.
69     *
70     * @author Matthew Cechini
71     */
72    private static enum PROPERTIES
73    {
74
75        SOCKET_PORT("SocketPort"),
76        WORKING_DIR("WorkingDirectory"),
77        GUI_VISIBLE("GUIvisible");
78        public String name;
79
80        private PROPERTIES(String n)
81        {
82            name = n;
83        }
84    }
85    /**
86     * Properties object.
87     */
88    private Properties paramicsCommProp = null;
89    /**
90     * Current working directory where files will be read and written
91     */
92    private String workingDirectory = null;
93    /**
94     * Socket used to create socket communication with the CAD Simulator.
95     */
96    private ServerSocket serverSocket = null;
97    /**
98     * Soccket used to communicate with CAD Simulator.
99     */
100    private Socket paramicsSocket = null;
101    /**
102     * Input Stream for reading data from the CAD Simulator.
103     */
104    private ObjectInputStream in = null;
105    /**
106     * Output Stream for writing data to the CAD Simulator.
107     */
108    private ObjectOutputStream out = null;
109    /**
110     * Map of all current ParamicsFileWriters referenced by I/O ID.
111     */
112    private TreeMap<String, ParamicsFileWriter> writers = null;
113    /**
114     * Map of all current ParamicsFileReaders referenced by I/O ID.
115     */
116    private TreeMap<String, ParamicsFileReader> readers = null;
117    /**
118     * The view class for the ParamicsCommunicator.
119     */
120    private ParamicsCommunicatorGUI theGUI;
121
122    /**
123     * Constructor. Read in the property values. If the properties file does not
124     * contain a value for the working directory, open a dialog to prompt the
125     * user for the path of the Paramics working directory. An empty string is
126     * not accepted. A null signifies that the user pressed cancel. Prompt the
127     * user to accept the cancel and exit the application if confirmed. Continue
128     * until a valid directory has been entered, that exists, and append a '\'
129     * to the end of the directory if necessary.
130     *
131     * Initialize the Sockets and begin communication.
132     *
133     * @param propertiesFilePath File Path of ParamicsCommunicator properties
134     * file.
135     */
136    public ParamicsCommunicator(String propertiesFile)
137    {
138
139        writers = new TreeMap<String, ParamicsFileWriter>();
140        readers = new TreeMap<String, ParamicsFileReader>();
141
142        try
143        {
144            paramicsCommProp = new Properties();
145            paramicsCommProp.load(new FileInputStream(propertiesFile));
146
147            if (paramicsCommProp.getProperty(PROPERTIES.SOCKET_PORT.name) == null)
148            {
149                JOptionPane.showMessageDialog(theGUI,
150                        "Properties file missing CAD Simulator Port information.",
151                        "Invalid Configuration", JOptionPane.ERROR_MESSAGE);
152                System.exit(0);
153            } else if (paramicsCommProp.getProperty(PROPERTIES.WORKING_DIR.name) == null
154                    || paramicsCommProp.getProperty(PROPERTIES.WORKING_DIR.name).length() == 0)
155            {
156
157                try
158                {
159                    String workingDir = null;
160
161                    while (workingDir == null || workingDir.length() == 0)
162                    {
163                        workingDir = JOptionPane.showInputDialog(null,
164                                "Please set the output directory for Paramics communication.",
165                                "Paramics Working Directory", JOptionPane.QUESTION_MESSAGE);
166
167                        if (workingDir == null)
168                        {
169                        } else if (!new File(workingDir).exists())
170                        {
171                            JOptionPane.showMessageDialog(null,
172                                    "Directory does not exist.",
173                                    "Invalid Working Directory", JOptionPane.WARNING_MESSAGE);
174
175                            workingDir = null;
176                        } else if (!new File(workingDir).isDirectory())
177                        {
178                            JOptionPane.showMessageDialog(null,
179                                    workingDir + " is not a directory.",
180                                    "Invalid Working Directory", JOptionPane.WARNING_MESSAGE);
181
182                            workingDir = null;
183                        }
184                    }
185
186                    if (workingDir.lastIndexOf("\\") != workingDir.length() - 1)
187                    {
188                        workingDir = workingDir + "\\";
189                    }
190
191                    paramicsCommProp.setProperty(PROPERTIES.WORKING_DIR.name, workingDir);
192                    paramicsCommProp.store(new FileOutputStream(propertiesFile), "");
193                } catch (IOException ioe)
194                {
195                    paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "Constructor",
196                            "Exception in writing properties file.", ioe);
197                }
198
199            }
200
201            workingDirectory = paramicsCommProp.getProperty(
202                    PROPERTIES.WORKING_DIR.name).trim();
203
204        } catch (Exception e)
205        {
206            paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "Constructor",
207                    "Exception in reading properties file.", e);
208        }
209
210        // Should we display the GUI?
211        String visibleProp = paramicsCommProp.getProperty(PROPERTIES.GUI_VISIBLE.name);
212        // If no property was given, or if it was given and says True
213        if (visibleProp == null || (visibleProp.toLowerCase().equals("true")))
214        {
215            theGUI = new ParamicsCommunicatorGUI(); // it sets itself visible
216            addObserver(theGUI);
217            theGUI.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
218        }
219
220        try
221        {
222            initializeSockets(Integer.parseInt(paramicsCommProp.getProperty(
223                    PROPERTIES.SOCKET_PORT.name).trim()));
224        } catch (Exception e)
225        {
226            paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "Constructor",
227                    "Exception in initializing sockets.", e);
228        }
229
230    }
231
232    /**
233     * Transmits a message XML document object to the CAD Simulator.
234     *
235     * @param mess The ParamicsCommMessage to be transmitted.
236     */
237    private void write(Document mess)
238    {
239
240        synchronized (paramicsSocket)
241        {
242            try
243            {
244                out.writeObject(mess);
245                out.flush();
246            } catch (Exception e)
247            {
248                paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "write",
249                        "Exception in writing to the socket.", e);
250            }
251        }
252    }
253
254    /**
255     * Observer/Observable update method. The Paramics Communicator observers
256     * registered ParamicsReaders. When messages are to be sent, they are sent
257     * through this method. All messages are ParamicsCommMessage objects. Send
258     * these messages to the write() method for transmission on the socket.
259     */
260    public void update(Observable o, Object arg)
261    {
262
263        if (arg instanceof Document)
264        {
265            write((Document) arg);
266        }
267    }
268
269    /**
270     * Runnable method. While this thread is not interrupted, read in an object
271     * from the socket input stream. If an object exists, call doMessage() to
272     * parse and perform the received action in the message.
273     */
274    public void run()
275    {
276
277        while (true)
278        {
279            try
280            {
281                doMessage((Document) in.readObject());
282            } catch (SocketTimeoutException ste)
283            {
284                //just try again
285            } catch (EOFException eofe)
286            {
287                paramLogger.logp(Level.SEVERE, "ParamicsCommunicator",
288                        "run", "EOF Exception in reading data from the socket.", eofe);
289            } catch (Exception e)
290            {
291                paramLogger.logp(Level.SEVERE, "ParamicsCommunicator",
292                        "run", "Exception in reading data from the socket.", e);
293
294                JOptionPane.showMessageDialog(theGUI,
295                        "Connection has been lost to the CAD Simulator.  "
296                        + "Paramics Communicator will now shutdown.",
297                        "Dropped Connection", JOptionPane.ERROR_MESSAGE);
298                break;
299            }
300        }
301
302
303        try
304        {
305            in.close();
306        } catch (Exception e)
307        {
308        }
309        try
310        {
311            out.close();
312        } catch (Exception e)
313        {
314        }
315        try
316        {
317            serverSocket.close();
318        } catch (Exception e)
319        {
320        }
321        try
322        {
323            paramicsSocket.close();
324        } catch (Exception e)
325        {
326        }
327
328    }
329
330    /**
331     * Perform the action represented in XML document message received from the
332     * CAD Simulator. First determine if the action is from a READER, WRITER,
333     * and RESET. If the paramics action is REGISTER, add a new
334     * ParamicsFileReader/Writer to the local list of readers/writers and update
335     * the GUI with a FileRegUpdate object. If the paramics action is
336     * UNREGISTER, remove the ParamicsFileReader/Writer from the local list of
337     * readers/writers and update the GUI with a FileRegUpdate object. If RESET
338     * is received, clear all readers and writers.
339     *
340     * @param mess Received XML document message.
341     */
342    private void doMessage(Document mess)
343    {
344
345        Element rootElement = mess.getDocumentElement();
346
347        String id = null;
348        String action = null;
349
350        switch (PARAMICS_COMM_TAGS.fromString(rootElement.getNodeName()))
351        {
352            case READER:
353                id = rootElement.getAttribute(PARAMICS_COMM_TAGS.ID.tag);
354                action = rootElement.getAttribute(PARAMICS_COMM_TAGS.ACTION.tag);
355
356                switch (PARAMICS_ACTIONS.fromString(action))
357                {
358                    case REGISTER:
359                        Integer interval = Integer.parseInt(rootElement.getChildNodes().item(0).getTextContent());
360                        String targetFile = rootElement.getChildNodes().item(1).getTextContent();
361
362                        readers.put(id, new ParamicsFileReader(workingDirectory, id,
363                                interval, targetFile));
364                        readers.get(id).addObserver(this);
365                        readers.get(id).addObserver(theGUI);
366
367                        setChanged();
368                        notifyObservers(new FileRegUpdate(IO_TYPE.READ,
369                                REG_TYPE.REGISTER, id, targetFile, interval));
370                        break;
371                    case UNREGISTER:
372                        readers.get(id).deleteObserver(this);
373                        readers.get(id).deleteObserver(theGUI);
374                        readers.remove(id);
375
376                        setChanged();
377                        notifyObservers(new FileRegUpdate(IO_TYPE.READ,
378                                REG_TYPE.UNREGISTER, id, null, null));
379                        break;
380                }
381                break;
382            case WRITER:
383                id = rootElement.getAttribute(PARAMICS_COMM_TAGS.ID.tag);
384                action = rootElement.getAttribute(PARAMICS_COMM_TAGS.ACTION.tag);
385
386                switch (PARAMICS_ACTIONS.fromString(action))
387                {
388                    case REGISTER:
389                        String targetFile = rootElement.getChildNodes().item(0).getTextContent();
390
391                        writers.put(id, new ParamicsFileWriter(id,
392                                workingDirectory, targetFile));
393                        writers.get(id).addObserver(theGUI);
394
395                        setChanged();
396                        notifyObservers(new FileRegUpdate(IO_TYPE.WRITE,
397                                REG_TYPE.REGISTER, id, targetFile, null));
398                        break;
399                    case UNREGISTER:
400                        writers.remove(id);
401
402                        writers.get(id).deleteObserver(theGUI);
403
404                        setChanged();
405                        notifyObservers(new FileRegUpdate(IO_TYPE.WRITE,
406                                REG_TYPE.UNREGISTER, id, null, null));
407                        break;
408                    case WRITE_FILE:
409                        writers.get(id).writeMessage((Element) rootElement.getChildNodes().item(0));
410                        break;
411                }
412                break;
413            case RESET:
414                readers.clear();
415                writers.clear();
416                break;
417        }
418    }
419
420    /**
421     * Method waits to accept a socket connection from the CAD Simulator. When a
422     * connection has been established the method exits. The input and output
423     * streams are created on the new socket.
424     *
425     * @param socketPort Socket port to use for establishing Socket
426     * communication.
427     * @throws IOException if there is an exception in establishing Socket
428     * communication.
429     */
430    private void initializeSockets(Integer socketPort) throws IOException
431    {
432
433        boolean waiting = true;
434
435        try
436        {
437            serverSocket = new ServerSocket(socketPort);
438            //delay for accept timeout(milliseconds)
439            serverSocket.setSoTimeout(10 * 1000);
440        } catch (IOException ioe)
441        {
442            throw new IOException("Exception in creating "
443                    + "the server socket on port " + socketPort);
444        }
445
446        while (waiting)
447        {
448            try
449            {
450                paramicsSocket = serverSocket.accept();
451                waiting = false;
452            } catch (SocketTimeoutException ste)
453            {
454                System.out.println("...waiting for socket connection from the CAD Simulator...");
455            } catch (IOException ioe)
456            {
457                throw new IOException("Exception in creating "
458                        + "the receiving socket on port " + socketPort);
459            }
460        }
461
462
463        //** out must be performed before in to unlock for connecting socket **//
464        try
465        {
466            out = new ObjectOutputStream(paramicsSocket.getOutputStream());
467            in = new ObjectInputStream(paramicsSocket.getInputStream());
468        } catch (IOException ioe)
469        {
470            throw new IOException("Exception in creating input "
471                    + "and output streams on socket.");
472        }
473
474    }
475
476    /**
477     * Construct the ParamicsCommunicator with the properties file path, either
478     * from the command line arguments or default.
479     *
480     * @param args Command line arguments.
481     */
482    public static void main(String[] args)
483    {
484        System.setProperty("PARAMICS_COMM_PROPERTIES", "config/paramics_communicator_config.properties");
485
486        try
487        {
488            if (System.getProperty("PARAMICS_COMM_PROPERTIES") != null)
489            {
490                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
491
492                new Thread(new ParamicsCommunicator(System.getProperty(
493                        "PARAMICS_COMM_PROPERTIES"))).start();
494            } else
495            {
496                throw new Exception("PARAMICS_COMM_PROPERTIES system property not defined.");
497            }
498        } catch (Exception e)
499        {
500            paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "Main",
501                    "Error occured initializing application", e);
502
503            JOptionPane.showMessageDialog(null, e.getMessage(),
504                    "Error - Program Exiting", JOptionPane.ERROR_MESSAGE);
505
506            System.exit(-1);
507        }
508
509
510    }
511}
Note: See TracBrowser for help on using the repository browser.