In this program there is a single remote server which performs miscellaneous work. Because there is only one server, it seems like a singleton pattern could fit well. 

The problem that a distributed program introduces is that every client will have its own version of a `static` variable. Therefore I have defined a basic `ComputeInterface` which is implemented by two classes. `ComputeServer` is the object which performs the work asked for by clients. `ComputeService` is a class which performs an RMI lookup to the `ComputeServer` and acts like singleton server in the client program.

The location information for the Server is maintained in a `Configuration` class:

    public class Configuration {
        public static final int COMPUTE_REMOTE_PORT = 8900;
        public static final String COMPUTE_REMOTE_ID = "COMPUTE_REMOTE_ID";
        public static final String COMPUTE_REMOTE_HOST = "localhost";
    }

A `ComputeTask` implements `Serializable` and is performed by the `ComputeInterface` which implements `Remote`. The `ComputeInterface` contains an `isConnected` method which is used for determining if there is connectivity to the server from the service:

    public interface ComputeTask extends Serializable{
        void doWork();
    }

    public interface ComputeInterface extends Remote {
        ComputeTask compute(ComputeTask task) throws RemoteException;
        boolean isConnected() throws RemoteException;
    }

This is the implementation for the server:

    final class ComputeServer extends UnicastRemoteObject implements ComputeInterface {
        public static void main(String[] args) throws RemoteException, AlreadyBoundException {
            ComputeServer computeServer = new ComputeServer();
            Registry registry = LocateRegistry.createRegistry(Configuration.COMPUTE_REMOTE_PORT);
            registry.bind(Configuration.COMPUTE_REMOTE_ID, computeServer);
            System.out.println("Compute Server Running");
        }

        private ComputeServer() throws RemoteException {
            super();
        }

        @Override
        public synchronized ComputeTask compute(ComputeTask task) throws RemoteException{
            task.doWork();
            return task;
        }

        @Override
        public synchronized boolean isConnected() throws RemoteException{
            return true;
        }
    }

And here is the `Service`. If the server has not yet been connected, the service will attempt to do a registry lookup on the server. If the registry lookup up was successful *(or has already been performed)*, it will check the server connectivity before performing any tasks.

    final public class ComputeService implements ComputeInterface{

        public static final ComputeInterface service = new ComputeService();
        private static ComputeInterface computeServer;

        private ComputeService(){}

        @Override
        public synchronized boolean isConnected() throws RemoteException{
            return ComputeService.connected();
        }

        private static boolean connected(){
            if (computeServer == null) {
                try{
                    Registry reg = LocateRegistry.getRegistry(Configuration.COMPUTE_REMOTE_HOST, Configuration.COMPUTE_REMOTE_PORT);
                    computeServer = (ComputeInterface) reg.lookup(Configuration.COMPUTE_REMOTE_ID);
                    System.out.println("New Connection to Compute Server");
                }
                catch (RemoteException | NotBoundException e){
                    System.err.print(e);
                    computeServer = null;
                    return false;
                }
            }
            try{
                return computeServer.isConnected();
            }
            catch (RemoteException e){
                System.err.print(e);
                computeServer = null;
            }
            return false;
        }

        @Override
        public synchronized ComputeTask compute(ComputeTask task) throws RemoteException{
            if(!ComputeService.connected()) return task;
            return computeServer.compute(task);
        }
    }

The use of this tool would then simply be:

    CustomComputeTask task = new CustomComputeTask();
    task = ComputeService.service.compute(task);