Computer Science Honours 2011

Distributed & Parallel Processing
Practical Three Solution

Use RMI to implement a simple message service.

The starting point for this, as for any RMI application, is to create an interface, specifying the "remote" methods that need to be provided.  In this case we need two methods: one to deposit a message for a specified user, and one to retrieve the messages for a user.

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;

/** This interface specifies the remote object
  * methods for the simple message service.
  */
public interface SimpleMessageService extends Remote
  {
    /** Deposit a message for the given user of the service.
      * Automatically creates "mailboxes" for new users.
      */
    public void depositMessage (String username, String message) throws RemoteException;
    
    /** Retrieve all the messages for the given user.
      * Returns null if the username is not known.
      */
    public List<String> retrieveMessages (String username) throws RemoteException;

  } // interface SimpleMessageService

The server that implements this is rather more complicated.  The central part of this is to decide how to store the messages.  I have used a HashMap with usernames as the keys and a list of messages (i.e. strings) as the associated values.  This allows simple, efficient retrieval of each user's "mailbox".

import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import java.util.*;

public class SimpleMessageServer implements SimpleMessageService
  { private HashMap<String, LinkedList<String>> messages = new HashMap<String, LinkedList<String>>();
  
    public void depositMessage (String username, String message) throws RemoteException
      { LinkedList<String> lst = null;
        if (messages.containsKey(username)) // Already have a mailbox
          { lst = messages.get(username);
            lst.add(message);
          }
        else // First entry
          { lst = new LinkedList<String>();
            lst.add(message); 
            messages.put(username, lst);
          }
      } // depositMessage
    
    public List<String> retrieveMessages (String username) throws RemoteException
      { return messages.get(username);
      } // retrieveMessages

    public static void main (String args[])
      { try
          { SimpleMessageServer server = new SimpleMessageServer();
      	    SimpleMessageService stub = (SimpleMessageService)UnicastRemoteObject.exportObject(server, 0);

      	    // Bind the remote object's stub in the registry
      	    Registry registry = LocateRegistry.getRegistry();
      	    registry.bind("SimpleMessageService", stub);

      	    System.err.println("SimpleMessageService Server ready");
          }
        catch (Exception e)
          { System.err.println("Server exception: " + e.toString());
	          e.printStackTrace();
          }

      } // main

  } // class SimpleMessageServer

I chose to write the client as two separate programs: one to deposit messages and one to retrieve messages.  They are both very simple, using command-line parameters for the data.  This is the program to deposit a message.

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.RemoteException;

public class StoreSimpleMessage
  { 
    public static void main (String args[])
      { try
          { Registry registry = LocateRegistry.getRegistry();
      	    SimpleMessageService server = (SimpleMessageService)registry.lookup("SimpleMessageService");
      	    server.depositMessage(args[0], args[1]); // Store message
      	  }
        catch (Exception e)
          { System.err.println("Client exception: " + e.toString());
      	    e.printStackTrace();
      	    System.exit(1);
      	  }
      } // main

  } // class StoreSimpleMessage

Lastly, the program to retrieve messages is also very simple.

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.RemoteException;

import java.util.List;

public class GetSimpleMessages
  { 
    public static void main (String args[])
      { List<String> lst = null;
        try
          { Registry registry = LocateRegistry.getRegistry();
      	    SimpleMessageService server = (SimpleMessageService)registry.lookup("SimpleMessageService");
      	    lst = server.retrieveMessages(args[0]); // Retrieve messages
      	  }
        catch (Exception e)
          { System.err.println("Client exception: " + e.toString());
      	    e.printStackTrace();
      	    System.exit(1);
      	  }
      	if (lst == null)
      	  System.out.println("No messages for " + args[0]);
      	else
      	  for (String msg : lst)
      	    System.out.println(msg);
      } // main

  } // class GetSimpleMessages


George Wells, G.Wells@ru.ac.za