Question

A RMI server which works fine without the stopServer functionality.

public class HelloServer extends UnicastRemoteObject implements HelloInterface
{
    private final static int PORT=1102;
    private final String serverName="server"; 
    private Timer timer;

    public HelloServer()  throws RemoteException 
    {
       timer = new Timer();  //At this line a new Thread will be created
       timer.schedule(new StopServerTask(), 5000);

    }

    @Override
    public String serverResponse(String request) throws RemoteException 
    {
    return "Hello"+request;
    }


    public static void main(String[] args)
    {

        try 
        {

            HelloServer skeleton=new HelloServer();
            System.out.println("Starting server");
            skeleton.startServer();
            System.out.println("Server started");


        } 
        catch (RemoteException ex) 
        {
            ex.printStackTrace();
        }


    }

    public void startServer()
    {
  try {

            HelloServer skeleton=new HelloServer();
            Registry reg=LocateRegistry.createRegistry(PORT);
            reg.rebind(serverName, skeleton);
            System.out.println("Server is ready");

        } catch (RemoteException ex) 
        {
            Logger.getLogger(HelloInterface.class.getName()).log(Level.SEVERE, null, ex);
        }    
    }

    public void stopServer()
    {
    System.out.println("Stopping server");
        try {

            Registry rmiRegistry = LocateRegistry.getRegistry(PORT);
            HelloInterface myService = (HelloInterface) rmiRegistry.lookup(serverName);

            rmiRegistry.unbind(serverName);

            UnicastRemoteObject.unexportObject(rmiRegistry, true);

        } catch (NoSuchObjectException e) 
        {
            e.printStackTrace();
        } catch (NotBoundException e) 
        {
            e.printStackTrace();
        } catch (RemoteException ex) {
            Logger.getLogger(HelloServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    class StopServerTask extends TimerTask
        {

        @Override
        public void run() 
        {
        stopServer();
        }

        }
}

Whenever stopServer() in invoked exception is thrown at

UnicastRemoteObject.unexportObject(rmiRegistry, true);

Here is the stack Trace

java.rmi.NoSuchObjectException: object not exported
    at sun.rmi.transport.ObjectTable.unexportObject(ObjectTable.java:153)
    at java.rmi.server.UnicastRemoteObject.unexportObject(UnicastRemoteObject.java:297)
    at rmi.HelloServer.stopServer(HelloServer.java:84)

Things are same even when I clean the service object by using

 UnicastRemoteObject.unexportObject(myService, true);

Could someone suggest a clean way to stop the server which also releases the port for reuse.

Was it helpful?

Solution

You need to store the result of LocateRegistry.createRegistry(), and unexport that. At present you're trying to unexport a stub.

OTHER TIPS

I implemented a shutdown-service in my rmi-server. If I want to shut it down, I call it with a password. Simple Example:

public interface ShutdownInterface extends Remote {
  public void shutdownService(String password) throws RemoteException;
}

The serverside implementation can look something like:

public class ShutdownService extends UnicastRemoteObject implements ShutdownInterface {

private static final long serialVersionUID = 1L;

private boolean doShutdown = false;

public ShutdownService() throws RemoteException {
    super();
}

@Override
public void shutdownService(String password) throws RemoteException {
    if ("abcde12345".equals(password)) {
        System.out.println("shutdown requested.");
        this.doShutdown = true;
    } else {
        System.out.println("wrong pwd for shutdown");
    }

}

public boolean isDoShutdown() {
    return this.doShutdown;
}

}

Now the server itself keeps a reference to this:

public class BackendServer {
public final static int RMI_PORT = 1974;
private Registry registry = null;
private ShutdownService shutdownService = null;

public BackendServer() throws RemoteException {
    registry = LocateRegistry.createRegistry(RMI_PORT);
    this.shutdownService = new ShutdownService();
}

public void initialize() throws AccessException, RemoteException, AlreadyBoundException {
    shutdownService = new ShutdownService();
    registry.bind("ShutdownService", shutdownService);
    registry.bind("MyDataService", new MyDataService());
}

public void stop() throws NoSuchObjectException {
    System.out.println("stopping rmi server.");
    UnicastRemoteObject.unexportObject(registry, true);
    System.exit(0);
}

public boolean shouldStop() {
    return this.shutdownService.isDoShutdown();
}

public static void main(String args[]) {
    try {
        BackendServer bs = new BackendServer();
        bs.initialize();
        System.out.println("Server ready.");

        while (!bs.shouldStop()) {
            Thread.sleep(1000);
        }
        bs.stop();
    } catch (Exception e) {
        System.err.println("Server exception: " + e.toString());
        e.printStackTrace();
    }
}

}

Of course, this can be realized in a more beautiful way, but this should give you an idea of how to easily implement a shutdown yourself. You can call it from the main client or from a small commandline-tool you code for your server.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top