diff --git a/src/clients/StudentClient.java b/src/clients/StudentClient.java index bbeb484..d8fee11 100644 --- a/src/clients/StudentClient.java +++ b/src/clients/StudentClient.java @@ -1,258 +1,258 @@ -package clients; - -import constants.Constants; -import discovery.computername.ComputerNameResolver; -import discovery.computername.InvalidComputerNameException; -import discovery.computername.OtagoComputerNameResolver; -import discovery.server.ServiceLocator; -import discovery.server.ServiceNotFoundException; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.logging.Level; -import java.util.logging.Logger; -import network.MessageGenerator; -import network.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 lab = nameResolver.getLabName(); - this.machineId = nameResolver.getMachineId(); - - - // find server IP (uses network multicast) - final String serverIp = new ServiceLocator().locateServer(lab); - - this.foundServer = true; - -// this.systemTrayIcon.displayMessage("Yay", "Server found: " +serverIp, TrayIcon.MessageType.INFO); - - this.requestSender = new RequestSender(serverIp); - - } 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() { - - public void actionPerformed(final ActionEvent e) { - helpRequest(); - } - }); - - final MenuItem requestMarking = new MenuItem("Request Marking"); - requestMarking.addActionListener(new ActionListener() { - - public void actionPerformed(final ActionEvent e) { - markingRequest(); - } - }); - - final MenuItem cancelHelp = new MenuItem("Cancel Help"); - cancelHelp.addActionListener(new ActionListener() { - - public void actionPerformed(final ActionEvent e) { - cancelHelp(); - } - }); - - final MenuItem cancelMarking = new MenuItem("Cancel Marking"); - cancelMarking.addActionListener(new ActionListener() { - - public void actionPerformed(final ActionEvent e) { - cancelMarking(); - } - }); - - final MenuItem cancelAll = new MenuItem("Cancel All Requests"); - cancelAll.addActionListener(new ActionListener() { - - public void actionPerformed(final ActionEvent e) { - cancelAll(); - } - }); - - final MenuItem exit = new MenuItem("Exit"); - exit.addActionListener(new ActionListener() { - - 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(generator.requestHelp(machineId)); - 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(generator.requestMarking(machineId)); - 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, "COMPUTERNAME"); - - new StudentClient(nameResolver); - } -} +package clients; + +import constants.Constants; +import discovery.computername.ComputerNameResolver; +import discovery.computername.InvalidComputerNameException; +import discovery.computername.OtagoComputerNameResolver; +import discovery.server.ServiceLocator; +import discovery.server.ServiceNotFoundException; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.logging.Level; +import java.util.logging.Logger; +import network.MessageGenerator; +import network.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 lab = nameResolver.getLabName(); + this.machineId = nameResolver.getMachineId(); + + + // find server IP (uses network multicast) + final String serverIp = new ServiceLocator().locateServer(lab); + + this.foundServer = true; + +// this.systemTrayIcon.displayMessage("Yay", "Server found: " +serverIp, TrayIcon.MessageType.INFO); + + this.requestSender = new RequestSender(serverIp); + + } 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() { + + public void actionPerformed(final ActionEvent e) { + helpRequest(); + } + }); + + final MenuItem requestMarking = new MenuItem("Request Marking"); + requestMarking.addActionListener(new ActionListener() { + + public void actionPerformed(final ActionEvent e) { + markingRequest(); + } + }); + + final MenuItem cancelHelp = new MenuItem("Cancel Help"); + cancelHelp.addActionListener(new ActionListener() { + + public void actionPerformed(final ActionEvent e) { + cancelHelp(); + } + }); + + final MenuItem cancelMarking = new MenuItem("Cancel Marking"); + cancelMarking.addActionListener(new ActionListener() { + + public void actionPerformed(final ActionEvent e) { + cancelMarking(); + } + }); + + final MenuItem cancelAll = new MenuItem("Cancel All Requests"); + cancelAll.addActionListener(new ActionListener() { + + public void actionPerformed(final ActionEvent e) { + cancelAll(); + } + }); + + final MenuItem exit = new MenuItem("Exit"); + exit.addActionListener(new ActionListener() { + + 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(generator.requestHelp(machineId)); + 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(generator.requestMarking(machineId)); + 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"); + + new StudentClient(nameResolver); + } +}