Newer
Older
democall3 / src / clients / StudentClient.java
geoma48p on 20 Jul 2015 9 KB Started transition to JMS.
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.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<String> activeServers = new ServiceLocator().getActiveServers();

			final Lab lab = (Lab) JOptionPane.showInputDialog(null, "Which lab?", "Which lab?", JOptionPane.QUESTION_MESSAGE, null, activeServers.toArray(), currentLab);

			String labName="";
			
			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(labName, 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() {

				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");

		nameResolver.resolve();
		System.out.println(nameResolver);
		
		new StudentClient(nameResolver);
	}
}