import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import java.util.LinkedList; import java.util.List; import java.util.Random; /** * Class for master process in simple master/worker example using RMI. * In this example, the master process generates a fixed number of (fake) tasks * with randomly-generated times and waits for workers to connect and process * them. */ public class RMIMaster implements RMIMasterInterface { /** * Constructs object with specified parameters. */ public RMIMaster(int tasks, int maxTaskTime) { // generate tasks and put on queue Random randGen = new Random(); for (int i = 0; i < tasks; ++i) { // generate integer in range 1 .. maxTaskTime taskQueue.add(new Task(randGen.nextInt(maxTaskTime-1)+1)); } } /** * Starts master process (i.e., makes it available as a remote object * for worker processes to use). */ public void start() throws RemoteException { // register self as ready for remote calls RMIMasterInterface stub = (RMIMasterInterface) UnicastRemoteObject.exportObject(this, 0); Registry registry = LocateRegistry.getRegistry(); registry.rebind(BINDING_NAME, stub); } /** * Waits until the queue is empty and all workers have reported * results. */ public void waitForComplete() { // wait for all tasks to be complete synchronized (taskQueue) { while (!taskQueue.isEmpty()) { try { taskQueue.wait(); } catch (InterruptedException e) { System.err.println("should not happen?: " + e); } } } // wait for all workers to report results synchronized (workers) { while (!workers.isEmpty()) { try { workers.wait(); } catch (InterruptedException e) { System.err.println("should not happen?: " + e); } } } } /** * Stops master process (i.e., unregisters remote object). */ public void stop() throws RemoteException { // unregister self UnicastRemoteObject.unexportObject(this, false); } /** * Gets task from queue (thread-safe). Notifies waiting process if * queue is empty. Makes sure requesting worker is included in list * of workers. */ public Task getTask(RMIWorkerInterface w) { addWorker(w); synchronized (taskQueue) { taskQueue.notifyAll(); if (taskQueue.isEmpty()) return null; else { Task t = taskQueue.remove(0); String workerHost = null; try { workerHost = w.hostName(); } catch (RemoteException e) { workerHost = "unknown host"; } System.out.println("Sending to worker at " + workerHost + ": task with time " + t.time); return t; } } } /** * Adds worker (thread-safe). Does nothing if worker is already in the * list of workers. */ public void addWorker(RMIWorkerInterface w) { synchronized (workers) { if (!workers.contains(w)) { try { System.out.println("New worker at " + w.hostName()); workers.add(w); } catch (RemoteException e) { System.err.println("Unable to register new worker"); workers.add(w); } } } } /** * Removes worker (thread-safe). Notifies waiting process if no workers. */ public void removeWorker(RMIWorkerInterface w) { synchronized (workers) { workers.remove(w); if (workers.isEmpty()) { workers.notifyAll(); } } } /** * Prints worker results. */ public void reportResults(RMIWorkerInterface w) { try { System.out.println("Worker at " + w.hostName() + " completed " + w.numTasks() + " tasks" + ", total time = " + w.totalTime()); removeWorker(w); } catch (RemoteException e) { System.out.println("Unable to report results for remote worker"); } } /** * Main program -- constructs an object and starts it up. * @param args command-line arguments -- total tasks, maximum task time */ public static void main(String[] args) { String usageMsg = "Arguments are totalTasks, maxTime"; if (args.length < 2) { System.err.println(usageMsg); System.exit(1); } try { int tasks = Integer.parseInt(args[0]); int maxtime = Integer.parseInt(args[1]); RMIMaster taskMaster = new RMIMaster(tasks, maxtime); taskMaster.start(); System.out.println("Master waiting for workers"); taskMaster.waitForComplete(); System.out.println("Master done"); taskMaster.stop(); } catch (NumberFormatException e) { System.err.println(usageMsg); } catch (RemoteException e) { System.err.println("Error in server: " + e); } } // ---- variables ---- private List taskQueue = new LinkedList(); private List workers = new LinkedList(); }