package clients; import constants.Constants; import discovery.computername.ComputerNameResolver; import discovery.computername.InvalidComputerNameException; import discovery.computername.OtagoComputerNameResolver; import discovery.jms.ServiceLocator; import discovery.server.multicast.ServiceNotFoundException; import gui.Lab; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; import network.MessageGenerator; import network.MessageType; import network.jms.RequestSender; /* * The student's client for requesting help. * * It adds a system tray icon that has a pop-up menu that the student can use to * request help or cancel their request. Requests are automatically canceled * when the student clicks the "exit" menu item, or the client is terminated by * the OS (via a shutdown hook) meaning there should never be requests in the * queue for students who have gone home. * * This aims to be both simple and robust, therefor the StudentClient stores no * state relating to requests, uses no persistent connections to the server, and * receives no information from the server. * * The client uses a multi-cast broadcast to discover the IP of the server, * which it then uses to send requests to the server. * * The wire protocol is very simple. A string in the form "request 23" is a * request for from the machine with ID 23, and "cancel 23" will cancel that * request. Sending multiple "request" commands or multiple "cancel" commands to * the server should cause no duplication or problems on the server and are * effectively ignored. * * @author Mark */ public class StudentClient { private static final Logger LOG = Logger.getLogger(StudentClient.class.getName()); private final PopupMenu trayPopopMenu = new PopupMenu(); private final Image trayIconImage = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/icon.png")); private final TrayIcon systemTrayIcon = new TrayIcon(trayIconImage, "Demo Call " + Constants.VERSION, trayPopopMenu); private final MessageGenerator generator = new MessageGenerator(); private String machineId; private RequestSender requestSender; private boolean foundServer = false; private final Thread shutDownHook = new Thread() { @Override public void run() { cleanUp(); } }; public StudentClient(final ComputerNameResolver nameResolver) { try { createTrayMenu(); // not sure this is necessary but Windows is currently not exiting // when the shutdown hook kicks in... this.shutDownHook.setDaemon(true); Runtime.getRuntime().addShutdownHook(this.shutDownHook); try { nameResolver.resolve(); } catch (InvalidComputerNameException ex) { this.systemTrayIcon.displayMessage("Whoops", ex.getMessage(), TrayIcon.MessageType.ERROR); // give user a chance to read message Thread.sleep(5000); // shutdown exit(); } final String currentLab = nameResolver.getLabName(); this.machineId = nameResolver.getMachineId(); // find server IP (uses network multicast) final Collection<Lab> activeLabs = new ServiceLocator().getActiveLabs(); final Lab lab = (Lab) JOptionPane.showInputDialog(null, "Which lab?", "Which lab?", JOptionPane.QUESTION_MESSAGE, null, activeLabs.toArray(), currentLab); String labName=null; if (lab == null) { System.exit(0); } else { labName = lab.getLabName(); } this.foundServer = true; // this.systemTrayIcon.displayMessage("Yay", "Server found: " +serverIp, TrayIcon.MessageType.INFO); this.requestSender = new RequestSender(lab, machineId); } catch (ServiceNotFoundException ex) { this.systemTrayIcon.displayMessage("Whoops", "Could not connect to server. Please try again and let the supervisor know if it continues to happen.", TrayIcon.MessageType.ERROR); } catch (Exception ex) { LOG.log(Level.SEVERE, null, ex); } } private void createTrayMenu() { try { this.systemTrayIcon.setImageAutoSize(true); final MenuItem requestHelp = new MenuItem("Request Help"); requestHelp.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { helpRequest(); } }); final MenuItem requestMarking = new MenuItem("Request Marking"); requestMarking.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { markingRequest(); } }); final MenuItem cancelHelp = new MenuItem("Cancel Help"); cancelHelp.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { cancelHelp(); } }); final MenuItem cancelMarking = new MenuItem("Cancel Marking"); cancelMarking.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { cancelMarking(); } }); final MenuItem cancelAll = new MenuItem("Cancel All Requests"); cancelAll.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { cancelAll(); } }); final MenuItem exit = new MenuItem("Exit"); exit.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { exit(); } }); this.trayPopopMenu.add(requestHelp); this.trayPopopMenu.add(cancelHelp); this.trayPopopMenu.addSeparator(); this.trayPopopMenu.add(requestMarking); this.trayPopopMenu.add(cancelMarking); this.trayPopopMenu.addSeparator(); this.trayPopopMenu.add(cancelAll); this.trayPopopMenu.addSeparator(); this.trayPopopMenu.add(exit); SystemTray.getSystemTray().add(this.systemTrayIcon); } catch (Exception ex) { LOG.log(Level.SEVERE, null, ex); } } private void helpRequest() { try { requestSender.sendRequest(MessageType.HELP); systemTrayIcon.displayMessage("Help is on the way", "Your request is now in the queue.", TrayIcon.MessageType.INFO); } catch (Exception ex) { systemTrayIcon.displayMessage("Whoops", "Failed to make request", TrayIcon.MessageType.ERROR); LOG.log(Level.SEVERE, "Error making request", ex); } } private void markingRequest() { try { requestSender.sendRequest(MessageType.MARKING); systemTrayIcon.displayMessage("Help is on the way", "Your request is now in the queue.", TrayIcon.MessageType.INFO); } catch (Exception ex) { systemTrayIcon.displayMessage("Whoops", "Failed to make request", TrayIcon.MessageType.ERROR); LOG.log(Level.SEVERE, "Error making request", ex); } } private void cancelHelp() { // try { // requestSender.sendRequest(generator.cancelHelp(machineId)); // systemTrayIcon.displayMessage("Request removed", "Your request has been removed from the queue.", TrayIcon.MessageType.INFO); // } catch (Exception ex) { // systemTrayIcon.displayMessage("Whoops", "Failed to make request", TrayIcon.MessageType.ERROR); // LOG.log(Level.SEVERE, "Error making request", ex); // } } private void cancelMarking() { // try { // requestSender.sendRequest(generator.cancelMarking(machineId)); // systemTrayIcon.displayMessage("Request removed", "Your request has been removed from the queue.", TrayIcon.MessageType.INFO); // } catch (Exception ex) { // systemTrayIcon.displayMessage("Whoops", "Failed to cancel request", TrayIcon.MessageType.ERROR); // LOG.log(Level.SEVERE, "Error cancelling request", ex); // } } private void cancelAll() { // try { // requestSender.sendRequest(generator.cancelHelp(machineId)); // requestSender.sendRequest(generator.cancelMarking(machineId)); // systemTrayIcon.displayMessage("All requests removeds", "All of your request have been removed from the queues.", TrayIcon.MessageType.INFO); // } catch (Exception ex) { // systemTrayIcon.displayMessage("Whoops", "Failed to cancel request", TrayIcon.MessageType.ERROR); // LOG.log(Level.SEVERE, "Error cancelling request", ex); // } } private void exit() { this.cleanUp(); // force an exit since they are several threads lurking around that could keep the process running System.exit(0); } private void cleanUp() { // cancel any requests the student has made if (this.foundServer) { cancelAll(); } // remove the tray icon from the system tray SystemTray.getSystemTray().remove(systemTrayIcon); } @SuppressWarnings("ResultOfObjectAllocationIgnored") public static void main(final String[] args) { // System.out.println("Student Client"); // final String name = "SB318-15"; // final String name = "SB317-10"; // final String name = "SBEASTCAL1-30"; // final String name = "SB316-15"; final String name = args.length > 0 ? args[0] : null; final ComputerNameResolver nameResolver = new OtagoComputerNameResolver(name, "CLIENTNAME"); nameResolver.resolve(); System.out.println(nameResolver); new StudentClient(nameResolver); } }