UnicastRemoteObject.exportObject (remote_object
The exportObject() method returns a stub which can be cast to the remote interface that the client implements. Here is an example which simulates this.
I have the following pieces of code:
- AttractionListener.java - The remote interface which the client will implement. It has a callback method attractionAdded() which the RMI server will invoke on completion of a long running task.
- CallbackClient.java - The client code which invokes the long running method addAttraction() on the RMI server.
- Attractions.java - The remote interface which will be implemented by the RMI Server. It has a method addAttractionListener() which lets the client register itself with the server.
- AttractionsImpl.java - The RMI server which implements Attractions interface. It runs the long running task on a seperate thread.
- ServerRMI.java - The code which binds the RMI server to the rmi registry.
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface AttractionListener extends Remote {
public void attractionAdded(String attraction) throws RemoteException;
}
CallbackClient.java
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Scanner;
public class CallbackClient implements AttractionListener {
public void attractionAdded(String attraction)
throws RemoteException {
System.out.println("Attraction Added:" + attraction);
}
public static void main(String args[]) {
try {
AttractionListener client = new CallbackClient();
System.out.println("Exporting the client");
UnicastRemoteObject.exportObject(client);
String serverURL = "rmi://127.0.0.1:1099/ServerRMI";
Attractions server =
(Attractions)Naming.lookup(serverURL);
server.addAttractionListener(client);
String s;
while (true) {
System.out.println("Enter new attraction:");
Scanner sc = new Scanner(System.in);
s = sc.next();
if (s != null) {
server.addAttraction(s);
}
}
} catch (Exception e) {
System.out.println("Exception occured " +
"while adding attraction: " +
"\n" + e.getMessage());
}
}
}
Attractions.java
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;
public interface Attractions extends Remote {
public void addAttraction(String name) throws RemoteException;
public List<String> showAttractions() throws RemoteException;
public void addAttractionListener(AttractionListener listener) throws RemoteException;
}
AttractionsImpl.java
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
public class AttractionsImpl extends UnicastRemoteObject implements Attractions {
private static final long serialVersionUID = 1L;
private List<String> attractions = new ArrayList<String>();
private AttractionListener listener;
protected AttractionsImpl() throws RemoteException {
super();
}
@Override
public void addAttraction(String name) throws RemoteException {
if (name != null) {
verifyAttraction(name);
}
}
@Override
public List<String> showAttractions() throws RemoteException {
List<String> a = new ArrayList<String>();
a.addAll(attractions);
return attractions;
}
@Override
public void addAttractionListener(
AttractionListener listener) throws RemoteException {
this.listener = listener;
}
private void verifyAttraction(String name) {
Runnable t = new VerifyThread(name);
new Thread(t).start();
System.out.println("Verify Thread started");
}
private class VerifyThread implements Runnable {
private String name;
VerifyThread(String name) {
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println("Finished verifying");
attractions.add(name);
if (listener!= null)
listener.attractionAdded(name);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
ServerRMI.java
import java.rmi.Naming;
public class ServerRMI {
public static void main (String args[] ) {
try {
Attractions attractions = new AttractionsImpl();
Naming.rebind("ServerRMI", attractions);
System.out.println("Server started!");
}
catch (Exception e) {
System.out.println("Exception: " + e);
}
}
}
Here are steps for getting the code working:
Compile the code
run rmic on the CallbackClient
start the rmiregistry
start the server
start the client
Here is a sample output:
Running the client:
Exporting the client
Enter new attraction:
tt
Enter new attraction:
rr
Attraction Added:tt
Attraction Added:rr
Server Output:
Server started!
Verify Thread started
Finished verifying
Verify Thread started
Finished verifying
I have kept the code simple to illustrate RMI callbacks. Usually the server has a List of listeners as there will be multiple clients. Also since RMI server handles each request in separate thread for calls originating from different connections, you will need to synchronize the code i.e. make the server-side code thread-safe.