source: tmcsimulator/trunk/src/tmcsim/client/ATMSDriverClient.java @ 105

Revision 105, 10.3 KB checked in by jdalbey, 9 years ago (diff)

ATMSDriverClient.java Enhanced so it now syncs with Sim Mgr clock and reads a file of events and pretends to launch each event at the schedule time. Added batch event data file.

Line 
1package tmcsim.client;
2
3import java.awt.event.ActionEvent;
4import java.awt.event.ActionListener;
5import java.io.FileInputStream;
6import java.io.FileNotFoundException;
7import java.rmi.Naming;
8import java.rmi.RemoteException;
9import java.rmi.server.UnicastRemoteObject;
10import java.util.LinkedList;
11import java.util.Properties;
12import java.util.Queue;
13import java.util.Scanner;
14import java.util.concurrent.TimeUnit;
15import java.util.logging.Level;
16import java.util.logging.Logger;
17import javax.swing.JOptionPane;
18import javax.swing.JWindow;
19import javax.swing.Timer;
20import javax.swing.UIManager;
21import tmcsim.common.SimulationException;
22import tmcsim.interfaces.CADClientInterface;
23import tmcsim.interfaces.CoordinatorInterface;
24
25/**
26 * Skeleton for ATMS Driver that reads a "batch" file of highway
27 * status update commands.
28 * It operates as a client of the
29 * CAD server, using RMI to poll the server every second for the current
30 * simulation clock time.  It uses the simulation clock time
31 * to fire update commands at the desired time.
32 * Note: Sim Mgr must be running before starting this application.
33 *
34 * @author jdalbey
35 */
36public class ATMSDriverClient extends UnicastRemoteObject implements
37        CADClientInterface
38{
39    private static final String CONFIG_FILE_NAME = "cad_client_config.properties";
40    private final static int ONE_SECOND = 1000;
41    /**
42     * Error logger.
43     */
44    private static Logger cadClientLogger = Logger.getLogger("tmcsim.client");
45
46    @Override
47    public void refresh() throws RemoteException
48    {
49        throw new UnsupportedOperationException("Not supported yet.");
50    }
51
52    /**
53     * Enumeration containing properties name values. See CADClient class
54     * description for more information.
55     *
56     * @author Matthew Cechini
57     * @see CADClient
58     */
59    private static enum PROPERTIES
60    {
61        CAD_SIM_HOST("CADSimulatorHost"), CAD_SIM_PORT("CADSimulatorSocketPort"), CAD_RMI_PORT(
62        "CADRmiPort"), CLIENT_CAD_POS("CADPosition"), CLIENT_USER_ID(
63        "CADUserID"), KEYBOARD_TYPE("KeyboardType"), DISPLAY_TYPE(
64        "DisplayType");
65        public String name;
66
67        private PROPERTIES(String n)
68        {
69            name = n;
70        }
71    }
72    /**
73     * CADClientSocket Object to handle socket communication between the Client
74     * and CAD Simulator.
75     */
76    private CADClientSocket theClientSocket;
77
78    /**
79     * Properties object for the CADClient class.
80     */
81    private Properties cadClientProp;
82    /**
83     * RMI interface for communication with the remote Coordinator.
84     */
85    private static CoordinatorInterface theCoorInt;
86    /**
87     * reference to itself to be used for disconnecting from CADSimulator
88     */
89    private CADClientInterface client = this;
90   
91    /**
92     * Queue of batch events
93     */
94    private Queue<String> eventQueue;
95   
96
97    /**
98     * Constructor. Initialize data from parsed properties file. Create a socket
99     * connection to the CADSimulator.
100     *
101     * @param propertiesFile File path (absolute or relative) to the properties
102     * file containing configuration data.
103     */
104    public ATMSDriverClient(String propertiesFile) throws SimulationException,
105            RemoteException
106    {
107        if (!verifyProperties(propertiesFile))
108        {
109            System.exit(0);
110        }
111
112        connect(cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name).trim(),
113                cadClientProp.getProperty(PROPERTIES.CAD_RMI_PORT.name).trim());
114
115        // READ THE BATCH FILE OF COMMANDS and put in a queue
116        readBatchFile();
117        // Consider special cases:  1) time to fire first command
118        // has already past when application starts.
119        // 2.  Two commands have same fire time specified.
120        // 3.  How to "override" a command, to clear an incident.
121       
122        // Create a timer that fetches the simulation time every second.
123        Timer timer = new Timer(ONE_SECOND, new ActionListener()
124        {
125            public void actionPerformed(ActionEvent e)
126            {
127                String currentClock = "";
128                try
129                {
130                    long simtime = theCoorInt.getCurrentSimulationTime();
131                    currentClock = formatInterval(simtime);
132                    System.out.println("Current clock: " + currentClock);
133                } catch (RemoteException ex)
134                {
135                    Logger.getLogger(ATMSDriverClient.class.getName()).log(Level.SEVERE, null, ex);
136                }
137                if (!eventQueue.isEmpty())
138                {
139                    // Check the queue of commands to see if the first
140                    // item matches the current time.  IF so,
141                    // issue that command and remove it from queue.
142                    String nextEvent = eventQueue.peek();
143                    String eventTime = nextEvent.substring(0,8);
144                    System.out.println("Next event will be launched at: " + eventTime);
145                    if (eventTime.equals(currentClock))
146                    {
147                        System.out.println("LAUNCHING EVENT at " + nextEvent );
148                        eventQueue.remove();
149                    }
150                    //theView.updateTime("" + formatInterval(simtime));
151                }
152            }
153        });
154        timer.start();
155
156        ensureProperShutdown();
157    }
158
159    private void readBatchFile()
160    {
161        FileInputStream fis;
162        try {
163            fis = new FileInputStream("config/vds_data/atmsBatchEvents.txt");
164            Scanner scan = new Scanner(fis);
165            eventQueue = new LinkedList<String>();
166            while (scan.hasNext())
167            {
168                eventQueue.add(scan.nextLine());
169            }
170        } catch (FileNotFoundException ex) {
171            Logger.getLogger(ATMSDriverClient.class.getName()).log(Level.SEVERE, null, ex);
172        }
173    }
174   
175    /**
176     * Connect to the Coordinator's RMI object, and register this object for
177     * callback with the Coordinator.
178     *
179     * @param hostname Host name of the CAD Simulator.
180     * @param portNumber Port number of the CAD Simulator RMI communication.
181     * @throws SimulationException if there is an error creating the RMI
182     * connection.
183     */
184    protected void connect(String hostname, String portNumber)
185            throws SimulationException
186    {
187
188        String coorIntURL = "";
189
190        try
191        {
192            coorIntURL = "rmi://" + hostname + ":" + portNumber
193                    + "/coordinator";
194            theCoorInt = (CoordinatorInterface) Naming.lookup(coorIntURL);
195            theCoorInt.registerForCallback(this);
196        } catch (Exception e)
197        {
198            throw new SimulationException(SimulationException.CAD_SIM_CONNECT,
199                    e);
200        }
201    }
202
203    /**
204     * This method verifies that the CAD Simulator Host and Port values are not
205     * null. Also, if a CAD Position or User ID do not exist in the properties
206     * file, the user is prompted to enter values. These values are written to
207     * the properties file. If the user cancels the process of entering these
208     * values, the verification fails.
209     *
210     * @param propertiesFile File path (absolute or relative) to the properties
211     * file containing configuration data.
212     * @return True if the properties file is valid, false if not.
213     * @throws SimulationException if there is an exception in verifying the
214     * properties file, or if the user cancels input.
215     */
216    private boolean verifyProperties(String propertiesFile)
217            throws SimulationException
218    {
219
220        // Load the properties file.
221        try
222        {
223            cadClientProp = new Properties();
224            cadClientProp.load(new FileInputStream(propertiesFile));
225        } catch (Exception e)
226        {
227            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
228                    "Constructor", "Exception in reading properties file.", e);
229
230            throw new SimulationException(SimulationException.INITIALIZE_ERROR,
231                    e);
232        }
233
234
235        // Ensure that the properties file does not have null values for the
236        // CAD Simulator's connection information.
237        if (cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name) == null
238                || cadClientProp.getProperty(PROPERTIES.CAD_SIM_PORT.name) == null)
239        {
240            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
241                    "Constructor", "Null value in properties file.");
242            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
243        }
244
245        return true;
246    }
247
248    /**
249     * Format a time in seconds as HH:MM:SS
250     *
251     * @param l
252     * @return
253     */
254    private String formatInterval(final long l)
255    {
256        final long hr = TimeUnit.SECONDS.toHours(l);
257        final long min = TimeUnit.SECONDS.toMinutes(l - TimeUnit.HOURS.toSeconds(hr));
258        final long sec = TimeUnit.SECONDS.toSeconds(l - TimeUnit.HOURS.toSeconds(hr) - TimeUnit.MINUTES.toSeconds(min));
259        return String.format("%02d:%02d:%02d", hr, min, sec);
260    }
261
262    public void ensureProperShutdown()
263    {
264        Runtime.getRuntime().addShutdownHook(new Thread()
265        {
266            public void run()
267            {
268                try
269                {
270                    theCoorInt.unregisterForCallback(client);
271                } catch (RemoteException e)
272                {
273                    e.printStackTrace();
274                }
275            }
276        });
277    }
278
279    /**
280     * Construct the CADClient with the properties file path, either from the
281     * command line arguments or default.
282     *
283     * @param args Command line arguments.
284     */
285    public static void main(String[] args)
286    {
287        if (System.getProperty("CONFIG_DIR") == null)
288        {
289            System.setProperty("CONFIG_DIR", "config");
290        }
291
292        try
293        {
294            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
295            new ATMSDriverClient(System.getProperty("CONFIG_DIR") + System.getProperty("file.separator") + CONFIG_FILE_NAME);
296
297        } catch (Exception e)
298        {
299            cadClientLogger.logp(Level.SEVERE, "SimulationManager", "Main",
300                    "Error initializing application.");
301
302            JOptionPane.showMessageDialog(new JWindow(), e.getMessage(),
303                    "Error - Program Exiting", JOptionPane.ERROR_MESSAGE);
304
305            System.exit(-1);
306        }
307
308    }
309}
Note: See TracBrowser for help on using the repository browser.