Name: acR10002 Date: 09/30/2001
Once the user creates the RMI registry on a specific port there should be
an API to shutdown the registry and free the occupied system resources.
I've searched throw the RMI spec and didn't found explicit words how to do
it. Given the specification for UnicastRemoteObject.unexportObject() :
--------- javadoc for UnicastRemoteObject.unexportObject(), jdk1.4.0-b81 ----
Removes the remote object, obj, from the RMI runtime. If successful, the object
can no longer accept incoming RMI calls. If the force parameter is true, the
object is forcibly unexported even if there are pending calls to the remote
object or the remote object still has calls in progress.
------------------
and the fact that Registry extends Remote (i.e.is a remote object), one would
assume the registry could be removed using the call:
UnicastRemoteObject.unexportObject(registry, true). Though this call allows to
create another registry on the same port, it, however, doesn't close the socket
being used for the first registry though. This problem can be illustrated in a
following example:
------------------------ Test.java -----------------
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.net.*;
import java.io.IOException;
public class Test {
public static void main(String args[]) {
Registry reg = null;
System.out.println("Creating registry on port 2000...");
try {
reg = LocateRegistry.createRegistry(2000);
System.out.println("Registry created!");
} catch (Exception e) {
e.printStackTrace(System.out);
System.exit(1);
}
System.out.println("Removing the registry...");
try {
if (UnicastRemoteObject.unexportObject(reg, true)) {
System.out.println("Registry removed!");
} else {
System.out.println("Registry can not be removed.");
System.exit(1);
}
} catch (Exception e) {
e.printStackTrace(System.out);
System.exit(1);
}
System.out.println("Trying to reuse the port 2000...");
try {
new ServerSocket(2000);
System.out.println("Socket created, registry has been completely removed.");
} catch (IOException e) {
System.out.println("Got exception : " + e);
System.exit(1);
}
}
}
--------------------------------------------------
which produces the same output under jdk1.2.2, jdk1.3.1 and jdk1.4:
------------- example output ------------
--> /set/java/jdk1.4/solaris/bin/java Test
Creating registry on port 2000...
Registry created!
Removing the registry...
Registry removed!
Trying to reuse the port 2000...
Got exception : java.net.BindException: Address already in use
-----------------------------------------
So it looks like either a bug in the implementation or oversight in RMI
architecture/spec. If UnicastRemoteObject.unexportObject() is not the right thing to
do, then there should be an appropriate API to correctly shutdown the registry.
Please note also, even if one uses custom server socket factory for registry
creation, and, then, explicitly closes the socket on port 2000 using factory's
methods, like these:
---
RMIServerSocketFactory ssf = new MyRMIServerSocketFactory();
RMIClientSocketFactory csf = new MyRMIClientSocketFactory();
Registry reg = LocateRegistry.createRegistry(2000, csf, ssf);
UnicastRemoteObject.unexportObject(reg, true);
ssf.closeServerSocket();
---
then it doesn't help too - it has been detected that createRegistry()
call creates two server sockets, one on the specific port (2000 in our
example) and another one on the dynamic. The closeServerSocket() call
closes the socket on port 2000, but the socket on the dynamic port still
remains opened in either case.
======================================================================