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

Revision 228, 15.7 KB checked in by jdalbey, 8 years ago (diff)

System Tests updated to work with new integrated Traffic Mgr. All system tests now passing.

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