A348 Remote Server Invocation |
Because RMI is Java-based its use is limited as a general solution for building Web or Internet services. An open solution for distributed services being developed is .NET by Microsoft. Where Java passes data (method parameters and results) as Java obejcts, .NET converts data and passes as XML. We have examined ways in which programs can explicitly generate and parse XML, .NET performs this conversion between language representations and XML transparently, allowing one language to invoke methods of another (e.g. Java could call a C++ method, any parameters would be converted from Java-to-XML-to-C++ representation. Another key feature of .NET is that calls can be made to modules (methods/functions/subroutines) on the same or other computers with no change to the caller or calling program, offering the potential for a truly networked language.
// TimeServerInf.java interface definition
import java.rmi.*;
public interface TimeServerInf extends Remote {
public String getTime() throws RemoteException;
}
|
// TimeServerImpl.java
import java.rmi.*;
import java.rmi.server.*;
public class TimeServerImpl extends UnicastRemoteObject implements TimeServerInf {
public TimeServerImpl() throws RemoteException { super(); }
// implementation for TimeServerInf interface method, return the current date/time as String
public String getTime() {
return new java.util.Date().toString();
}
public static void main( String args[] ) throws Exception {
System.err.println( "Initializing server: please wait." );
// create server object and bind TimeServerImpl object to the rmiregistry on default port 1099
Naming.rebind( "//localhost/Time", new TimeServerImpl() );
System.err.println("The Time Server is up and running." );
}
}
|
// TimeClient.java import java.rmi.*;
public class TimeClient {
public static void main( String args[] ) throws Exception {
// lookup TimeServerInf remote object in rmiregistry on port 1099 of local host
TimeServerInf ts = (TimeServerInf) Naming.lookup( "//localhost/Time" );
// get time from server
System.out.println(ts.getTime());
}
}
TimeClient OutputThe time is: Tue Jun 19 11:30:36 EDT 2001 |
RMI software components - The RMI software components include
the infrastructure to suppport a programming model where apparent communication
is directly between the client and server as illustrated at left below.
![]() |
|
// TimeServerInf.java interface definition
import java.rmi.*;
public interface TimeServerInf extends Remote {
public String getTime() throws RemoteException;
}
|
// TimeServerImpl.java
import java.rmi.*;
import java.rmi.server.*;
public class TimeServerImpl extends UnicastRemoteObject implements TimeServerInf {
public TimeServerImpl() throws RemoteException { super(); }
// implementation for TimeServerInf interface method
public String getTime() {
try { return java.net.InetAddress.getLocalHost() + " " + new java.util.Date().toString(); }
catch(Exception e) { return "Failed"; }
}
public static void main( String args[] ) throws Exception {
System.err.println( "Initializing server: please wait." );
// create server object and bind TimeServerImpl object to the rmiregistry
Naming.rebind( "//localhost/Time", new TimeServerImpl() );
System.err.println("The Time Server is up and running." );
}
}
|
// TimeClient.java
import java.rmi.*;
public class TimeClient {
public static void main( String args[] ) throws Exception {
String host = "localhost";
if (args.length > 0) host = args[0];
// lookup TimeServerInf remote object in rmiregistry
TimeServerInf ts = (TimeServerInf) Naming.lookup( "//" + host + "/Time" );
// get time from server
System.out.println(ts.getTime());
}
}
|
| Output:
ray-laptop/127.0.0.1 Tue Jun 19 11:02:59 EDT 2001 |
| path=C:\JDK1.2.2\BIN;%path%
set classpath=%classpath%;.;C:\JDK1.2.2\lib\classes.zip javac *.java rmic -v1.2 TimeServerImpl start rmiregistry start java TimeServerImpl java TimeClient |
Define path to Java components
Define classpath to Java components Compile all Java programs. Generate a Java 2 TimeServerImpl_Stub.class used by client to invoke RMI server methods. Start the RMI registry used to bind server objects to host and port number (normally port 1099). Start the server and bind to host and port number. Execute client invoking getTime method on server. |
The key software elements are the same as before:
// SortServerInf.java interface definition
import java.rmi.*;
public interface SortServerInf extends Remote {
public int[] sort( int data[] ) throws RemoteException;
}
|
// SortServerImpl.java
import java.rmi.*;
import java.rmi.server.*;
public class SortServerImpl extends UnicastRemoteObject implements SortServerInf {
public SortServerImpl() throws RemoteException { super(); }
// implementation for SortServerInf interface method
public int[] sort( int data[] ) {
int n = data.length;
int temp;
for (int pass = 0; pass < n-1; pass++)
for (int pair=0; pair < n-pass-1; pair++)
if( data[pair] < data[pair+1]) {
temp = data[pair];
data[pair] = data[pair+1];
data[pair+1] = temp;
}
return data;
}
public static void main( String args[] ) throws Exception {
System.err.println( "Initializing server: please wait." );
String number = "";
if (args.length > 0) number = args[0];
// create server object and bind SortServerImpl object to the rmiregistry
Naming.rebind( "//localhost/Sort" + number, new SortServerImpl() );
System.err.println("The Sort Server " + number + " is up and running." );
}
}
|
// SortClient.java
import java.rmi.*;
public class SortClient {
public static void main( String args[] ) throws Exception {
int unsorted[] = {93, 81, 95, 74};
int sorted[];
String host = "localhost";
if (args.length > 0) host = args[0];
// lookup SortServerInf remote object in rmiregistry
SortServerInf ss = (SortServerInf) Naming.lookup( "//" + host + "/Sort" );
// Sort on server
sorted = ss.sort(unsorted);
System.out.println("Unsorted Sorted");
for (int i=0; i<unsorted.length; i++)
System.out.println(unsorted[i] + " " + sorted[i]);
}
}
|
Output:
Unsorted Sorted 93 95 81 93 95 81 74 74 |
| path=C:\JDK1.2.2\BIN;%path%
set classpath=%classpath%;.;C:\JDK1.2.2\lib\classes.zip javac *.java rmic -v1.2 SortServerImpl start rmiregistry start java SortServerImpl java SortClient |
Define path to Java components
Define classpath to Java components Compile all Java programs. Generate a Java 2 SortServerImpl_Stub.class used by client to invoke RMI server methods. Start the RMI registry used to bind server objects to host and port number (normally port 1099). Start the server and bind to host and port number. Execute client invoking sort method on server. |
// MultiSortClient.java
import java.rmi.*;
public class MultiSortClient {
public static void main( String args[] ) throws Exception {
int unsorted1[] = {93, 81, 95, 74};
int unsorted2[] = {93, 81, 95, 74};
int sorted1[], sorted2[];
int sorted[];
String host1 = "localhost", host2 = "localhost";
if (args.length == 2) { host1 = args[0]; host2 = args[1]; }
// lookup SortServerInf remote object in rmiregistry
SortServerInf ss1 = (SortServerInf) Naming.lookup( "//" + host1 + "/Sort1" );
SortServerInf ss2 = (SortServerInf) Naming.lookup( "//" + host2 + "/Sort2" );
// Sort on server
sorted1 = ss1.sort(unsorted1);
sorted2 = ss2.sort(unsorted2);
sorted = new MultiSortClient().merge(sorted1, sorted2);
System.out.println("Sorted");
for (int i=0; i<sorted.length; i++)
System.out.println(sorted[i]);
}
private int[] merge(int s1[], int s2[]) {
int merged[] = new int[s1.length+s2.length];
int i1=0, i2=0;
for (int i=0; i<merged.length; i++)
if (i1 == s1.length) merged[i] = s2[i2++];
else if (i2 == s2.length) merged[i] = s1[i1++];
else if (s1[i1] > s2[i2]) merged[i]=s1[i1++];
else merged[i] = s2[i2++];
return merged;
}
}
|
Output:
Sorted 95 95 93 93 81 81 74 74 |
| path=C:\JDK1.2.2\BIN;%path%
set classpath=%classpath%;.;C:\JDK1.2.2\lib\classes.zip javac *.java rmic -v1.2 SortServerImpl start rmiregistry start java SortServerImpl 1 start java SortServerImpl 2 java MultiSortClient |
Define path to Java components
Define classpath to Java components Compile all Java programs. Generate a Java 2 SortServerImpl_Stub.class used by client to invoke RMI server methods. Start the RMI registry used to bind server objects to host and port number (normally port 1099). Start the server and bind to //localhost/Sort1 and port number. Start the server and bind to //localhost/Sort2 and port number. Execute client invoking sort method on server. |
where
each executes sequentially. Ideally both sorts would occur simultaneously,
This can be achieved by making each server sort invocation in a seperate
thread on the client and waiting for each server to finished before merging
the sorted arrays. The following implements a threaded client that is in
other aspects the same as the previous example. The key changes are:
// TMultiSortClient.java
import java.rmi.*;
class SortThread extends Thread {
int unsorted[], sorted[];
SortServerInf ss;
String name;
boolean sorting;
public SortThread(SortServerInf ss, int unsorted[], String name) {
this.unsorted = unsorted;
this.ss = ss;
this.name = name;
sorting = true;
}
public int[] getSorted() {
return sorted;
}
public void run() {
System.out.println("Started thread " + name);
try {
sorted = ss.sort(unsorted);
} catch(Exception e) {}
System.out.println("Finished thread " + name);
sorting = false;
}
public boolean sorting() {
return sorting;
}
}
public class TMultiSortClient {
public static void main( String args[] ) throws Exception {
int unsorted1[] = {93, 81, 95, 74};
int unsorted2[] = {93, 81, 95, 74};
int sorted1[], sorted2[];
int sorted[];
SortThread thread1, thread2;
String host1 = "localhost", host2 = "localhost";
if (args.length == 2) { host1 = args[0]; host2 = args[1]; }
// lookup SortServerInf remote object in rmiregistry
SortServerInf ss1 = (SortServerInf) Naming.lookup( "//" + host1 + "/Sort1" );
SortServerInf ss2 = (SortServerInf) Naming.lookup( "//" + host2 + "/Sort2" );
// Start sort threads
thread1 = new SortThread(ss1, unsorted1, "Sort1");
thread2 = new SortThread(ss2, unsorted2, "Sort2");
thread1.start();
thread2.start();
// Wait while either thread is sorting
while(thread1.sorting() || thread2.sorting()) System.out.println("Sorting");;
sorted = new TMultiSortClient().merge(thread1.getSorted(), thread2.getSorted());
System.out.println("Sorted");
for (int i=0; i<sorted.length; i++)
System.out.println(sorted[i]);
}
private int[] merge(int s1[], int s2[]) {
int merged[] = new int[s1.length+s2.length];
int i1=0, i2=0;
for (int i=0; i<merged.length; i++)
if (i1 == s1.length) merged[i] = s2[i2++];
else if (i2 == s2.length) merged[i] = s1[i1++];
else if (s1[i1] > s2[i2]) merged[i]=s1[i1++];
else merged[i] = s2[i2++];
return merged;
}
}
|
| Output
Sorting Started thread Sort2 Started thread Sort1 Sorting Sorting Finished thread Sort2 Finished thread Sort1 Sorting Sorted 95 95 93 93 81 81 74 74 |
| path=C:\JDK1.2.2\BIN;%path%
set classpath=%classpath%;.;C:\JDK1.2.2\lib\classes.zip javac *.java rmic -v1.2 SortServerImpl start rmiregistry start java SortServerImpl 1 start java SortServerImpl 2 java TMultiSortClient |
Define path to Java components
Define classpath to Java components Compile all Java programs. Generate a Java 2 SortServerImpl_Stub.class used by client to invoke RMI server methods. Start the RMI registry used to bind server objects to host and port number (normally port 1099). Start the server and bind to //localhost/Sort1 and port number. Start the server and bind to //localhost/Sort2 and port number. Execute client invoking sort method on all servers. |