Java Q&A by Govind Seshadri Example 1: javac -d . QClientInterface.java javac -d . QServerInterface.java javac -d . QuoteServer.java javac -d . QuoteApplet.java Example 2: rmic -d . mypackage.rmiexamples.QuoteServer rmic -d . mypackage.rmiexamples.QuoteApplet Listing One /** Defines the methods available to the client for remote invocation */ package mypackage.rmiexamples; public interface QServerInterface extends java.rmi.Remote { public void addQuote(String quote) throws java.rmi.RemoteException; public void setQClientInterface(QClientInterface c) throws java.rmi.RemoteException; } Listing Two /** Defines methods available to server for remote invocation as callbacks */ package mypackage.rmiexamples; public interface QClientInterface extends java.rmi.Remote { public void refreshClient(String q) throws java.rmi.RemoteException; } Listing Three package mypackage.rmiexamples; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; import mypackage.rmiexamples.QClientInterface; import mypackage.rmiexamples.QServerInterface; import java.util.*; import java.rmi.registry.LocateRegistry; public class QuoteServer extends UnicastRemoteObject implements QServerInterface, Runnable { private Vector clientele; //tracks all connected clients private QClientInterface myQClientInterface; private Vector quoteList; //maintains updatable list of quotes private QClientInterface myClientObj; private Thread clientThread=null; private static int counter=0; public QuoteServer () throws java.rmi.RemoteException { super(); // create and initialize the quote list quoteList = new Vector(); quoteList.addElement("Climb mountains to see lowlands"); quoteList.addElement("If you want the rainbow, put up with the rain"); quoteList.addElement("Smooth seas do not make skilful sailors"); clientele = new Vector(); } public void setQClientInterface(QClientInterface c) throws RemoteException { synchronized (clientele) { clientele.addElement(c); } if (clientThread == null) { clientThread = new Thread(this, "clientThread"); clientThread.start(); } } private void doIt() { synchronized (clientele) { Vector backup = (Vector) clientele.clone(); int seed; while ((seed = new Random().nextInt()) <=0) ; seed = seed % quoteList.size(); String data = quoteList.elementAt(seed)+ ": "+ ++counter; for (int i=0; i < clientele.size(); i++) { myClientObj = (QClientInterface) clientele.elementAt(i); try { //update the client asynchronously via callback myClientObj.refreshClient((String) data ); } catch (RemoteException e) { System.out.println("client must have disconnected!"); //get rid of remote reference for disconnected client backup.removeElement(myClientObj); if (backup.size() <= 0) { //no more clients- so stop server thread clientele = (Vector) backup.clone(); Thread dummy = clientThread; clientThread = null; dummy.stop(); } } } clientele = (Vector) backup.clone(); } //end syncronization on clientele } public void run() { while (true) { try { //sleep for a second Thread.currentThread().sleep(1000); } catch (Exception e) { } doIt(); } } public void addQuote(String quote) throws RemoteException { synchronized (quoteList) { //update quote list quoteList.addElement(quote); } } public static void main(String[] args) { System.setSecurityManager(new RMISecurityManager()); try { System.out.println("QuoteServer.main: creating registry"); LocateRegistry.createRegistry(1099); System.out.println("QuoteServer.main: creating server"); QuoteServer myQuoteServer=new QuoteServer(); System.out.println("QuoteServer.main: binding server "); Naming.rebind("/QuoteServer", myQuoteServer); System.out.println("QuoteServer bound in registry"); } catch (Exception e) { System.out.println("Exception on binding QuoteServer"); System.out.println(e.toString()); } } } Listing Four package mypackage.rmiexamples; import mypackage.rmiexamples.QServerInterface; import mypackage.rmiexamples.QClientInterface; import java.rmi.*; import java.rmi.server.*; import java.util.Random; import java.awt.*; import java.applet.*; public class QuoteApplet extends Applet implements QClientInterface { public QServerInterface srvQuote=null; //the client uses jdk1.1 event handling mechanism void sendQuote_Clicked(java.awt.event.ActionEvent event) { try { //update the remote server object with a new quote srvQuote.addQuote((String)myQuote.getText()); } catch (Exception e) { System.out.println(e.toString()); } } public void init() { super.init(); try { //by exporting the client object, turn it into a //remote object UnicastRemoteObject.exportObject(this); } catch (Exception e) { System.out.println("Could not export client remote object"); System.out.println(e); } try { //obtain the remote server object's reference by interrogating the //rmi registry srvQuote = (QServerInterface) Naming.lookup("//"+getCodeBase().getHost()+"/QuoteServer"); srvQuote.setQClientInterface(this); } catch (Exception e) { System.out.println("Could not set client interface at server"); System.out.println(e.toString()); } } public void addNotify() { //don't worry about the specifics of the //following code. All it does is create a GUI //for the rmi client super.addNotify(); setLayout(null); resize(1016,565); label1 = new java.awt.Label("Input Quote:"); label1.reshape(21,24,72,21); add(label1); myQuote = new java.awt.TextField(); myQuote.reshape(104,24,242,21); add(myQuote); sendQuote = new java.awt.Button("Send"); sendQuote.reshape(357,24,48,21); add(sendQuote); quoteList = new java.awt.TextArea(); add(quoteList); quoteList.reshape(36,60,371,125); //register listners Action lAction = new Action(); sendQuote.addActionListener(lAction); } java.awt.Label label1; java.awt.TextField myQuote; java.awt.Button sendQuote; java.awt.TextArea quoteList; public void refreshClient(String q) throws java.rmi.RemoteException { //this is the callback method implementation quoteList.append(q+"\n"); } class Action implements java.awt.event.ActionListener { public void actionPerformed(java.awt.event.ActionEvent event) { Object object = event.getSource(); if (object == sendQuote) sendQuote_Clicked(event); } } }