source: tmcsimulator/trunk/src/tmcsim/client/ClockClient.java @ 464

Revision 464, 8.3 KB checked in by jdalbey, 7 years ago (diff)

Repair refresh method in ClockClient? to fix #174.

Line 
1package tmcsim.client;
2
3import java.awt.event.ActionEvent;
4import java.awt.event.ActionListener;
5import java.io.FileInputStream;
6import java.rmi.Naming;
7import java.rmi.RemoteException;
8import java.rmi.server.UnicastRemoteObject;
9import java.util.Properties;
10import java.util.concurrent.TimeUnit;
11import java.util.logging.Level;
12import java.util.logging.Logger;
13import javax.swing.JOptionPane;
14import javax.swing.JWindow;
15import javax.swing.Timer;
16import javax.swing.UIManager;
17import tmcsim.common.SimulationException;
18import tmcsim.interfaces.CADClientInterface;
19import tmcsim.interfaces.CoordinatorInterface;
20
21/**
22 * ClockClient shows the simulation clock time. It operates as a client of the
23 * CAD server, using RMI to poll the server every second for the current
24 * simulation clock time.
25 *
26 * @author jdalbey
27 */
28public class ClockClient extends UnicastRemoteObject implements
29        CADClientInterface
30{
31    /**
32     * Error logger.
33     */
34    private static Logger cadClientLogger = Logger.getLogger("tmcsim.client");
35
36    @Override
37    public void refresh() throws RemoteException
38    {
39       // We have no responsibilities when Coordinator invokes this
40       // Fixes #174
41    }
42
43    /**
44     * Enumeration containing properties name values. See CADClient class
45     * description for more information.
46     *
47     * @author Matthew Cechini
48     * @see CADClient
49     */
50    private static enum PROPERTIES
51    {
52        CAD_SIM_HOST("CADSimulatorHost"), CAD_SIM_PORT("CADSimulatorSocketPort"), CAD_RMI_PORT(
53        "CADRmiPort"), CLIENT_CAD_POS("CADPosition"), CLIENT_USER_ID(
54        "CADUserID"), KEYBOARD_TYPE("KeyboardType"), DISPLAY_TYPE(
55        "DisplayType");
56        public String name;
57
58        private PROPERTIES(String n)
59        {
60            name = n;
61        }
62    }
63    /**
64     * CADClientSocket Object to handle socket communication between the Client
65     * and CAD Simulator.
66     */
67    private CADClientSocket theClientSocket;
68    /**
69     * Instance of the ClockView.
70     */
71    private ClockView theView;
72    /**
73     * Properties object for the CADClient class.
74     */
75    private Properties cadClientProp;
76    /**
77     * RMI interface for communication with the remote Coordinator.
78     */
79    private static CoordinatorInterface theCoorInt;
80    /**
81     * reference to itself to be used for disconnecting from CADSimulator
82     */
83    private CADClientInterface client = this;
84    private static final String CONFIG_FILE_NAME = "cad_client_config.properties";
85    private final static int ONE_SECOND = 1000;
86
87    /**
88     * Constructor. Initialize data from parsed properties file. Create a socket
89     * connection to the CADSimulator.
90     *
91     * @param propertiesFile File path (absolute or relative) to the properties
92     * file containing configuration data.
93     */
94    public ClockClient(String propertiesFile) throws SimulationException,
95            RemoteException
96    {
97        if (!verifyProperties(propertiesFile))
98        {
99            System.exit(0);
100        }
101
102        connect(cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name).trim(),
103                cadClientProp.getProperty(PROPERTIES.CAD_RMI_PORT.name).trim());
104
105        theView = new ClockView();
106        theView.setVisible(true);
107
108        // Create a timer that fetches the simulation time every second.
109        Timer timer = new Timer(ONE_SECOND, new ActionListener()
110        {
111            public void actionPerformed(ActionEvent e)
112            {
113                try
114                {
115                    long simtime = theCoorInt.getCurrentSimulationTime();
116                    theView.updateTime("" + formatInterval(simtime));
117                } catch (RemoteException ex)
118                {
119                    Logger.getLogger(ClockClient.class.getName()).log(Level.SEVERE, null, ex);
120                }
121            }
122        });
123        timer.start();
124
125        ensureProperShutdown();
126    }
127
128    /**
129     * Connect to the Coordinator's RMI object, and register this object for
130     * callback with the Coordinator.
131     *
132     * @param hostname Host name of the CAD Simulator.
133     * @param portNumber Port number of the CAD Simulator RMI communication.
134     * @throws SimulationException if there is an error creating the RMI
135     * connection.
136     */
137    protected void connect(String hostname, String portNumber)
138            throws SimulationException
139    {
140
141        String coorIntURL = "";
142
143        try
144        {
145            coorIntURL = "rmi://" + hostname + ":" + portNumber
146                    + "/coordinator";
147            theCoorInt = (CoordinatorInterface) Naming.lookup(coorIntURL);
148            theCoorInt.registerForCallback(this);
149        } catch (Exception e)
150        {
151            throw new SimulationException(SimulationException.CAD_SIM_CONNECT,
152                    e);
153        }
154    }
155
156    /**
157     * This method verifies that the CAD Simulator Host and Port values are not
158     * null. Also, if a CAD Position or User ID do not exist in the properties
159     * file, the user is prompted to enter values. These values are written to
160     * the properties file. If the user cancels the process of entering these
161     * values, the verification fails.
162     *
163     * @param propertiesFile File path (absolute or relative) to the properties
164     * file containing configuration data.
165     * @return True if the properties file is valid, false if not.
166     * @throws SimulationException if there is an exception in verifying the
167     * properties file, or if the user cancels input.
168     */
169    private boolean verifyProperties(String propertiesFile)
170            throws SimulationException
171    {
172
173        // Load the properties file.
174        try
175        {
176            cadClientProp = new Properties();
177            cadClientProp.load(new FileInputStream(propertiesFile));
178        } catch (Exception e)
179        {
180            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
181                    "Constructor", "Exception in reading properties file.", e);
182
183            throw new SimulationException(SimulationException.INITIALIZE_ERROR,
184                    e);
185        }
186
187
188        // Ensure that the properties file does not have null values for the
189        // CAD Simulator's connection information.
190        if (cadClientProp.getProperty(PROPERTIES.CAD_SIM_HOST.name) == null
191                || cadClientProp.getProperty(PROPERTIES.CAD_SIM_PORT.name) == null)
192        {
193            cadClientLogger.logp(Level.SEVERE, "SimulationManager",
194                    "Constructor", "Null value in properties file.");
195            throw new SimulationException(SimulationException.INITIALIZE_ERROR);
196        }
197
198        return true;
199    }
200
201    /**
202     * Format a time in seconds as HH:MM:SS
203     *
204     * @param l
205     * @return
206     */
207    private String formatInterval(final long l)
208    {
209        final long hr = TimeUnit.SECONDS.toHours(l);
210        final long min = TimeUnit.SECONDS.toMinutes(l - TimeUnit.HOURS.toSeconds(hr));
211        final long sec = TimeUnit.SECONDS.toSeconds(l - TimeUnit.HOURS.toSeconds(hr) - TimeUnit.MINUTES.toSeconds(min));
212        return String.format("%02d:%02d:%02d", hr, min, sec);
213    }
214
215    public void ensureProperShutdown()
216    {
217        Runtime.getRuntime().addShutdownHook(new Thread()
218        {
219            public void run()
220            {
221                try
222                {
223                    theCoorInt.unregisterForCallback(client);
224                } catch (RemoteException e)
225                {
226                    e.printStackTrace();
227                }
228            }
229        });
230    }
231
232    /**
233     * Construct the CADClient with the properties file path, either from the
234     * command line arguments or default.
235     *
236     * @param args Command line arguments.
237     */
238    public static void main(String[] args)
239    {
240        if (System.getProperty("CONFIG_DIR") == null)
241        {
242            System.setProperty("CONFIG_DIR", "config");
243        }
244
245        try
246        {
247            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
248            new ClockClient(System.getProperty("CONFIG_DIR") + System.getProperty("file.separator") + CONFIG_FILE_NAME);
249
250        } catch (Exception e)
251        {
252            cadClientLogger.logp(Level.SEVERE, "SimulationManager", "Main",
253                    "Error initializing application.");
254
255            JOptionPane.showMessageDialog(new JWindow(), e.getMessage(),
256                    "Error - Program Exiting", JOptionPane.ERROR_MESSAGE);
257
258            System.exit(-1);
259        }
260
261    }
262}
Note: See TracBrowser for help on using the repository browser.