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 @ 6

Revision 6, 18.2 KB checked in by jdalbey, 10 years ago (diff)

Multifile commit. Add version # to Paramics Communicator. Move Load button in Sim Mgr. Add several tests. Add package jars target.

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        public String name;
78
79        private PROPERTIES(String n)
80        {
81            name = n;
82        }
83    }
84    /**
85     * Properties object.
86     */
87    private Properties paramicsCommProp = null;
88    /**
89     * Current working directory where files will be read and written
90     */
91    private String workingDirectory = null;
92    /**
93     * Socket used to create socket communication with the CAD Simulator.
94     */
95    private ServerSocket serverSocket = null;
96    /**
97     * Soccket used to communicate with CAD Simulator.
98     */
99    private Socket paramicsSocket = null;
100    /**
101     * Input Stream for reading data from the CAD Simulator.
102     */
103    private ObjectInputStream in = null;
104    /**
105     * Output Stream for writing data to the CAD Simulator.
106     */
107    private ObjectOutputStream out = null;
108    /**
109     * Map of all current ParamicsFileWriters referenced by I/O ID.
110     */
111    private TreeMap<String, ParamicsFileWriter> writers = null;
112    /**
113     * Map of all current ParamicsFileReaders referenced by I/O ID.
114     */
115    private TreeMap<String, ParamicsFileReader> readers = null;
116    /**
117     * The view class for the ParamicsCommunicator.
118     */
119    private ParamicsCommunicatorGUI theGUI;
120
121    /**
122     * Constructor. Read in the property values. If the properties file does not
123     * contain a value for the working directory, open a dialog to prompt the
124     * user for the path of the Paramics working directory. An empty string is
125     * not accepted. A null signifies that the user pressed cancel. Prompt the
126     * user to accept the cancel and exit the application if confirmed. Continue
127     * until a valid directory has been entered, that exists, and append a '\'
128     * to the end of the directory if necessary.
129     *
130     * Initialize the Sockets and begin communication.
131     *
132     * @param propertiesFilePath File Path of ParamicsCommunicator properties
133     * file.
134     */
135    public ParamicsCommunicator(String propertiesFile)
136    {
137
138        writers = new TreeMap<String, ParamicsFileWriter>();
139        readers = new TreeMap<String, ParamicsFileReader>();
140
141        theGUI = new ParamicsCommunicatorGUI();
142        addObserver(theGUI);
143        theGUI.addWindowListener(new WindowListener()
144        {
145            public void windowActivated(WindowEvent arg0)
146            {
147            }
148
149            ;
150            public void windowClosed(WindowEvent arg0)
151            {
152            }
153
154            ;
155            public void windowClosing(WindowEvent arg0)
156            {
157                System.exit(0);
158            }
159
160            public void windowDeactivated(WindowEvent arg0)
161            {
162            }
163
164            ;
165            public void windowDeiconified(WindowEvent arg0)
166            {
167            }
168
169            ;
170            public void windowIconified(WindowEvent arg0)
171            {
172            }
173
174            ;
175            public void windowOpened(WindowEvent arg0)
176            {
177            }
178        ;
179        });
180
181        try
182        {
183            paramicsCommProp = new Properties();
184            paramicsCommProp.load(new FileInputStream(propertiesFile));
185
186            if (paramicsCommProp.getProperty(PROPERTIES.SOCKET_PORT.name) == null)
187            {
188                JOptionPane.showMessageDialog(theGUI,
189                        "Properties file missing CAD Simulator Port information.",
190                        "Invalid Configuration", JOptionPane.ERROR_MESSAGE);
191                System.exit(0);
192            } else if (paramicsCommProp.getProperty(PROPERTIES.WORKING_DIR.name) == null
193                    || paramicsCommProp.getProperty(PROPERTIES.WORKING_DIR.name).length() == 0)
194            {
195
196                try
197                {
198                    String workingDir = null;
199
200                    while (workingDir == null || workingDir.length() == 0)
201                    {
202                        workingDir = JOptionPane.showInputDialog(null,
203                                "Please set the output directory for Paramics communication.",
204                                "Paramics Working Directory", JOptionPane.QUESTION_MESSAGE);
205
206                        if (workingDir == null)
207                        {
208                        } else if (!new File(workingDir).exists())
209                        {
210                            JOptionPane.showMessageDialog(null,
211                                    "Directory does not exist.",
212                                    "Invalid Working Directory", JOptionPane.WARNING_MESSAGE);
213
214                            workingDir = null;
215                        } else if (!new File(workingDir).isDirectory())
216                        {
217                            JOptionPane.showMessageDialog(null,
218                                    workingDir + " is not a directory.",
219                                    "Invalid Working Directory", JOptionPane.WARNING_MESSAGE);
220
221                            workingDir = null;
222                        }
223                    }
224
225                    if (workingDir.lastIndexOf("\\") != workingDir.length() - 1)
226                    {
227                        workingDir = workingDir + "\\";
228                    }
229
230                    paramicsCommProp.setProperty(PROPERTIES.WORKING_DIR.name, workingDir);
231                    paramicsCommProp.store(new FileOutputStream(propertiesFile), "");
232                } catch (IOException ioe)
233                {
234                    paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "Constructor",
235                            "Exception in writing properties file.", ioe);
236                }
237
238            }
239
240            workingDirectory = paramicsCommProp.getProperty(
241                    PROPERTIES.WORKING_DIR.name).trim();
242
243        } catch (Exception e)
244        {
245            paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "Constructor",
246                    "Exception in reading properties file.", e);
247        }
248
249
250        try
251        {
252            initializeSockets(Integer.parseInt(paramicsCommProp.getProperty(
253                    PROPERTIES.SOCKET_PORT.name).trim()));
254        } catch (Exception e)
255        {
256            paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "Constructor",
257                    "Exception in initializing sockets.", e);
258        }
259
260    }
261
262    /**
263     * Transmits a message XML document object to the CAD Simulator.
264     *
265     * @param mess The ParamicsCommMessage to be transmitted.
266     */
267    private void write(Document mess)
268    {
269
270        synchronized (paramicsSocket)
271        {
272            try
273            {
274                out.writeObject(mess);
275                out.flush();
276            } catch (Exception e)
277            {
278                paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "write",
279                        "Exception in writing to the socket.", e);
280            }
281        }
282    }
283
284    /**
285     * Observer/Observable update method. The Paramics Communicator observers
286     * registered ParamicsReaders. When messages are to be sent, they are sent
287     * through this method. All messages are ParamicsCommMessage objects. Send
288     * these messages to the write() method for transmission on the socket.
289     */
290    public void update(Observable o, Object arg)
291    {
292
293        if (arg instanceof Document)
294        {
295            write((Document) arg);
296        }
297    }
298
299    /**
300     * Runnable method. While this thread is not interrupted, read in an object
301     * from the socket input stream. If an object exists, call doMessage() to
302     * parse and perform the received action in the message.
303     */
304    public void run()
305    {
306
307        while (true)
308        {
309            try
310            {
311                doMessage((Document) in.readObject());
312            } catch (SocketTimeoutException ste)
313            {
314                //just try again
315            } catch (EOFException eofe)
316            {
317                paramLogger.logp(Level.SEVERE, "ParamicsCommunicator",
318                        "run", "EOF Exception in reading data from the socket.", eofe);
319            } catch (Exception e)
320            {
321                paramLogger.logp(Level.SEVERE, "ParamicsCommunicator",
322                        "run", "Exception in reading data from the socket.", e);
323
324                JOptionPane.showMessageDialog(theGUI,
325                        "Connection has been lost to the CAD Simulator.  "
326                        + "Paramics Communicator will now shutdown.",
327                        "Dropped Connection", JOptionPane.ERROR_MESSAGE);
328                break;
329            }
330        }
331
332
333        try
334        {
335            in.close();
336        } catch (Exception e)
337        {
338        }
339        try
340        {
341            out.close();
342        } catch (Exception e)
343        {
344        }
345        try
346        {
347            serverSocket.close();
348        } catch (Exception e)
349        {
350        }
351        try
352        {
353            paramicsSocket.close();
354        } catch (Exception e)
355        {
356        }
357
358    }
359
360    /**
361     * Perform the action represented in the received XML document message.
362     * First determine if the action is from a READER, WRITER, and RESET. If the
363     * paramics action is REGISTER, add a new ParamicsFileReader/Writer to the
364     * local list of readers/writers and update the GUI with a FileRegUpdate
365     * object. If the paramics action is UNREGISTER, remove the
366     * ParamicsFileReader/Writer from the local list of readers/writers and
367     * update the GUI with a FileRegUpdate object. If RESET is received, clear
368     * all readers and writers.
369     *
370     * @param mess Received XML document message.
371     */
372    private void doMessage(Document mess)
373    {
374
375        Element rootElement = mess.getDocumentElement();
376
377        String id = null;
378        String action = null;
379
380        switch (PARAMICS_COMM_TAGS.fromString(rootElement.getNodeName()))
381        {
382            case READER:
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                        Integer interval = Integer.parseInt(rootElement.getChildNodes().item(0).getTextContent());
390                        String targetFile = rootElement.getChildNodes().item(1).getTextContent();
391
392                        readers.put(id, new ParamicsFileReader(workingDirectory, id,
393                                interval, targetFile));
394                        readers.get(id).addObserver(this);
395                        readers.get(id).addObserver(theGUI);
396
397                        setChanged();
398                        notifyObservers(new FileRegUpdate(IO_TYPE.READ,
399                                REG_TYPE.REGISTER, id, targetFile, interval));
400                        break;
401                    case UNREGISTER:
402                        readers.get(id).deleteObserver(this);
403                        readers.get(id).deleteObserver(theGUI);
404                        readers.remove(id);
405
406                        setChanged();
407                        notifyObservers(new FileRegUpdate(IO_TYPE.READ,
408                                REG_TYPE.UNREGISTER, id, null, null));
409                        break;
410                }
411                break;
412            case WRITER:
413                id = rootElement.getAttribute(PARAMICS_COMM_TAGS.ID.tag);
414                action = rootElement.getAttribute(PARAMICS_COMM_TAGS.ACTION.tag);
415
416                switch (PARAMICS_ACTIONS.fromString(action))
417                {
418                    case REGISTER:
419                        String targetFile = rootElement.getChildNodes().item(0).getTextContent();
420
421                        writers.put(id, new ParamicsFileWriter(id,
422                                workingDirectory, targetFile));
423                        writers.get(id).addObserver(theGUI);
424
425                        setChanged();
426                        notifyObservers(new FileRegUpdate(IO_TYPE.WRITE,
427                                REG_TYPE.REGISTER, id, targetFile, null));
428                        break;
429                    case UNREGISTER:
430                        writers.remove(id);
431
432                        writers.get(id).deleteObserver(theGUI);
433
434                        setChanged();
435                        notifyObservers(new FileRegUpdate(IO_TYPE.WRITE,
436                                REG_TYPE.UNREGISTER, id, null, null));
437                        break;
438                    case WRITE_FILE:
439                        writers.get(id).writeMessage((Element) rootElement.getChildNodes().item(0));
440                        break;
441                }
442                break;
443            case RESET:
444                readers.clear();
445                writers.clear();
446                break;
447        }
448    }
449
450    /**
451     * Method waits to accept a socket connection from the CAD Simulator. When a
452     * connection has been established the method exits. The input and output
453     * streams are created on the new socket.
454     *
455     * @param socketPort Socket port to use for establishing Socket
456     * communication.
457     * @throws IOException if there is an exception in establishing Socket
458     * communication.
459     */
460    private void initializeSockets(Integer socketPort) throws IOException
461    {
462
463        boolean waiting = true;
464
465        try
466        {
467            serverSocket = new ServerSocket(socketPort);
468            //delay for accept timeout(milliseconds)
469            serverSocket.setSoTimeout(10 * 1000);
470        } catch (IOException ioe)
471        {
472            throw new IOException("Exception in creating "
473                    + "the server socket on port " + socketPort);
474        }
475
476        while (waiting)
477        {
478            try
479            {
480                paramicsSocket = serverSocket.accept();
481                waiting = false;
482            } catch (SocketTimeoutException ste)
483            {
484                System.out.println("...waiting...");
485            } catch (IOException ioe)
486            {
487                throw new IOException("Exception in creating "
488                        + "the receiving socket on port " + socketPort);
489            }
490        }
491
492
493        //** out must be performed before in to unlock for connecting socket **//
494        try
495        {
496            out = new ObjectOutputStream(paramicsSocket.getOutputStream());
497            in = new ObjectInputStream(paramicsSocket.getInputStream());
498        } catch (IOException ioe)
499        {
500            throw new IOException("Exception in creating input "
501                    + "and output streams on socket.");
502        }
503
504    }
505
506    /**
507     * Construct the ParamicsCommunicator with the properties file path, either
508     * from the command line arguments or default.
509     *
510     * @param args Command line arguments.
511     */
512    public static void main(String[] args)
513    {
514        System.setProperty("PARAMICS_COMM_PROPERTIES", "config/paramics_communicator_config.properties");
515
516        try
517        {
518            if (System.getProperty("PARAMICS_COMM_PROPERTIES") != null)
519            {
520                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
521
522                new Thread(new ParamicsCommunicator(System.getProperty(
523                        "PARAMICS_COMM_PROPERTIES"))).start();
524            } else
525            {
526                throw new Exception("PARAMICS_COMM_PROPERTIES system property not defined.");
527            }
528        } catch (Exception e)
529        {
530            paramLogger.logp(Level.SEVERE, "ParamicsCommunicator", "Main",
531                    "Error occured initializing application", e);
532
533            JOptionPane.showMessageDialog(null, e.getMessage(),
534                    "Error - Program Exiting", JOptionPane.ERROR_MESSAGE);
535
536            System.exit(-1);
537        }
538
539
540    }
541}
Note: See TracBrowser for help on using the repository browser.