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

Revision 57, 19.7 KB checked in by jdalbey, 9 years ago (diff)

Clock Client first draft

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