tags:

views:

249

answers:

3

Hi all,

I have implemented a RMI Server and now I wanted to test if the method to start and stop this server are correcly implemented, using a JUnit test.

Here is the (simplified) code of my RMI server:

public void startServer() {
    try {
        ...
        registry = LocateRegistry.createRegistry(serverPort);
        registry.rebind("foobar", myRemoteObject);
    } catch (Exception e) {
        e.printStackTrace();
    }  
}

public void stopServer() {
    try {
        registry.unbind("foobar");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Now, I want to make a JUnit test to check if the startServer() and stopServer() are correctly working.

Thus, I've implemented this simple JUnit test:

private boolean isRunning(int port) {
    boolean portTaken = false;
    ServerSocket socket = null;
    try {
        socket = new ServerSocket(port);
        // If we have succesfully created the ServerSocket, then it means that the port is available...
    } catch (IOException e) {
        portTaken = true;
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e2) {
            }
        }
    }
    return portTaken;
}

@Test
public void testStartAndStopServer() {
    MyRMIServer server = new MyRMIServer();
    assertNotNull(server);
    int port = server.getServerPort();
    assertTrue(port != -1);
    // Check if the current server is NOT running.
    assertFalse(isRunning(port));
    // Start the server and then check if it is running.
    server.startServer();
    assertTrue(isRunning(port));
    // Now stop the server...
    server.stopServer();
    assertFalse(isRunning(port));
}

My problem is that the last assert is not valid. If I print the stacktrace in the method isRunning(), I get the error java.net.BindException: Address already in use: JVM_Bind.

This means that the port is still used so I guess that my stopServer() is not correct. What did I get wrong?

Note that if I use the registry.list() method before and after calling my method stopServer(), I see:

BEFORE: foobar
AFTER: (nothing)


Edit:

I've also modified my stopServer() regarding a solution explained here:

public void stopServer() {
    try {
        registry.unbind("foobar");
        UnicastRemoteObject.unexportObject(myRemoteObject, true);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

but it doesn't solve my problem...

A: 

First, I would tend to avoid empty exception blocks, even in "can't happen" cases.

  try {
            socket.close();
  } catch (IOException e2) {
  }

just concenvably there's an exception there.

My (rather wild) guess, is that you might have a timing problem. Perhaps the network infrastructure takes a short time to notice that the socket is closed. Does sleeping for a second or two before the final assert fix it?

djna
1. Yes, in my complete code, no exception block is empty ;) It was just to simplify code here.2. I've tried to put a Thread.sleep(upTo5000ms) just after server.stopServer();, but it does not help :(
romaintaz
A: 

I think you need to unexport the registry. Try:

public void stopServer() {
    try {
        registry.unbind("foobar");
        UnicastRemoteObject.unexportObject(registry, true);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

However, one source claims you cannot free up the port until the JVM exits. I don't know if that's true or not (haven't tried it), but unexporting the registry is a step in the right direction.

Rob H
A: 

I had the same problem and ended up modifying my server code so that the start method would basically look like (notice the call to getRegistry and rebind after the catch which will get back the registry if it was already there):

public void startServer() {
    try {
        ...
        registry = LocateRegistry.createRegistry(serverPort);
    } catch (RemoteException e) {
    }
    LocateRegistry.getRegistry(port);
    registry.rebind("foobar", myRemoteObject);  
}
JRL