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

Revision 204, 15.6 KB checked in by jdalbey, 9 years ago (diff)

TrafficModelManager?.java Refactor for code sharing with TrafficModelEventDriver?. Write unit test.

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