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

source: tmcsimulator/trunk/src/tmcsim/client/CADClockDisplay.java @ 62

Revision 62, 14.5 KB checked in by jdalbey, 9 years ago (diff)

Clock Client version 1 done.

RevLine 
1package tmcsim.client;
2
3import java.awt.event.ActionEvent;
4import java.awt.event.ActionListener;
5import java.io.FileInputStream;
6import java.io.FileOutputStream;
7import java.io.IOException;
8import java.rmi.Naming;
9import java.rmi.RemoteException;
10import java.rmi.server.UnicastRemoteObject;
11import java.util.Properties;
12import java.util.Vector;
13import java.util.concurrent.TimeUnit;
14import java.util.logging.Level;
15import java.util.logging.Logger;
16import javax.swing.JOptionPane;
17import javax.swing.JWindow;
18import javax.swing.Timer;
19import javax.swing.UIManager;
20import tmcsim.client.cadclientgui.CADClientGUI;
21import tmcsim.common.SimulationException;
22import tmcsim.interfaces.CADClientInterface;
23import tmcsim.interfaces.CoordinatorInterface;
24
25/**
26 * CADClockDisplay shows the simulation clock time. It operates as a client of
27 * the CAD server, using RMI to poll the server every second for the current
28 * simulation clock time.
29 */
30public class CADClockDisplay extends UnicastRemoteObject implements
31        CADClientInterface
32{
33    /**
34     * Error logger.
35     */
36    private static Logger cadClientLogger = Logger.getLogger("tmcsim.client");
37
38    /**
39     * Enumeration containing properties name values. See CADClient class
40     * description for more information.
41     *
42     * @author Matthew Cechini
43     * @see CADClient
44     */
45    private static enum PROPERTIES
46    {
47        CAD_SIM_HOST("CADSimulatorHost"), CAD_SIM_PORT("CADSimulatorSocketPort"), CAD_RMI_PORT(
48        "CADRmiPort"), CLIENT_CAD_POS("CADPosition"), CLIENT_USER_ID(
49        "CADUserID"), KEYBOARD_TYPE("KeyboardType"), DISPLAY_TYPE(
50        "DisplayType");
51        public String name;
52
53        private PROPERTIES(String n)
54        {
55            name = n;
56        }
57    }
58    /**
59     * CADClientSocket Object to handle socket communication between the Client
60     * and CAD Simulator.
61     */
62    private CADClientSocket theClientSocket;
63    /**
64     * Instance of the CADClientModel.
65     */
66    private CADClientModel theClientScreenModel;
67    /**
68     * Instance of the CADClockView.
69     */
70    private CADClockView theClientScreenView;
71    /**
72     * Instance of the CADCLientGUI Replaces CADClockView
73     */
74    private CADClientGUI theClientGUI;
75    /**
76     * Properties object for the CADClient class.
77     */
78    private Properties cadClientProp;
79    /**
80     * RMI interface for communication with the remote Coordinator.
81     */
82    private static CoordinatorInterface theCoorInt;
83    /**
84     * reference to itself to be used for disconnecting from CADSimulator
85     */
86    private CADClientInterface client = this;
87    private static final String CONFIG_FILE_NAME = "cad_client_config.properties";
88    private final static int ONE_SECOND = 1000;
89
90    /**
91     * Constructor. Initialize data from parsed properties file. Create a socket
92     * connection to the CADSimulator.
93     *
94     * @param propertiesFile File path (absolute or relative) to the properties
95     * file containing configuration data.
96     */
97    public CADClockDisplay(String propertiesFile) throws SimulationException,
98            RemoteException
99    {
100        if (!verifyProperties(propertiesFile))
101        {
102            System.exit(0);
103        }
104
105        connect(cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name).trim(),
106                cadClientProp.getProperty(PROPERTIES.CAD_RMI_PORT.name).trim());
107
108        theClientScreenView = new CADClockView();
109        theClientScreenView.setVisible(true);
110
111        // Create a timer that fetches the simulation time every second.
112        Timer timer = new Timer(ONE_SECOND, new ActionListener()
113        {
114            public void actionPerformed(ActionEvent e)
115            {
116                try
117                {
118                    long simtime = theCoorInt.getCurrentSimulationTime();
119                    theClientScreenView.updateTime("" + formatInterval(simtime));
120                } catch (RemoteException ex)
121                {
122                    Logger.getLogger(CADClockDisplay.class.getName()).log(Level.SEVERE, null, ex);
123                }
124            }
125        });
126        timer.start();
127
128        ensureProperShutdown();
129    }
130
131    /**
132     * Connect to the Coordinator's RMI object, and register this object for
133     * callback with the Coordinator.
134     *
135     * @param hostname Host name of the CAD Simulator.
136     * @param portNumber Port number of the CAD Simulator RMI communication.
137     * @throws SimulationException if there is an error creating the RMI
138     * connection.
139     */
140    protected void connect(String hostname, String portNumber)
141            throws SimulationException
142    {
143
144        String coorIntURL = "";
145
146        try
147        {
148            coorIntURL = "rmi://" + hostname + ":" + portNumber
149                    + "/coordinator";
150            theCoorInt = (CoordinatorInterface) Naming.lookup(coorIntURL);
151            theCoorInt.registerForCallback(this);
152        } catch (Exception e)
153        {
154            throw new SimulationException(SimulationException.CAD_SIM_CONNECT,
155                    e);
156        }
157    }
158
159    /**
160     * This method verifies that the CAD Simulator Host and Port values are not
161     * null. Also, if a CAD Position or User ID do not exist in the properties
162     * file, the user is prompted to enter values. These values are written to
163     * the properties file. If the user cancels the process of entering these
164     * values, the verification fails.
165     *
166     * @param propertiesFile File path (absolute or relative) to the properties
167     * file containing configuration data.
168     * @return True if the properties file is valid, false if not.
169     * @throws SimulationException if there is an exception in verifying the
170     * properties file, or if the user cancels input.
171     */
172    private boolean verifyProperties(String propertiesFile)
173            throws SimulationException
174    {
175
176        // Load the properties file.
177        try
178        {
179            cadClientProp = new Properties();
180            cadClientProp.load(new FileInputStream(propertiesFile));
181        } catch (Exception e)
182        {
183            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
184                    "Constructor", "Exception in reading properties file.", e);
185
186            throw new SimulationException(SimulationException.INITIALIZE_ERROR,
187                    e);
188        }
189
190
191        // Ensure that the properties file does not have null values for the
192        // CAD Simulator's connection information.
193        if (cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name) == null
194                || cadClientProp.getProperty(PROPERTIES.CAD_SIM_PORT.name) == null)
195        {
196            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
197                    "Constructor", "Null value in properties file.");
198            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
199        }
200
201        try
202        {
203            // If the properties file does not specify a CAD position, prompt
204            // the
205            // user to select one. If the user selects a position, write the
206            // new properties values to the file. If the user cancels, else
207            // throw an exception.
208            if (cadClientProp.getProperty(PROPERTIES.CLIENT_CAD_POS.name) == null)
209            {
210                if (getCADPosition())
211                {
212                    cadClientProp.store(new FileOutputStream(propertiesFile),
213                            "");
214                }
215                else
216                {
217                    throw new SimulationException(
218                            SimulationException.INITIALIZE_ERROR);
219                }
220            }
221
222            // If the properties file does not specifiy a CAD User ID, prompt
223            // the
224            // user to enter a value. If the user enters a valid ID, write the
225            // new properties values to the file. If the user cancels, else
226            // throw an exception.
227            if (cadClientProp.getProperty(PROPERTIES.CLIENT_USER_ID.name) == null)
228            {
229                if (getUserID())
230                {
231                    cadClientProp.store(new FileOutputStream(propertiesFile),
232                            "");
233                }
234                else
235                {
236                    throw new SimulationException(
237                            SimulationException.INITIALIZE_ERROR);
238                }
239            }
240        } catch (IOException ioe)
241        {
242            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
243                    "Constructor",
244                    "Exception in writing to the properties file.");
245            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
246        }
247
248        // Ensure that the properties file has a valid display type
249        if (cadClientProp.getProperty(PROPERTIES.DISPLAY_TYPE.name) == null
250                || (!cadClientProp.getProperty(PROPERTIES.DISPLAY_TYPE.name)
251                .equals("FULL_SCREEN") && !cadClientProp.getProperty(
252                PROPERTIES.DISPLAY_TYPE.name).equals("FRAME")))
253        {
254            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
255                    "Constructor", "Invalid display type.");
256            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
257        }
258
259        return true;
260    }
261
262    /**
263     * This method prompts the user to select a value for the CAD position. If
264     * the user cancels the method returns false, else the Properties object is
265     * updated and true is returned.
266     *
267     * @return True if the user successfully selected a CAD position, false if
268     * not.
269     */
270    private boolean getCADPosition()
271    {
272
273        Vector<Integer> positions = new Vector<Integer>();
274        for (int i = 0; i < 10; i++)
275        {
276            positions.add(i);
277        }
278
279        Object cadPos = null;
280
281        while (true)
282        {
283            cadPos = JOptionPane.showInputDialog(null,
284                    "Please assign this workstation a CAD position number.",
285                    "CAD Position Asignment", JOptionPane.QUESTION_MESSAGE,
286                    null, positions.toArray(), positions.get(0));
287
288            // If the user pressed cancel, confirm the exit and return false.
289            if (cadPos == null)
290            {
291                if (JOptionPane
292                        .showConfirmDialog(
293                        null,
294                        "CAD Client cannot load until a valid CAD "
295                        + "position has been selected.  Do you wish to "
296                        + "cancel loading the CAD Client?",
297                        "Confirm Exit", JOptionPane.YES_NO_OPTION,
298                        JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION)
299                {
300                    return false;
301                }
302            } // Else the user selected a CAD position, exit the loop.
303            else
304            {
305                break;
306            }
307        }
308
309        cadClientProp.setProperty(PROPERTIES.CLIENT_CAD_POS.name,
310                cadPos.toString());
311        return true;
312    }
313
314    /**
315     * This method prompts the user to enter a 5-character User ID. If the user
316     * cancels the method returns false, else the Properties object is updated
317     * and true is returned.
318     *
319     * @return True if the user successfully selected a CAD position, false if
320     * not.
321     */
322    private boolean getUserID()
323    {
324        String cadUID = null;
325
326        while (true)
327        {
328            cadUID = JOptionPane.showInputDialog(null,
329                    "Please assign this workstation a 6-character CAD "
330                    + "User ID.", "CAD User ID Asignment",
331                    JOptionPane.QUESTION_MESSAGE);
332
333            // /If the user pressed cancel, confirm the exit and return false.
334            if (cadUID == null)
335            {
336                if (JOptionPane.showConfirmDialog(null,
337                        "CAD Client cannot load until a valid User ID "
338                        + "has been entered.  Do you wish to "
339                        + "cancel loading the CAD Client?",
340                        "Confirm Exit", JOptionPane.YES_NO_OPTION,
341                        JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION)
342                {
343                    return false;
344                }
345            } // If the user does not enter a valid User ID, notify and reprompt.
346            else if (cadUID.length() != 6)
347            {
348                JOptionPane.showMessageDialog(null,
349                        "The User ID must be 6 characters.", "Invalid User ID",
350                        JOptionPane.WARNING_MESSAGE);
351            } // Else the user entered a valid value, exit the loop.
352            else
353            {
354                break;
355            }
356        }
357
358        cadClientProp.setProperty(PROPERTIES.CLIENT_USER_ID.name, cadUID);
359        return true;
360    }
361
362    /**
363     * Construct the CADClient with the properties file path, either from the
364     * command line arguments or default.
365     *
366     * @param args Command line arguments.
367     */
368    public static void main(String[] args)
369    {
370        if (System.getProperty("CONFIG_DIR") == null)
371        {
372            System.setProperty("CONFIG_DIR", "config");
373        }
374
375        try
376        {
377            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
378            new CADClockDisplay(System.getProperty("CONFIG_DIR") + System.getProperty("file.separator") + CONFIG_FILE_NAME);
379
380        } catch (Exception e)
381        {
382            cadClientLogger.logp(Level.SEVERE, "SimulationManager", "Main",
383                    "Error initializing application.");
384
385            JOptionPane.showMessageDialog(new JWindow(), e.getMessage(),
386                    "Error - Program Exiting", JOptionPane.ERROR_MESSAGE);
387
388            System.exit(-1);
389        }
390
391    }
392
393    public void refresh()
394    {
395        theClientGUI.screen.refreshScreens();
396    }
397
398    public void ensureProperShutdown()
399    {
400        Runtime.getRuntime().addShutdownHook(new Thread()
401        {
402            public void run()
403            {
404                try
405                {
406                    theCoorInt.unregisterForCallback(client);
407                } catch (RemoteException e)
408                {
409                    e.printStackTrace();
410                }
411            }
412        });
413    }
414
415    /**
416     * Format a time in seconds as HH:MM:SS
417     *
418     * @param l
419     * @return
420     */
421    private String formatInterval(final long l)
422    {
423        final long hr = TimeUnit.SECONDS.toHours(l);
424        final long min = TimeUnit.SECONDS.toMinutes(l - TimeUnit.HOURS.toSeconds(hr));
425        final long sec = TimeUnit.SECONDS.toSeconds(l - TimeUnit.HOURS.toSeconds(hr) - TimeUnit.MINUTES.toSeconds(min));
426        return String.format("%02d:%02d:%02d", hr, min, sec);
427    }
428}
Note: See TracBrowser for help on using the repository browser.