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

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

Revision 248, 17.7 KB checked in by jdalbey, 7 years ago (diff)

TrafficModelManager?: multi-file commit to enhance Traffic Mgr to output highway status to json file for viewing in Google Map.

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