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

source: tmcsimulator/trunk/src/tmcsim/client/ATMSBatchDriver.java @ 184

Revision 184, 17.3 KB checked in by jtorres, 9 years ago (diff)

highways.java: converted to immutable, removed use of FEPLineLoader and added loadLines(), loadLine(), loadStation(), and loadLoop() methods. Renamed loadHighways() to configureHighways(), renamed writeHighwaysMeta() to getHighwaysMeta() which now returns a String containing metadata instead of opening a file and writing to it, which is more flexible. FEPLineLoader.java: deleted, no longer need it. FEPLine.java: converted to immutable, removed unnecessary member variables and adjusted all methods accordingly. Station.java: MLTotVol() and OppTotVol?() are now being updated at end of updateByDirection(). ATMSDriver.java: Now using one config file: highways_fullmap.txt, as opposed to the older lds.txt and loop.txt files. config/vds_data: added highways_fullmap.txt. config/atms_driver_config.properties, atms_driver_config_local.properties: updated config to reflect use of highways_fullmap.txt instead of old loop.txt and lds.txt configuration. ATMSBatchDriver.java: conformed highways initialization in constructor to reflect use of highways_fullmap.txt

RevLine 
1package tmcsim.client;
2
3import atmsdriver.ConsoleTrafficDriver;
4import atmsdriver.model.Highways;
5import atmsdriver.model.TrafficEvent;
6import atmsdriver.model.LoopDetector.DOTCOLOR;
7import java.awt.event.ActionEvent;
8import java.awt.event.ActionListener;
9import java.io.FileInputStream;
10import java.io.FileNotFoundException;
11import java.rmi.Naming;
12import java.rmi.RemoteException;
13import java.rmi.server.UnicastRemoteObject;
14import java.text.ParseException;
15import java.text.SimpleDateFormat;
16import java.util.ArrayList;
17import java.util.Collections;
18import java.util.Date;
19import java.util.HashMap;
20import java.util.LinkedList;
21import java.util.List;
22import java.util.Map;
23import java.util.Properties;
24import java.util.Scanner;
25import java.util.concurrent.TimeUnit;
26import java.util.logging.Level;
27import java.util.logging.Logger;
28import javax.swing.JOptionPane;
29import javax.swing.JWindow;
30import javax.swing.Timer;
31import javax.swing.UIManager;
32import tmcsim.common.SimulationException;
33import tmcsim.interfaces.CADClientInterface;
34import tmcsim.interfaces.CoordinatorInterface;
35
36/**
37 * Skeleton for ATMS Driver that reads a "batch" file of highway status update
38 * commands. It operates as a client of the CAD server, using RMI to poll the
39 * server every second for the current simulation clock time. It uses the
40 * simulation clock time to fire update commands at the desired time. Note: Sim
41 * Mgr must be running before starting this application. TODO: We probably want
42 * to be able to "override" a command, to force clearing an incident.
43 *
44 * @author jdalbey
45 */
46public class ATMSBatchDriver extends UnicastRemoteObject implements
47        CADClientInterface
48{
49
50    private static final String CONFIG_FILE_NAME = "cad_client_config.properties";
51    private final static int ONE_SECOND = 1000;
52    private static final int FEPSIM_INTERVAL = 30000;
53    private final static SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
54    /**
55     * Error logger.
56     */
57    private static Logger cadClientLogger = Logger.getLogger("tmcsim.client");
58
59    @Override
60    public void refresh() throws RemoteException
61    {
62        System.out.println("ATMSBatchDriver.refresh() was invoked.");
63    }
64
65    /**
66     * Enumeration containing properties name values. See CADClient class
67     * description for more information.
68     *
69     * @author Matthew Cechini
70     * @see CADClient
71     */
72    private static enum PROPERTIES
73    {
74        CAD_SIM_HOST("CADSimulatorHost"), CAD_SIM_PORT("CADSimulatorSocketPort"), CAD_RMI_PORT(
75                "CADRmiPort"), CLIENT_CAD_POS("CADPosition"), CLIENT_USER_ID(
76                "CADUserID"), KEYBOARD_TYPE("KeyboardType"), DISPLAY_TYPE(
77                "DisplayType");
78        public String name;
79
80        private PROPERTIES(String n)
81        {
82            name = n;
83        }
84    }
85    /**
86     * CADClientSocket Object to handle socket communication between the Client
87     * and CAD Simulator.
88     */
89    private CADClientSocket theClientSocket;
90
91    /**
92     * Properties object for the CADClient class.
93     */
94    private Properties cadClientProp;
95    /**
96     * RMI interface for communication with the remote Coordinator.
97     */
98    private static CoordinatorInterface theCoorInt;
99    /**
100     * reference to itself to be used for disconnecting from CADSimulator
101     */
102    private CADClientInterface client = this;
103
104    /**
105     * Highways in traffic network
106     */
107    final private Highways highways;
108
109    /**
110     * LinkedList of batch events
111     */
112    private LinkedList<TrafficEvent> eventQueue;
113    /**
114     * Map of incidents to events
115     */
116    private Map<String, List<TrafficEvent>> incidents;
117
118    /**
119     * Instance of ConsoleTrafficDriver that contains the highway model
120     */
121    private ConsoleTrafficDriver console;
122
123    /**
124     * GUI for this driver
125     */
126    private ATMSBatchViewer theView;
127
128    /**
129     * Constructor. Initialize data from parsed properties file. Create a socket
130     * connection to the CADSimulator.
131     *
132     * @param propertiesFile File path (absolute or relative) to the properties
133     * file containing configuration data.
134     */
135    public ATMSBatchDriver(String propertiesFile) throws SimulationException,
136            RemoteException
137    {
138        if (!verifyProperties(propertiesFile))
139        {
140            System.exit(0);
141        }
142        // Initialize the highway model
143        incidents = new HashMap<String, List<TrafficEvent>>();
144        highways = new Highways(
145                "config/vds_data/highways_fullmap.txt",
146                //        "192.168.251.46", 8080);  //IP address of FEP Sim Linux VM
147                "localhost", 8080);
148
149        connect(cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name).trim(),
150                cadClientProp.getProperty(PROPERTIES.CAD_RMI_PORT.name).trim());
151
152        // READ THE BATCH FILE OF COMMANDS and put in a queue
153        readBatchFile();
154        // Launch the display
155        theView = new ATMSBatchViewer(this, new ArrayList<String>(incidents.keySet()));
156        theView.setVisible(true);
157        theView.update("0:00", "1:11", eventQueue);
158
159        // Create a timer that fetches the simulation time every second.
160        Timer timer = new Timer(ONE_SECOND, new ActionListener()
161        {
162            // Every second, see if an event should be launched
163            public void actionPerformed(ActionEvent e)
164            {
165                String currentClock = "";
166                String currentATMStime = "";
167                Date simClock = new Date();
168                // Obtain the simulation time from the CAD server
169                try
170                {
171                    long simtime = theCoorInt.getCurrentSimulationTime();
172                    currentClock = formatInterval(simtime);
173                    // For Debugging, show the ATMS time
174//                    long ATMStime = theCoorInt.getATMStime();       
175//                    Date atmsdate = new Date(ATMStime);
176//                    currentATMStime = formatter.format(atmsdate);
177                    try
178                    {
179                        simClock = formatter.parse(currentClock);
180                    }
181                    catch (ParseException ex)
182                    {
183                        Logger.getLogger(ATMSBatchDriver.class.getName()).log(Level.SEVERE, null, ex);
184                        System.out.println("Invalid simulation clock time found in ATMSDriverClient");
185                        System.exit(-1);
186                    }
187                    //System.out.println("Current clock: " + currentClock);
188                }
189                catch (RemoteException ex)
190                {
191                    System.out.println("Remote Exception reading sim or ATMS clock time");
192                    Logger.getLogger(ATMSBatchDriver.class.getName()).log(Level.SEVERE, null, ex);
193                }
194                // If we have any events left to process
195                if (!eventQueue.isEmpty())
196                {
197                    // Get the time to launch the next event
198                    TrafficEvent nextEvent = eventQueue.peek();
199                    Date eventTime = nextEvent.eventDate;
200                    //System.out.println("Next event will be launched at: " + formatter.format(eventTime));
201                    // Check the queue of events to see if the first
202                    // item should be launched.  IF so,
203                    // issue that command and remove it from queue.
204                    if (eventTime.before(simClock) || eventTime.equals(simClock))
205                    {
206                        System.out.println("LAUNCHING EVENT: " + nextEvent.toString());
207                        // apply colorization to highways
208                        highways.applyColorToHighwayStretch(nextEvent.routeNumber, nextEvent.dir,
209                                nextEvent.postmile, nextEvent.range, nextEvent.color);
210                        // Remove this event from the queue, we're done with it.
211                        eventQueue.remove();
212                    }
213
214                    theView.update(currentClock, currentATMStime, eventQueue);
215                }
216            }
217        });
218        timer.start();
219
220        // Start the FEP thread (to update ATMS every 30 sec). (See class def below)
221        Thread wtfep = new WriteToFEPThread();
222        wtfep.start();
223
224        ensureProperShutdown();
225    }
226
227    private void readBatchFile()
228    {
229        FileInputStream fis;
230        try
231        {
232            fis = new FileInputStream("config/vds_data/atmsBatchEvents.txt");
233            eventQueue = new LinkedList<TrafficEvent>();
234            // Read all lines from the file of events
235            Scanner scan = new Scanner(fis);
236            while (scan.hasNext())
237            {
238                // Read a line and add it to the event queue
239                String line = scan.nextLine().trim();
240                if (line.charAt(0) != '#')
241                {
242                    TrafficEvent evt;
243                    try
244                    {
245                        evt = new TrafficEvent(line);
246                        eventQueue.add(evt);
247                        String incident = evt.incident;
248                        // Add the line to the list for the corresponding incident
249                        List evtList;
250                        if (incidents.containsKey(evt.incident))
251                        {
252                            evtList = incidents.get(evt.incident);
253                        }
254                        else
255                        {
256                            evtList = new ArrayList<String>();
257                        }
258                        evtList.add(evt);
259                        // and put it back in the map
260                        incidents.put(incident, evtList);
261                    }
262                    catch (ParseException ex)
263                    {
264                        Logger.getLogger(ATMSBatchDriver.class.getName()).log(Level.SEVERE, null, ex);
265                        System.out.println("Wrong format data in batch event file: " + line + " \nskipping.");
266                        System.out.println("Skipping badly formatted event.");
267                    }
268                }
269            }
270        }
271        catch (FileNotFoundException ex)
272        {
273            Logger.getLogger(ATMSBatchDriver.class.getName()).log(Level.SEVERE, null, ex);
274        }
275        System.out.println("Events file read, " + eventQueue.size() + " events queued.");
276        // Put the events in chronological order
277        Collections.sort(eventQueue);
278    }
279
280    /**
281     * Clear an incident. For each event associated with an incident, turn the
282     * dots in its range Green and remove it from the event queue.
283     *
284     * @param incidentNumber incident to be cleared.
285     */
286    public void clearIncident(String incidentNumber)
287    {
288        boolean ok = incidents.containsKey(incidentNumber);
289        if (!ok)
290        {
291            System.out.println("Sorry, that incident number isn't found.");
292            return;
293        }
294        System.out.println("Clearing incident " + incidentNumber);
295        List<TrafficEvent> events = incidents.get(incidentNumber);
296        // Process each event associated with this incident
297        for (TrafficEvent event : events)
298        {
299            System.out.println("Event: " + event + " cleared.");
300            eventQueue.remove(event);
301
302            // apply colorization to highways, forcing to green, indicating cleared
303            highways.applyColorToHighwayStretch(event.routeNumber, event.dir,
304                    event.postmile, event.range, DOTCOLOR.GREEN);
305
306        }
307        // Now refresh the view with the updated queue of events
308        theView.update("0:00", "0:00", eventQueue);
309    }
310
311    /**
312     * Connect to the Coordinator's RMI object, and register this object for
313     * callback with the Coordinator.
314     *
315     * @param hostname Host name of the CAD Simulator.
316     * @param portNumber Port number of the CAD Simulator RMI communication.
317     * @throws SimulationException if there is an error creating the RMI
318     * connection.
319     */
320    protected void connect(String hostname, String portNumber)
321            throws SimulationException
322    {
323
324        String coorIntURL = "";
325
326        try
327        {
328            coorIntURL = "rmi://" + hostname + ":" + portNumber
329                    + "/coordinator";
330            theCoorInt = (CoordinatorInterface) Naming.lookup(coorIntURL);
331            theCoorInt.registerForCallback(this);
332        }
333        catch (Exception e)
334        {
335            throw new SimulationException(SimulationException.CAD_SIM_CONNECT,
336                    e);
337
338        }
339    }
340
341    /**
342     * This method verifies that the CAD Simulator Host and Port values are not
343     * null. Also, if a CAD Position or User ID do not exist in the properties
344     * file, the user is prompted to enter values. These values are written to
345     * the properties file. If the user cancels the process of entering these
346     * values, the verification fails.
347     *
348     * @param propertiesFile File path (absolute or relative) to the properties
349     * file containing configuration data.
350     * @return True if the properties file is valid, false if not.
351     * @throws SimulationException if there is an exception in verifying the
352     * properties file, or if the user cancels input.
353     */
354    private boolean verifyProperties(String propertiesFile)
355            throws SimulationException
356    {
357
358        // Load the properties file.
359        try
360        {
361            cadClientProp = new Properties();
362            cadClientProp.load(new FileInputStream(propertiesFile));
363        }
364        catch (Exception e)
365        {
366            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
367                    "Constructor", "Exception in reading properties file.", e);
368
369            throw new SimulationException(SimulationException.INITIALIZE_ERROR,
370                    e);
371        }
372
373        // Ensure that the properties file does not have null values for the
374        // CAD Simulator's connection information.
375        if (cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name) == null
376                || cadClientProp.getProperty(PROPERTIES.CAD_SIM_PORT.name) == null)
377        {
378            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
379                    "Constructor", "Null value in properties file.");
380            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
381        }
382
383        return true;
384    }
385
386    /**
387     * Format a time in seconds as HH:MM:SS
388     *
389     * @param l
390     * @return
391     */
392    private String formatInterval(final long l)
393    {
394        final long hr = TimeUnit.SECONDS.toHours(l);
395        final long min = TimeUnit.SECONDS.toMinutes(l - TimeUnit.HOURS.toSeconds(hr));
396        final long sec = TimeUnit.SECONDS.toSeconds(l - TimeUnit.HOURS.toSeconds(hr) - TimeUnit.MINUTES.toSeconds(min));
397        return String.format("%02d:%02d:%02d", hr, min, sec);
398    }
399
400    public void ensureProperShutdown()
401    {
402        Runtime.getRuntime().addShutdownHook(new Thread()
403        {
404            public void run()
405            {
406                try
407                {
408                    theCoorInt.unregisterForCallback(client);
409                }
410                catch (RemoteException e)
411                {
412                    e.printStackTrace();
413                }
414            }
415        });
416    }
417
418    /**
419     * Construct the CADClient with the properties file path, either from the
420     * command line arguments or default.
421     *
422     * @param args Command line arguments.
423     */
424    public static void main(String[] args)
425    {
426        if (System.getProperty("CONFIG_DIR") == null)
427        {
428            System.setProperty("CONFIG_DIR", "config");
429        }
430
431        try
432        {
433            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
434            new ATMSBatchDriver(System.getProperty("CONFIG_DIR") + System.getProperty("file.separator") + CONFIG_FILE_NAME);
435
436        }
437        catch (Exception e)
438        {
439            cadClientLogger.logp(Level.SEVERE, "SimulationManager", "Main",
440                    "Error initializing application.");
441
442            JOptionPane.showMessageDialog(new JWindow(), e.getMessage(),
443                    "Error - Program Exiting", JOptionPane.ERROR_MESSAGE);
444
445            System.exit(-1);
446        }
447
448    }
449
450    class WriteToFEPThread extends Thread
451    {
452
453        public void run()
454        {
455            System.out.println("WriteToFEP Thread starting.");
456            // Run indefinitely
457            while (true)
458            {
459                try
460                {
461                    // Write the highway network status to the FEP Simulator
462                    highways.writeToFEP();
463                }
464                catch (SimulationException ex)
465                {
466                    // Ask user if they want to proceed without FEP Sim connection
467                    int reply = JOptionPane.showConfirmDialog(null, "Failed to connect to FEP Sim, proceed anyway?", "Network Failure", JOptionPane.YES_NO_OPTION);
468                    if (reply == JOptionPane.NO_OPTION)
469                    {
470                        System.exit(0);
471                    }
472                    System.out.println("Skipping writeToFEP...");
473                }
474
475                // Wait for FEP Sim to process the data we just sent
476                try
477                {
478                    Thread.sleep(FEPSIM_INTERVAL);
479                }
480                catch (InterruptedException ie)
481                {
482                    ie.printStackTrace();
483                }
484            }
485
486        }
487    }
488}
Note: See TracBrowser for help on using the repository browser.