1. Here's the server code (when we get started).
class Server implements ServerExports {
  int index = -1;

  public int register(ClientExports client) {
    clients[++index] = client;
    return index;
  }


  ClientExports clients[] = new ClientExports[100];

  public void broadcast(Update event) {

  }

}

public interface ServerExports {
  public int register(ClientExports client);
  public void broadcast(Update event);
}
2. This describes the kind of updates that will be sent:
class Update {

}
3. We can start describing the clients now:
class Client extends Thread {
  public void update(Update event) {

  }
  public void run() {

  }
}

public interface ClientExports {
  public void update(Update event);
}
4. Can we put all these together already?
public class Simulation {
  public static void main(String[] args) { 
    // on the server's host (server starts first)
    Server server = new Server();
    // on any of the clients' hosts
    Client adrian = new Client("Adrian");
    Client raja = new Client("Raja");
    Client dijkstra = new Client("Edsger");

    adrian.start();
    raja.start();
    dijkstra.start();
  }
}
5. Can't we make the clients look a bit more realistic?
class Client extends Thread implements ClientExports {
  String name;

  public Client(String name) {
    this.name = name; 
  }

  public void update(Update event) {}

  public void run() {
    while (true) {
      try {
        sleep((int)(Math.random() * 6000 + 1000)); 
      } catch (Exception e) { 

      }
      System.out.println(this.name + " here...");
    }
  }
}
6. So how does the program run now?
class Simulation {
  public static void main(String[] args) { 
    // on the server's host
    Server server = new Server();

    // on any of the clients' hosts
    ServerExports far = server;

    Client adrian = new Client("Adrian");
    adrian.id = far.register(adrian);
    adrian.server = far;
    adrian.start();

    Client raja = new Client("Raja");
    raja.id = far.register(raja);
    raja.server = far;
    raja.start();

    Client dijkstra = new Client("Edsger");
    dijkstra.id = far.register(dijkstra);
    dijkstra.server = far;
    dijkstra.start();

  }
}
7. Most classes have changed:
class Update {
  String message;

  Update(String message) {
    this.message = message; 
  }

  public String toString() {
    return message; 
  }
}
class Client extends Thread implements ClientExports {
  String name;
  int id;

  ServerExports server;

  public Client(String name) {
    this.name = name;
  }

  public void update(Update event) {
    System.out.println(this.name +
                       " receives: ***(" + event + ")*** ");
  }

  public void run() {
    while (true) {
      try {
        sleep((int)(Math.random() * 6000 + 10000)); 
      } catch (Exception e) {

      }

      server.broadcast(new Update(this.name + " says: Howdy!"));

    }
  }
}
class Server implements ServerExports {

  ClientExports clients[] = new ClientExports[100];
  int index = -1;

  synchronized public int register(ClientExports client) {
    clients[++index] = client;
    return index;
  }

  synchronized public void broadcast(Update event) {
    for (int i = 0; i <= index; i++)
    clients[i].update(event);
  }
}
8. One should try/run the program now.

9. Well, we're done.

10. We can now switch to a networked version.

11. Here's the client:

import java.rmi.*;
import java.rmi.server.*;

public class Client extends Thread implements ClientExports {
  String name;
  int id;

  ServerExports server;

  public Client(String name) {
    this.name = name; 
  }

  public void update(Update event) throws RemoteException {
    System.out.println(this.name + " receives: ***(" + event + ")*** ");
  }

  public void run() {
    while (true) {
      try {
        sleep((int)(Math.random() * 6000 + 10000));
        server.broadcast(
          new Update(this.name + " says: Howdy!"));
      } catch (Exception e) { }
    }
  }

  public static void main(String[] args) {

  }
}
12. Here's the client interface now:
import java.rmi.*;

public interface ClientExports extends Remote {
  public void update(Update event) throws RemoteException;
}
13. Here's the server code:
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;

public class Server extends UnicastRemoteObject
                    implements ServerExports {

  ClientExports clients[] = new ClientExports[100];
  int index = -1;

  synchronized public int register(ClientExports client) 
                               throws RemoteException {

    clients[++index] = client;
    return index;
  }

  synchronized public void broadcast(Update event) 
                         throws RemoteException {
    for (int i = 0; i <= index; i++)
    clients[i].update(event);
  }

  public Server() throws RemoteException {
    System.out.println("Server being initialized... ");
  }

  public static void main(String[] args) {

  }
}
14. Here's the current server interface:
import java.rmi.*;

public interface ServerExports extends Remote {
  public int register(ClientExports client) throws RemoteException;
  public void broadcast(Update event) throws RemoteException;
} 
15. Careful with compilation now:
frilled.cs.indiana.edu%ls -ld *.java
-rw---- 1 dgerman faculty 775 Nov 14 21:55 Client.java
-rw---- 1 dgerman faculty 132 Nov 14 21:50 ClientExports.java
-rw---- 1 dgerman faculty 635 Nov 14 21:53 Server.java
-rw---- 1 dgerman faculty 205 Nov 14 21:51 ServerExports.java
-rw---- 1 dgerman faculty 172 Nov 14 21:47 Update.java
frilled.cs.indiana.edu%javac *.java
frilled.cs.indiana.edu%rmic Server
frilled.cs.indiana.edu%rmic Client
frilled.cs.indiana.edu%ls -ld *.class
-rw---- 1 dgerman faculty 1242 Nov 14 21:58 Client.class
-rw---- 1 dgerman faculty 214 Nov 14 21:58 ClientExports.class
-rw---- 1 dgerman faculty 1593 Nov 14 21:58 Client_Skel.class
-rw---- 1 dgerman faculty 2877 Nov 14 21:58 Client_Stub.class
-rw---- 1 dgerman faculty 679 Nov 14 21:58 Server.class
-rw---- 1 dgerman faculty 267 Nov 14 21:58 ServerExports.class
-rw---- 1 dgerman faculty 1937 Nov 14 21:58 Server_Skel.class
-rw---- 1 dgerman faculty 3613 Nov 14 21:58 Server_Stub.class
-rw---- 1 dgerman faculty 349 Nov 14 21:58 Update.class
frilled.cs.indiana.edu%
16. Now the finishing touches.

17. The server's main becomes:

static void main(String[] args) {

  System.setSecurityManager(new RMISecurityManager());

  try {

    Server pam = new Server();

    Registry cat =
      LocateRegistry.createRegistry(Integer.parseInt(args[0]));

    cat.bind("Dirac", pam);

    System.out.println("Server is ready... ");
  } catch (Exception e) {
    System.out.println("Server error: " + e + "... ");
  }

}
18. The client's main becomes:
public static void main(String[] args) {

  try {
    ServerExports far =
      (ServerExports)Naming.lookup(
        "rmi://" + args[0] + ":" + args[1] + "/Dirac");

    Client here = new Client(args[2]);
 
    UnicastRemoteObject.exportObject(here);

    here.id = far.register(here);
    here.server = far;
    here.start();

  } catch (Exception e) {
    System.out.println("Error in client... " + e);
    e.printStackTrace();
  }

}
19. Here's how you start the server:
java Server <server-port>
20. Here's how you start the client:
java Client <server-host> <server-port> <client-name>
21. This is important:
import java.io.*;

public class Update implements Serializable {
  Update(String message) {
    this.message = message;
  }
  String message;
  public String toString() {
    return message;
  }
}
22. And this is important too:
frilled.cs.indiana.edu% ls -ld .java*
-rw---- 1 dgerman faculty 56 Nov 14 22:49 .java.policy
frilled.cs.indiana.edu% cat .java.policy
grant {
  permission java.security.AllPermission;
};
frilled.cs.indiana.edu%
End of story.