JDK-4508962 : Unable to remove RMI registry once it was created
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.rmi
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: solaris_2.6
  • CPU: sparc
  • Submitted: 2001-09-30
  • Updated: 2001-10-03
  • Resolved: 2001-10-03
Related Reports
Duplicate :  
Description

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.

======================================================================

Comments
EVALUATION This report is effectively a duplicate of 4457683. It is a known limitation of the current RMI implementation that it never closes server (passive/listening) TCP port bindings for the lifetime of a virtual machine. One might reasonably argue that it should release any such binding once the number of remote objects (including perhaps a registry) exported (via JRMP) on a given port has transitioned to zero. This is something that we would like to fix, but it has not been a high priority because it has not been reported as much of a practical problem by customers. Regarding the workaround described at the end of the Description of this report, about using a custom server socket factory implementation to manually close unused server listening ports, it is not true that LocateRegistry.createRegistry creates two server sockets-- presumably it is some other (anonumous port) remote object export that is causing the other server socket creation observed. The same socket factory hack could certainly be used to close that server socket too, although it's not really related to registry isolation. Note that these workarounds would cause failures if remote objects (including a registry) were later exported on the same port unless the socket factory is also smart enough to re-bind the underlying ports again, because the RMI runtime implementation will think that it still has the ports reserved for itself. ###@###.### 2001-10-03
03-10-2001