import java.io.*; import java.net.*; import java.applet.*; //========================================================================== // WorkerApplet (C) Oct 1996 Laurence Vanhelsuwe - All Rights Reserved // ------------ // This is the foundation (base) class for applets wishing to take part in // in the distributed processing scheme. You need to subclass this to obtain // a functional Applet. // // This applet provides two main methods: // // - requestJob() // - returnResults() // // Jobs and results are application-specific byte arrays (UDP packets). // The workerapplet hides all the communication details from the applet // and also does not care about how job and result packets are structured. // // You use this class simply by: // - implementing your computation in a run() method (i.e. from Runnable) // - calling requestJob() which produces a job spec // - parse the job spec message and execute your application-specific job // - return the results to the server via returnResults() // // HISTORY: // -------- // 27-OCT-1996: First version // // Author email: lva@telework.demon.co.uk //========================================================================== public abstract class WorkerApplet extends Applet implements Runnable, CommonConstants { // the main purpose of this applet foundation is to produce a // jobDetails message. The application should fetch it, via // requestJob(), parse it and act on it. protected byte[] jobDetails; // the message received from server protected String serverName = "localhost"; protected int serverPort = 8001; protected InetAddress localMachine; // this applet's host name protected int resultsPort; // UDP port to return results to protected PrintStream o = System.out; // convenient shorthand protected boolean verbose = false; //--------------------------------------------------------------------- // This is the standard applet init(). // Grab applet arguments and init other things.. //--------------------------------------------------------------------- public void init () { // get JOBMASTER, JOBMASTERPORT applet args extractHTMLParameters(); try { localMachine = InetAddress.getLocalHost(); if (verbose) o.println("Local machine: '" + localMachine.getHostName() + "'"); } catch (Exception whatNow) { o.println("Exception occurred: " + whatNow); } } //--------------------------------------------------------------------- // This is the standard applet start(). // Since subclasses of WorkerApplet HAVE to implement run() and behave // as separate threads, here we launch the application-specific applet. //--------------------------------------------------------------------- public void start () { new Thread(this).start(); } //--------------------------------------------------------------------- // requestJob() // ------------ // Contacts the Job Master (server) and request a job from it. // The job spec is returned to the calling applet. //--------------------------------------------------------------------- protected byte[] requestJob() { try { tellJobMasterWeAreReady( localMachine ); // contact server jobDetails = receiveOrdersFromJobMaster(); // fetch reply } catch (UnknownHostException whatNow) { o.println("RequestJob Exception occurred: " + whatNow); jobDetails = null; } catch (SocketException whatNow) { o.println("RequestJob Exception occurred: " + whatNow); jobDetails = null; } catch (IOException whatNow) { o.println("RequestJob Exception occurred: " + whatNow); jobDetails = null; } return jobDetails; } //--------------------------------------------------------------------- // returnResults() // --------------- // The application-specific applet has calculated something; now return // the results the Job Master, who will assemble results into a total // solution on the server. //--------------------------------------------------------------------- protected void returnResults(byte[] results) throws Exception { if (verbose) o.println("Returning results..."); UDPUtils.sendUDP(results, serverName, resultsPort); if (verbose) o.println("Results on their way.."); } //--------------------------------------------------------------------- // Send notification to Job Master that this applet can accept a new // job. The packet contains this applet's host address so that the // Job Master can respond to us. //--------------------------------------------------------------------- protected void tellJobMasterWeAreReady( InetAddress machine) throws UnknownHostException, SocketException, IOException { byte[] jobReqMsg = new byte[ JOB_REQ_PACKET_LENGTH ]; if (verbose) o.println("Telling Job Master we're ready.."); String machineName = machine.getHostName(); int addressLength = machineName.length(); if (addressLength > TXT_ADDR_FIELD_LENGTH) { o.println("Machine address too long!" + machine); System.exit(100); } // Create a UDP packet with the following structure: // "READY " // IP address (4 bytes) // textual host address (e.g. "dialup-06.eunet.be") int ptr = 0; jobReqMsg[ptr++] = 'R'; jobReqMsg[ptr++] = 'E'; jobReqMsg[ptr++] = 'A'; jobReqMsg[ptr++] = 'D'; jobReqMsg[ptr++] = 'Y'; jobReqMsg[ptr++] = ' '; // add the numeric IP address byte[] ipAddress = machine.getAddress(); jobReqMsg[ptr++] = ipAddress[0]; jobReqMsg[ptr++] = ipAddress[1]; jobReqMsg[ptr++] = ipAddress[2]; jobReqMsg[ptr++] = ipAddress[3]; machineName.getBytes(0, addressLength, jobReqMsg, ptr); ptr += addressLength; // pad host name field with spaces for (int i=0; i < TXT_ADDR_FIELD_LENGTH - addressLength; i++) { jobReqMsg[ptr++] = ' '; } if (verbose) o.println("Sending: '\n" + new String (jobReqMsg, 0) +"'"); UDPUtils.sendUDP(jobReqMsg, serverName, serverPort); } //--------------------------------------------------------------------- // Wait for a job specification message, issued by the Job Master. //--------------------------------------------------------------------- protected byte[] receiveOrdersFromJobMaster() throws SocketException, IOException { byte[] jobMessage = new byte[2+2]; if (verbose) o.println("Waiting to receive job spec.."); jobMessage = UDPUtils.receiveUDP(jobMessage.length, APPLET_JOB_ACK_UDP_PORT); resultsPort = (jobMessage[0] << 8) + jobMessage[1]; if (verbose) o.println("I'll have to send results to # : " + resultsPort); jobDetails = new byte[jobMessage.length - 2]; for (int i=0; i < jobMessage.length-2; i++) { jobDetails[i] = jobMessage[i+2]; } return jobDetails; } //--------------------------------------------------------------------- // Although applets can only contact their server directly, the server // to contact is an external parameter (embedded in HTML). // This can be handy for intranets where applets can be given extra // access rights. //--------------------------------------------------------------------- protected void extractHTMLParameters() { serverName = getParameter("JobMaster"); String port = getParameter("JobMasterPort"); if (serverName==null || port==null) { o.println("Applet parameter not present. Please contact webmaster."); } serverPort = Integer.parseInt(port); if (verbose) o.println("Parallel Job Server : " + serverName); if (verbose) o.println("Parallel Job Server UDP port: " + serverPort); } //--------------------------------------------------------------------- // All user-friendly applets taking parameters should include information // describing these parameters. // Subclasses overriding this method should MERGE their parameter info // with this method's. //--------------------------------------------------------------------- public String[][] getParameterInfo() { String paramInfo[][] = { {"JobMaster", "Host address", "The address of the parallel server"}, {"JobMasterPort", "integer", "The UDP port number to use on server"}, }; return paramInfo; } //--------------------------------------------------------------------- //--------------------------------------------------------------------- public String getAppletInfo() { return "WorkerApplet v1.0 " + COPYRIGHT; } } // End of Class WorkerApplet