How to organize RMI Client-Server architecture

You need two remote object classes.

The first one is obtained via Naming.lookup(); it is a singleton; and it contains a login() method.

This method returns the second remote object, which is not a singleton, not registered in the Registry, and is created anew for every return value. This object contains all the banking methods and also a logout() method, which unexports it; it probably also implements the Unreferenced interface so it can detect a dead client, and unexport itself. Because it exists once per client, it can hold client state, and because it can only be obtained by a successful login step it solves your security problem.

public interface Login extends Remote
{
    Session login(String username, char[] password /* or whatever */)
        throws LoginException, RemoteException;
}

public interface Session extends Remote
{
    void logout() throws RemoteException;
    void deposit(...) throws RemoteException;
    void withdraw(...) throws RemoteException;
}

public class LoginImpl extends UnicastRemoteObject implements Login
{
    public Session login(String username, char[] password)
        throws LoginException, RemoteException
    {
        // username/password check; if it fails throw a LoginException
        return new SessionImpl(username); // or whatever
    }
}

public class SessionImpl extends UnicastRemoteObject implements Session, Unreferenced
{
    public void logout() throws RemoteException
    {
        unexportObject(this, true);
    }

    public void unreferenced()
    {
        unexportObject(this, true); // needs to be in a try/catch block of course
    }

    // etc
}

I described this as the Remote Session pattern in my book in 2001.

Of course you also need transport layer security: see javax.rmi.ssl.

Leave a Comment