source: tmcsimulator/trunk/src/tmcsim/client/CADClient.java @ 453

Revision 453, 19.7 KB checked in by jdalbey, 7 years ago (diff)

CADClient.java: Output revision number to console when client starts.

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