The implementation class associated with the MPJSlave interface normally behaves as follows (schematically):
public class MPJSlaveImpl extends UnicastRemoteObject { public static void main(String args []) { int slaveID = Integer.parseInt(args [0]) ; String masterPort = args [1] ; MPJService master = (MPJService) Naming.lookup("rmi://localhost:" + args [1] + "/MPJService") ; master.addSlave(int slaveID, int new MPJSlaveImpl()) ; } public runTask(MPJApplication task, String [] args, ...) throws RemoteException { ... create default communicator, `world' task.main(world, args) ; } }
The main method creates a remote object and ``registers'' it with its daemon by calling a remote method addSlave on the master. Later the client calls back with the runTask method, passing an instance of the actual user class. Because this is a serializable object it is passed by value to the remote runTask method. Importantly, the byte code for the user class will be loaded by RMIClassLoader from the code-base specified in the serialized object. As discussed below, this will be the URL of a process serving a (typically very much stripped-down) subset of the HTTP protocol.
Hence, using the dynamic class-loading mechanisms provided as standard in RMI, we ensure that all user code is automatically available to the remote host.