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

Revision 445, 15.2 KB checked in by jdalbey, 7 years ago (diff)

Changed restart dialog in CADClientView to a non-modal one to fix #159. Shortened exception log messages in other client modules.

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