A Style of Distributing Computation

I present a style of writing distributed applications that is suitable for presentation in an introductory programming class.

I foresee a number of objections to this style; I address them briefly at the end.

1. A Basic Setup

We start from a simple class:

burrowww.cs.indiana.edu% cat Peer.java
public class Peer {
String name;
Peer(String name) {
this.name = name;
}
public void ask(Peer other) {
System.out.println(name + " receives:\n " + other.report());
}
public String report() {
try {
return "For " + this.name + " the time is " +
new java.util.Date() + "\n on host " +
java.net.InetAddress.getLocalHost() + "\n";
} catch (Exception e) {
return "Error... " + e;
}
}
}
burrowww.cs.indiana.edu%

And here it is in action:

burrowww.cs.indiana.edu% cat Setup.java
class Setup {
public static void main(String[] args) {
Peer one = new Peer("Larry");
Peer two = new Peer("Michael");
one.ask(two);
}
}
burrowww.cs.indiana.edu% javac Setup.java
burrowww.cs.indiana.edu% ls -ld *.class
-rw-r--r-- 1 dgerman faculty 1040 Feb 18 23:37 Peer.class
-rw-r--r-- 1 dgerman faculty 388 Feb 18 23:56 Setup.class
burrowww.cs.indiana.edu% java Setup
Larry receives:
For Michael the time is Wed Feb 18 23:56:57 EST 2004
on host burrowww.cs.indiana.edu/129.79.245.98
burrowww.cs.indiana.edu% 

Let's see what it takes to place the two objects on different virtual machines.


2. Elements of Pure Design

This expression obviously refers to interfaces.

I list the following references which mention RMI (in the context of design patterns):

Now Gosling says (p. 118):

So here's what happens now:

burrowww.cs.indiana.edu% ls -ld *.java
-rw-r--r-- 1 dgerman faculty 478 Feb 19 00:10 Peer.java
-rw-r--r-- 1 dgerman faculty 48 Feb 19 00:09 PeerInterface.java
-rw-r--r-- 1 dgerman faculty 154 Feb 18 23:34 Setup.java
burrowww.cs.indiana.edu% cat Peer.java
public class Peer implements PeerInterface {
String name;
Peer(String name) {
this.name = name;
}
public void ask(PeerInterface other) {
System.out.println(other.report());
}
public String report() {
try {
return "For " + this.name + " the time is " +
new java.util.Date() + "\n on host " +
java.net.InetAddress.getLocalHost() + "\n";
} catch (Exception e) {
return "Error... " + e;
}
}
}
burrowww.cs.indiana.edu% cat PeerInterface.java
interface PeerInterface {
String report();
}

burrowww.cs.indiana.edu% javac PeerInterface.java
burrowww.cs.indiana.edu% java Setup
Larry receives:
For Michael the time is Thu Feb 19 00:10:24 EST 2004
on host burrowww.cs.indiana.edu/129.79.245.98
burrowww.cs.indiana.edu% 

3. Distributed Peers

Encapsulating the networked behaviour of the peers:

burrowww.cs.indiana.edu% ls -ld *.java
-rw-r--r-- 1 dgerman faculty 1547 Feb 19 00:22 NetworkedPeer.java
-rw-r--r-- 1 dgerman faculty 511 Feb 19 00:23 Peer.java
-rw-r--r-- 1 dgerman faculty 106 Feb 19 00:22 PeerInterface.java
-rw-r--r-- 1 dgerman faculty 154 Feb 18 23:34 Setup.java
burrowww.cs.indiana.edu% cat NetworkedPeer.java
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
public class NetworkedPeer extends Peer implements PeerInterface {
NetworkedPeer(String name) throws RemoteException {
super(name);
UnicastRemoteObject.exportObject(this);
}
public void startAsServer(String name, int port) {
System.setSecurityManager(new RMISecurityManager());
try {
Registry registry = LocateRegistry.createRegistry(port);
registry.bind(name, this);
System.out.println("Server is ready... ");
} catch (Exception e) {
System.out.println("Server error: " + e + "... ");
}
}
public void startAsClient(String peerHost, int port, String peerName) {
try {
PeerInterface peer = (PeerInterface)Naming.lookup("rmi://" + peerHost + ":" + port + "/" + peerName);
this.ask(peer);
} catch (Exception e) {
System.out.println("Something went wrong... " + e);
e.printStackTrace();
}
}
public static void main(String[] args) throws RemoteException {
String mode = args[0];
if (mode.equals("-S")) { // start as server
String port = args[1];
String name = args[2];
NetworkedPeer peer = new NetworkedPeer(name);
peer.startAsServer(name, Integer.parseInt(port));
} else { // start as client
String host = args[0];
String port = args[1];
String name = args[2];
NetworkedPeer peer = new NetworkedPeer(name);
peer.startAsClient(host, Integer.parseInt(port), name);
}
}
}
burrowww.cs.indiana.edu%

This was a lot of new code.

Here are the changes we need to make in the existent code.

burrowww.cs.indiana.edu% cat PeerInterface.java
import java.rmi.*;
interface PeerInterface extends Remote {
String report() throws RemoteException;
}
burrowww.cs.indiana.edu% cat Peer.java
public class Peer implements PeerInterface {
String name;
Peer(String name) {
this.name = name;
}
public void ask(PeerInterface other) throws java.rmi.RemoteException {
System.out.println(other.report());
}
public String report() {
try {
return "For " + this.name + " the time is " +
new java.util.Date() + "\n on host " +
java.net.InetAddress.getLocalHost() + "\n";
} catch (Exception e) {
return "Error... " + e;
}
}
}
burrowww.cs.indiana.edu% cat Setup.java
class Setup {
public static void main(String[] args) throws java.rmi.RemoteException {
Peer one = new Peer("Larry");
Peer two = new Peer("Michael");
one.ask(two);
two.ask(one);
}
}
burrowww.cs.indiana.edu% javac *.java
burrowww.cs.indiana.edu% java Setup
For Michael the time is Thu Feb 19 00:47:57 EST 2004
on host burrowww.cs.indiana.edu/129.79.245.98
For Larry the time is Thu Feb 19 00:47:57 EST 2004
on host burrowww.cs.indiana.edu/129.79.245.98
burrowww.cs.indiana.edu% rmic NetworkedPeer
burrowww.cs.indiana.edu% java NetworkedPeer -S 19086 Larry 
Server is ready...

We note though that all we need to do is change the decorations.

No real change of code is truly happening.

Meanwhile on tucotuco.cs.indiana.edu the same code is started as a client:

tucotuco.cs.indiana.edu% java NetworkedPeer burrowww.cs.indiana.edu 19086 Larry
For Larry the time is Thu Feb 19 00:52:34 EST 2004
on host burrowww.cs.indiana.edu/129.79.245.98

4. An Idiom

It is at this point that the pattern in the "Net Worth" paper should be proposed.

The goal would be to teach a particular style of development.

This is not the same as a pattern. It's more like an idiom that is taught by practice.

This is what the Little Lisper does with the recursive style of development.

With time an abstract pattern composed of a base case and recursion step emerges.

It is exactly what I want to do for this conference.

And I want to include a web page with a lot of (extensive) case studies.

I already have a web chat with shared virtual board and a simple avatar chat with penguins.

But the true value of this would be to teach a style of development.

That is, developing a distributed application in a certain specific style.

5. What Patterns

I can use the Adapter pattern but I don't like that I have to change the names.

It looks so much more reassuring to just decorate the code.

I believe we need a way to override a type (an interface).

If we can do that we can also provide a pattern, not just a style.

Perhaps I can do that using reflection and/or inner types.

I want to model what I showed above.

6. Serialization

I have avoided it in the example above (the simplest I can come up with).

I have no objections to bringing it up from the outset.

But I believe we can define a large enough class of applications where that wouldn't be necessary.

7. Why

I need to remind myself constantly I am doing this because I want to provide my students with a working tool.

The tool is a framework. My students are developing multiplayer games. They turn them in for their Master's Projects.

I am aware of many other tools available (e.g., Jabber). But this is to be a pure, grass-roots level Java solution.