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

Revision 47, 18.9 KB checked in by jdalbey, 10 years ago (diff)

Merge 305 modifications into trunk.

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