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 @ 654

Revision 654, 15.6 KB checked in by jdalbey, 4 years ago (diff)

TrafficModelManager?.java changed timer from Swing timer to java.util.timer to avoid any potential thread locking issues.
CADServer.java moved call to traffic mgr run() until after setVisible ... fix obscure bug on laptop NetBeans.

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