Further Technical Specifications
for the project on Design and Implementation of Basic RMI
Mechanisms
I hope the following specifications and suggestions can guide
you in this coursework so that you can avoid possible traps and
can focus on essential technical points without spending too much
time. Please read this document carefully.
The precise method to test your RMI programs is now given (though
you do not have to obey it as far as you can demonstrate
essentially the same thing). The default registry,
with interfaces and testing programs can be used. See Section 3
below (direct links are here for
testing and here for the registry).
1. What You Need to Do
- You have to write the code for the communication module (CM)
for each VM (look at Figure 5.6 in CDK3). The CM is just
a module which receives an invocation from a proxy and
sends it to a skeleton in another VM
How does a client-side CM know where the remote object
resides? And how does the server-side CM know which
skeleton to invoke? That is what the remote object
reference gives us (see 3.2 (1) below). The remote object
table relates remote object references to actual (local)
objects. A layout for remote object references is defined
in CDK3 Figure 4.10 but they can have a different shape
if you wish. Manipulation of remote object references is
best given as a separate class. The CM itself can be
divided into a few classes. It's your choice.
- Next, you need to consider how the arguments of an
invocation are made into a stream (if you use a TCP
socket you can just send a stream). You can do it in one
of two ways.
- You can use an algorithm which is explained in
CDK3 Section 4.3.2. You make a stream out of it
and send it via a TCP socket.
- You can use Java serialisation and send it via a
socket simply. But if you use the second
approach, you cannot use Java serialisation
blindly for marshalling each and every object.
Local references to objects that implement remote
interfaces (i.e., remote objects) have to be
replaced by their remote object references before
being serialized during marshalling. Similarly,
during unmarshalling, a remote reference has to
be mapped to a local proxy.
- What else do you have to write? NOTHING! Except the
skeletons and proxies for the test programs, which you
can easily make once the interfaces of (1) and (2) above
are determined. When you have done that you will
understand how RMI works.
So this is not as complex as you first thought: the whole code
should be quite unexpectedly short. Difficulties however lie in
the following: so far you have mostly been writing application
programs rather than this kind of program, which requires what is
often called system programming. That is, you are going to
realise fundamental functionalities used for other application
programs. A different kind of mind set is necessary to think in
that way.
In the rest of this decument, I offer some technical
specifications which should help in your decision making.
2. Technical Specification
- In Java RMI, a remote interface subclasses Remote:
in your case you will subclass MyRemote (choose
any name you like); which specifies no public methods nor
instances.
- The proxy class should implement the corresponding remote
interface. NOTE: this is the design which conforms to the
default construction in Section 3 below. If you have an
alternative idea for design/implementation, then you may
use it.
- You do not have to consider exceptions
due to distribution (RemoteException in the
standard Java RMI). Also you do not need
to concern yourself with garbage collection.
- You do not have to consider dynamic class
loading between a client and a server: we assume the same
class definitions are available in two sites.
- For marshalling and unmarshalling, you may use Java
serialisation in some form, as noted above (but note you
can not use it as it is, since remote
objects have to be treated differently).
- For simplicity, we restrict datatypes and classes which
your RMI deal with as follows
- Primitive datatypes: int and character strings.
- Classes: those which directly subclass Object,
as well as remote objects themselves.
We
assume (b) can only use primitive data of form (a).
[note: if you use serialisation appropriately,
you can essentially get rid of this restriction:
however I do not require this].
- Although you will hand-compile a proxy and a skeleton for
each remote interface, it is required that you separate
their basic functionalities as separate classes, so that
the hand-compiled stub/skeleton are as simple as possible.
This is already described in Section 1 above but to
summarise briefly:
- The Communication Module (CM), is responsible for
sending out marshalled data to the appropriate
destination. The CM is called by a proxy, while
it calls (on the server-side) a skeleton.
- Marshalling and unmarshalling.
- (Manipulation of) a remote object table.
- The CM above must implement at-most-once semantics
3. Test Programs, Registry, Default Constructions and How
Testing is Done
3.1 Test programs
Here you can find the code for
a remote server and a client , which are to be used for testing
your program.
3.2 Default Constructions
The following are default constructions. The subsequent
suggestions etc. are based on these the default constructions.
Maybe it will make your life easier to use these constructions.
On the other hand, if you consider it is better, you may refine/change
these constructions.
- Remote Object References (ROR)
As a default, we assume
that the registry etc. returns an instance of the
following class, which offers a default representation of
remote object reference, RemoteObjectRef.java
In the code, there is a "localise" method,
which you will implement according to your design.
The method is used as follows:
aRemoteInterface x= (ARemoteInterface) r.localise();
where r is an instance of RemoteObjectRef
above, x is an instance of the proxy class and ARemoteInterface
is the class of the remote interface. As noted in Section
2 above, this works because the proxy class should
implement the remote interface
- Comment
- As noted, localise should create a new
proxy object. This is actually *not* necessary
since for each remote object we have one proxy
class, whose sole instance, if created initially,
can act as the intermediary. In this case there
should be a static method which returns this
unique object. You can choose either design, or
other ones.
- You can place localise inside the SimpleRegistry
code. In that case, the client program and the
server program look exactly as in the usual Java
RMI code (except it uses myRemote instead
of Remote and it may not have remote
exceptions).
- You may need to turn a class name (given by a
string) into a class: for this and other
operations, you can use methods for Class,
as listed in Section 4 below.
- The code for the Registry
Here
is a specification and a code for SimpleRegistry
and LocateSimpleResistry, as well as a registry
server. The test programs give sample code which uses
these classes. Note that the registry program shows a way
of using TCP, via the Java socket interface.
3.3 How Testing is Done
- This is described here.
Please read this part carefully.
4. Further Technical Pointers
- For the Java API for TCP, read CDK3 Section 4.2.4, and
also see java.net.Socket and java.net.ServerSocket
in the Java API documentation.
- For checking whether some class (actually an interface)
is remote or not, you would find the following two
methods useful: these are in class Object and in
class Class, and form part of reflective
operations in Java.
- For any object o, Class o.getClass()
returns the runtime class of an object.
- For any class/interface c, Class c.getSuperclass()
returns the Class representing its
superclass.
Also the following methods may be useful:
- For an appropriate className, Class
forName(String className) returns the Class
object associated with the class or interface
with the given string name.
- For a class c, Object c.newInstance()
returns a new instance of the class c, as
if its default constructor (with no argument) is
called.
For other pertinent operations, see the sections for Java.lang.object,
java.lang.class and java.lang.reflect of
the Java API specification.
- For serialization, look at the interface Serializable
in the above mentioned API specification.