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

Revision 61, 16.2 KB checked in by jdalbey, 9 years ago (diff)

CADClock development.

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