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.

Était-ce utile?

La solution

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

Autres conseils

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top