source: tmcsimulator/trunk/src/tmcsim/cadsimulator/managers/TrafficModelManager.java @ 188

Revision 188, 15.5 KB checked in by jdalbey, 9 years ago (diff)

TrafficModelManager?.java: Now integrated into CAD Server. Passes smoke test, needs system testing.

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