TIANLUN ZHU
TIANLUN ZHU

Reputation: 351

Issue when closing a RMI server

I face some trouble when closing the RMI Server remotely. In my program, a client needs to connect to a RMI middleware server, and the RMI middleware connects to 3 different RMI servers(flightManager, carManager, and roomManager). A client can submit a shutdown command to the middleware. Then the middleware should shutdown 3 servers and itself. But after I shutting down the carManager, the middleware immediately shut down and leave 2 other servers alive.

The middleware connects 3 managers and receives stubs by 3 managers, when it receive a shutdown call, it does the following function:

public void shutdown() throws RemoteException{
     try{
         this.carManager.shutdown();
         this.flightManager.shutdown();
         this.roomManager.shutdown();
         UnicastRemoteObject.unexportObject(this, true);

         System.out.println("Server exiting.");
        }
        catch(Exception e){}
     System.exit(0);
}

This is the code for 3 different managers, it extends ResourceManger and give the middleware a stub as a IResourceManager.

public class RMIResourceManager extends ResourceManager 
{
private static String s_serverName = "Server";
private static String s_rmiPrefix = "test";

public static void main(String args[])
{
    if (args.length > 0)
    {
        s_serverName = args[0];
    }

    // Create the RMI server entry
    try {
        // Create a new Server object
        RMIResourceManager server = new RMIResourceManager(s_serverName);

        // Dynamically generate the stub (client proxy)
        IResourceManager resourceManager = (IResourceManager)UnicastRemoteObject.exportObject(server, 0);

        // Bind the remote object's stub in the registry
        Registry l_registry;
        try {
            l_registry = LocateRegistry.createRegistry(1099);
        } catch (RemoteException e) {
            l_registry = LocateRegistry.getRegistry(1099);
        }
        final Registry registry = l_registry;
        registry.rebind(s_rmiPrefix + s_serverName, resourceManager);

        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                try {
                    registry.unbind(s_rmiPrefix + s_serverName);
                    System.out.println("'" + s_serverName + "' resource manager unbound");
                }
                catch(Exception e) {
                    System.err.println((char)27 + "[31;1mServer exception: " + (char)27 + "[0mUncaught exception");
                    e.printStackTrace();
                }
            }
        });                                       
        System.out.println("'" + s_serverName + "' resource manager server ready and bound to '" + s_rmiPrefix + s_serverName + "'");
    }
    catch (Exception e) {
        System.err.println((char)27 + "[31;1mServer exception: " + (char)27 + "[0mUncaught exception");
        e.printStackTrace();
        System.exit(1);
    }

    // Create and install a security manager
    if (System.getSecurityManager() == null)
    {
        System.setSecurityManager(new SecurityManager());
    }
}

public RMIResourceManager(String name)
{
    super(name);
}
}

And Finally there is a ResourceManager Class implements IResourceManager. There is a shutdown function in it.

public class ResourceManager implements IResourceManager{

        public void shutdown() throws RemoteException{
            System.exit(1);
    }
}

It seems any termination of manager will cause the termination of the middleware. The shutdown function in middleware excecute the line "this.carManager.shutdown();" and never excecute the lines above. How can I deal with this problem?

The pictures shows the problem: The client inputs "shutdown". Then the carManager shuts down and immediately the middleware shuts down. The flightManager and roomManager stay alive. enter image description here

Upvotes: 1

Views: 348

Answers (1)

moilejter
moilejter

Reputation: 998

I think your problem is that your implementation of shutdown() actually shuts down the server in the middle of the interaction with its client - so the client stub sees the connection go down, and so throws an exception (which you see on your screen capture) - which aborts that client before it gets to try to shut down the other two.

You would want to implement your servers so that, when shutdown() gets called, you unregister that server (so no more client connections are accepted), then start up a delayed thread to actually shut down the application - that way, the call that you are in will return normally to the client, who can then proceed.

Alternatively, I guess you could wrap each of the three calls to shutdown() in a try/catch, so you can ignore the exception that each client will throw and move on to tell the next server to shutdown...

Upvotes: 1

Related Questions