Using Java RMI |
At the heart of the compute engine is a protocol that allows jobs to be submitted to the compute engine, the compute engine to run those jobs, and the results of the job to be returned to the client. This protocol is expressed in interfaces supported by the compute engine and by the objects that are submitted to the compute engine, as shown in the following figure.Each of the interfaces contains a single method. The compute engine's interface,
Compute
, allows jobs to be submitted to the engine; the client interface,Task,
defines how the compute engine executes a submitted task.The
compute.Compute
interface defines the remotely accessible part--the compute engine itself. Here is the remote interface with its single method:package compute; import java.rmi.Remote; import java.rmi.RemoteException; public interface Compute extends Remote { Object executeTask(Task t) throws RemoteException; }By extending the interface
java.rmi.Remote
, this interface marks itself as one whose methods can be called from any virtual machine. Any object that implements this interface becomes a remote object.As a member of a remote interface, the
executeTask
method is a remote method. Therefore the method must be defined as being capable of throwing ajava.rmi.RemoteException
. This exception is thrown by the RMI system during a remote method call to indicate that either a communication failure or a protocol error has occurred. ARemoteException
is a checked exception, so any code making a call to a remote method needs to handle this exception by either catching it or declaring it in itsthrows
clause.The second interface needed for the compute engine defines the type
Task
. This type is used as the argument to theexecuteTask
method in theCompute
interface. Thecompute.Task
interface defines the interface between the compute engine and the work that it needs to do, providing the way to start the work.package compute; import java.io.Serializable; public interface Task extends Serializable { Object execute(); }The
Task
interface defines a single method,execute
, which returns anObject
, has no parameters, and throws no exceptions. Since the interface does not extendRemote
, the method in this interface doesn't need to listjava.rmi.RemoteException
in itsthrows
clause.The return value for the
Compute
'sexecuteTask
andTask
'sexecute
methods is declared to be of typeObject
. This means that any task that wants to return a value of one of the primitive types, such as anint
or afloat
, needs to create an instance of the equivalent wrapper class for that type, such as anInteger
or aFloat
, and return that object instead.Note that the
Task
interface extends thejava.io.Serializable
interface. RMI uses the object serialization mechanism to transport objects by value between Java virtual machines. ImplementingSerializable
marks the class as being capable of conversion into a self-describing byte stream that can be used to reconstruct an exact copy of the serialized object when the object is read back from the stream.Different kinds of tasks can be run by a
Compute
object as long as they are implementations of theTask
type. The classes that implement this interface can contain any data needed for the computation of the task and any other methods needed for the computation.Here is how RMI makes this simple compute engine possible. Since RMI can assume that the
Task
objects are written in the Java programming language, implementations of theTask
object that were previously unknown to the compute engine are downloaded by RMI into the compute engine's virtual machine as needed. This allows clients of the compute engine to define new kinds of tasks to be run on the server machine without needing the code to be explicitly installed on that machine. In addition, because theexecuteTask
method returns ajava.lang.Object
, any type of object can be passed as a return value in the remote call.The compute engine, implemented by the
ComputeEngine
class, implements theCompute
interface, allowing different tasks to be submitted to it by calls to itsexecuteTask
method. These tasks are run using the task's implementation of theexecute
method. The compute engine reports results to the caller through its return value: anObject
.
Using Java RMI |