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

Revision 206, 16.6 KB checked in by jdalbey, 9 years ago (diff)

TrafficModelManager?.java Refactor to use Observable, along with the view. Add Reload button functionality.

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