Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
CSCE 515: Computer Network Programming Chin-Tser Huang [email protected] University of South Carolina An RMI Chat with Callback Example An RMI-based client/server chat system with callback mechanism Define remote interfaces RMICallbackServer and RMICallbackClient Server class RMICallbackServerImpl accepts client registration through interface RMICallbackServer Client class RMICallbackClientImpl sends messages to server and server broadcasts messages to each registered client through interface RMICallbackClient 4/12/2005 2 Interface RMICallbackServer /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.rmi.*; public interface RMICallbackServer extends Remote { public static final String REGISTRY_NAME = "Callback Server"; public abstract void register (RMICallbackClient client) throws RemoteException; public abstract void deregister (RMICallbackClient client) throws RemoteException; public abstract void say (String message) throws RemoteException; } 4/12/2005 3 Interface RMICallbackClient /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.rmi.*; public interface RMICallbackClient extends Remote { public abstract void said (String message) throws RemoteException; } 4/12/2005 4 Class RMICallbackServerImpl /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import import import import java.rmi.*; java.util.*; java.rmi.server.*; java.rmi.registry.*; public class RMICallbackServerImpl extends UnicastRemoteObject implements RMICallbackServer { // public RMICallbackServerImpl () throws RemoteException … // public void register (RMICallbackClient client) … // public void deregister (RMICallbackClient client) … // public void say (String message) … // public static void main (String[] args) throws RemoteException … } 4/12/2005 5 Methods of RMICallbackServerImpl protected Vector clients; public RMIChatServerImpl () throws RemoteException { clients = new Vector (); } public void register (RMICallbackClient client) { try { say (getClientHost () + " has joined."); } catch (ServerNotActiveException ignored) { } clients.addElement (client); } public void deregister (RMICallbackClient client) { clients.removeElement (client); try { say (getClientHost () + " has left."); } catch (ServerNotActiveException ignored) { } } 4/12/2005 6 Method say public void say (String message) { Vector clients = (Vector) this.clients.clone (); for (int i = 0; i < clients.size (); ++ i) { RMICallbackClient client = (RMICallbackClient) clients.elementAt (i); try { client.said (message); } catch (RemoteException ex) { this.clients.removeElement (client); } } } 4/12/2005 7 Method main public static void main (String[] args) throws RemoteException { RMICallbackServerImpl callbackServer = new RMICallbackServerImpl (); Registry registry = LocateRegistry.getRegistry (); registry.rebind (REGISTRY_NAME, callbackServer); } 4/12/2005 8 Class RMICallbackClientImpl /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import import import import import java.awt.*; java.rmi.*; java.awt.event.*; java.rmi.server.*; java.rmi.registry.*; public class RMICallbackClientImpl extends UnicastRemoteObject implements RMICallbackClient, ActionListener{ // public RMICallbackClientImpl (String host) throws RemoteException … // public synchronized void start () throws RemoteException, NotBoundException … // public synchronized void stop () throws RemoteException … // public void said (String message) … // public void actionPerformed (ActionEvent ev) … // public static void main (String[] args) throws RemoteException, NotBoundException … } 4/12/2005 9 Constructor RMICallbackClientImpl protected protected protected protected String host; Frame frame; TextField input; TextArea output; public RMICallbackClientImpl (String host) throws RemoteException { this.host = host; frame = new Frame ("RMICallbackClientImpl [" + host + "]"); frame.add (output = new TextArea (), "Center"); output.setEditable (false); frame.add (input = new TextField (), "South"); input.addActionListener (this); frame.addWindowListener (new WindowAdapter () { public void windowOpened (WindowEvent ev) { input.requestFocus (); } public void windowClosing (WindowEvent ev) { try { stop (); } catch (RemoteException ex) { ex.printStackTrace (); } } }); frame.pack (); } 4/12/2005 10 Methods start, stop, and said protected RMICallbackServer server; public synchronized void start () throws RemoteException, NotBoundException { if (server == null) { Registry registry = LocateRegistry.getRegistry (host); server = (RMICallbackServer) registry.lookup (RMICallbackServer.REGISTRY_NAME); server.register (this); frame.setVisible (true); } } public synchronized void stop () throws RemoteException { frame.setVisible (false); RMICallbackServer server = this.server; this.server = null; if (server != null) server.deregister (this); } public void said (String message) { output.append (message + "\n"); } 4/12/2005 11 Method actionPerformed public void actionPerformed (ActionEvent ev) { try { RMICallbackServer server = this.server; if (server != null) { server.say (ev.getActionCommand ()); input.setText (""); } } catch (RemoteException ex) { input.setVisible (false); frame.validate (); ex.printStackTrace (); } } 4/12/2005 12 Method main public static void main (String[] args) throws RemoteException, NotBoundException { if (args.length != 1) throw new IllegalArgumentException ("Syntax: RMICallbackClientImpl <host>"); RMICallbackClientImpl callbackClient = new RMICallbackClientImpl (args[0]); callbackClient.start (); } 4/12/2005 13 Disadvantages of Example For every client, need to maintain two network connections, one incoming and one outgoing Connections will timeout and need to be periodically reestablished 4/12/2005 14 An RMI Distributed List Example Client and server maintain list state in local IDList object When an update is attempted to a client list, makes a remote method call on server If server approves the change, it makes remote method calls on all registered clients to indicate the change 4/12/2005 15 Distributed List Data Structure List List Object1 addElement() Object1 Object2 Object4 Object2 Object3 Object3 List updateElement() List Object1 replaceElement() Object1 Object3, Object2 Object2, Object5 Object5 Object5 Object6 Object4 Object4 Object4 Object6 List Enumeration Object5 Object4 Object6 elements() Object5 Object4 removeElement() Object1 Object6 4/12/2005 16 Interface DistributedList /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.util.*; public interface DistributedList { public abstract void addElement (Object element); public abstract void updateElement (Object oldElement, Object newElement); public abstract void replaceElement (Object oldElement, Object newElement); public abstract void removeElement (Object element); public abstract Enumeration getElements (); public abstract void addChangeListener (ChangeListener listener); public abstract void removeChangeListener (ChangeListener listener); } 4/12/2005 17 Interface ChangeListener /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.util.*; public interface ChangeListener extends EventListener { public abstract void changeOccurred (ChangeEvent changeEvent); } 4/12/2005 18 Class ChangeEvent /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.util.*; public class ChangeEvent extends EventObject { public ChangeEvent (Object source) { super (source); } } 4/12/2005 19 Class ID /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.io.*; public class ID implements Serializable { protected int id; public ID (int id) { this.id = id; } public boolean equals (Object other) { return (other != null) && (other instanceof ID) && (((ID) other).id == id); } } public int hashCode () { return id; } 4/12/2005 20 Class IDList /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.io.*; import java.util.*; public class IDList implements Serializable { // public IDList () … // public synchronized ID allocateID () … // public synchronized boolean addElement (ID id, Object element) … // public synchronized boolean updateElement (ID oldID, ID id, Object element) … // public synchronized boolean replaceElement (ID oldID, ID id, Object element) … // public synchronized boolean removeElement (ID id) … // public synchronized ID getID (Object element) … // public Enumeration getElements () … // public synchronized Object clone () … } 4/12/2005 21 Constructor IDList protected Vector ids, elements; public IDList () { ids = new Vector (); elements = new Vector (); } 4/12/2005 22 Methods of IDList protected int id; public synchronized ID allocateID () { return new ID (id ++); } protected int updateCount; public int getUpdateCount () { return updateCount; } public synchronized boolean addElement (ID id, Object element) { if (ids.contains (id)) return false; ids.addElement (id); elements.addElement (element); ++ updateCount; return true; } 4/12/2005 23 Methods of IDList public synchronized boolean updateElement (ID oldID, ID id, Object element) { int index = ids.indexOf (oldID); if (index < 0) return false; ids.setElementAt (id, index); elements.setElementAt (element, index); ++ updateCount; return true; } public synchronized boolean replaceElement (ID oldID, ID id, Object element) { int index = ids.indexOf (oldID); if (index < 0) return false; ids.removeElementAt (index); elements.removeElementAt (index); ids.addElement (id); elements.addElement (element); ++ updateCount; return true; } 4/12/2005 24 Methods of IDList public synchronized boolean removeElement (ID id) { int index = ids.indexOf (id); if (index < 0) return false; ids.removeElementAt (index); elements.removeElementAt (index); ++ updateCount; return true; } public synchronized ID getID (Object element) { int index = elements.indexOf (element); if (index < 0) return null; else return (ID) ids.elementAt (index); } public Enumeration getElements () { return ((Vector) elements.clone ()).elements (); } 4/12/2005 25 Methods of IDList public synchronized Object clone () { try { IDList idList = (IDList) super.clone (); idList.ids = (Vector) ids.clone (); idList.elements = (Vector) elements.clone (); return idList; } catch (CloneNotSupportedException ignored) { return null; } } 4/12/2005 26 Interface RMIListServer /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.rmi.*; public interface RMIListServer extends Remote { public abstract IDList register (RMIListClient client) throws RemoteException; public abstract void deregister (RMIListClient client) throws RemoteException; public abstract void addElement (Object element) throws RemoteException; public abstract void updateElement (ID id, Object newElement) throws RemoteException; public abstract void replaceElement (ID id, Object newElement) throws RemoteException; public abstract void removeElement (ID id) throws RemoteException; } 4/12/2005 27 Interface RMIListClient /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.rmi.*; public interface RMIListClient extends Remote { public abstract void elementAdded (ID id, Object element) throws RemoteException; public abstract void elementUpdated (ID oldID, ID id, Object element) throws RemoteException; public abstract void elementReplaced (ID oldID, ID id, Object element) throws RemoteException; public abstract void elementRemoved (ID id) throws RemoteException; } 4/12/2005 28 Class RMIListServerImpl /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import import import import java.rmi.*; java.util.*; java.rmi.server.*; java.rmi.registry.*; public class RMIListServerImpl extends UnicastRemoteObject implements RMIListServer { // public RMIListServerImpl () throws RemoteException … // public synchronized IDList register (RMIListClient client) … // public synchronized void deregister (RMIListClient client) … // public synchronized void addElement (Object element) … // public synchronized void updateElement (ID id, Object element) … // public synchronized void replaceElement (ID id, Object element) … // public synchronized void removeElement (ID id) … // public static void main (String[] args) throws RemoteException, AlreadyBoundException … } 4/12/2005 29 Constructor RMIListServerImpl protected IDList idList; protected Vector clients; public RMIListServerImpl () throws RemoteException { idList = new IDList (); clients = new Vector (); } 4/12/2005 30 Methods of RMIListServerImpl public synchronized IDList register (RMIListClient client) { clients.addElement (client); return idList; } public synchronized void deregister (RMIListClient client) { clients.removeElement (client); } 4/12/2005 31 Methods of RMIListServerImpl public synchronized void addElement (Object element) { ID id = idList.allocateID (); if (idList.addElement (id, element)) { for (int i = 0; i < clients.size (); ++ i) { try { ((RMIListClient) clients.elementAt (i)).elementAdded (id, element); } catch (RemoteException ex) { clients.removeElementAt (i --); } } } } public synchronized void updateElement (ID id, Object element) { ID newID = idList.allocateID (); if (idList.updateElement (id, newID, element)) { for (int i = 0; i < clients.size (); ++ i) { try { ((RMIListClient) clients.elementAt (i)).elementUpdated (id, newID, element); } catch (RemoteException ex) { clients.removeElementAt (i --); } } } } 4/12/2005 32 Methods of RMIListServerImpl public synchronized void replaceElement (ID id, Object element) { ID newID = idList.allocateID (); if (idList.replaceElement (id, newID, element)) { for (int i = 0; i < clients.size (); ++ i) { try { ((RMIListClient) clients.elementAt (i)).elementReplaced (id, newID, element); } catch (RemoteException ex) { clients.removeElementAt (i --); } } } } public synchronized void removeElement (ID id) { if (idList.removeElement (id)) { for (int i = 0; i < clients.size (); ++ i) { try { ((RMIListClient) clients.elementAt (i)).elementRemoved (id); } catch (RemoteException ex) { clients.removeElementAt (i --); } } } } 4/12/2005 33 Method main public static void main (String[] args) throws RemoteException, AlreadyBoundException { if (args.length != 2) throw new IllegalArgumentException ("Syntax: RMIListServerImpl <port> <service>"); RMIListServerImpl listServer = new RMIListServerImpl (); Registry registry = LocateRegistry.createRegistry (Integer.parseInt (args[0])); registry.bind (args[1], listServer); } 4/12/2005 34 Class RMIListClientImpl /* Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import import import import java.rmi.*; java.util.*; java.rmi.server.*; java.rmi.registry.*; public class RMIListClientImpl implements DistributedList { // public RMIListClientImpl (String host, int port, String service) … // public synchronized void start () throws RemoteException, NotBoundException … // public synchronized void stop () throws RemoteException … // public synchronized void addElement (Object element) … // public synchronized void updateElement (Object oldElement, Object newElement) … // public synchronized void replaceElement (Object oldElement, Object newElement) … // public synchronized void removeElement (Object element) … // public Enumeration getElements () … // public void addChangeListener (ChangeListener listener) … // public void removeChangeListener (ChangeListener listener) … // protected void fireChangeEvent (ChangeEvent changeEvent) … // class Callback implements RMIListClient … } 4/12/2005 35 Constructor RMIListClientImpl protected String host, service; protected int port; public RMIListClientImpl (String host, int port, String service) { this.host = host; this.port = port; this.service = service; } 4/12/2005 36 Methods of RMIListClientImpl protected IDList idList; protected RMIListClient myself; protected RMIListServer listServer; public synchronized void start () throws RemoteException, NotBoundException { if (listServer == null) { myself = (RMIListClient) UnicastRemoteObject.exportObject (new Callback ()); Registry registry = LocateRegistry.getRegistry (host, port); listServer = (RMIListServer) registry.lookup (service); try { idList = listServer.register (myself); } catch (RemoteException ex) { listServer = null; throw ex; } fireChangeEvent (new ChangeEvent (this)); } } public synchronized void stop () throws RemoteException { try { if (listServer != null) listServer.deregister (myself); } finally { listServer = null; UnicastRemoteObject.unexportObject (myself, true); } } 4/12/2005 37 Methods of RMIListClientImpl public synchronized void addElement (Object element) { if (listServer != null) { try { listServer.addElement (element); } catch (RemoteException ex) { listServer = null; } } } public synchronized void updateElement (Object oldElement, Object newElement) { if (listServer != null) { ID id = idList.getID (oldElement); if (id != null) { try { listServer.updateElement (id, newElement); } catch (RemoteException ex) { listServer = null; } } } } 4/12/2005 38 Methods of RMIListClientImpl public synchronized void replaceElement (Object oldElement, Object newElement) { if (listServer != null) { ID id = idList.getID (oldElement); if (id != null) { try { listServer.replaceElement (id, newElement); } catch (RemoteException ex) { listServer = null; } } } } public synchronized void removeElement (Object element) { if (listServer != null) { ID id = idList.getID (element); if (id != null) { try { listServer.removeElement (id); } catch (RemoteException ex) { listServer = null; } } } } public Enumeration getElements () { return idList.getElements (); } 4/12/2005 39 Methods of RMIListClientImpl protected Vector listeners = new Vector (); public void addChangeListener (ChangeListener listener) { listeners.addElement (listener); } public void removeChangeListener (ChangeListener listener) { listeners.removeElement (listener); } protected void fireChangeEvent (ChangeEvent changeEvent) { synchronized (listeners) { for (int i = 0; i < listeners.size (); ++ i) ((ChangeListener) listeners.elementAt (i)).changeOccurred (changeEvent); } } 4/12/2005 40 Inner Class Callback class Callback implements RMIListClient { public void elementAdded (ID id, Object element) { idList.addElement (id, element); fireChangeEvent (new ChangeEvent (RMIListClientImpl.this)); } public void elementUpdated (ID oldID, ID id, Object element) { idList.updateElement (oldID, id, element); fireChangeEvent (new ChangeEvent (RMIListClientImpl.this)); } public void elementReplaced (ID oldID, ID id, Object element) { idList.replaceElement (oldID, id, element); fireChangeEvent (new ChangeEvent (RMIListClientImpl.this)); } } public void elementRemoved (ID id) { idList.removeElement (id); fireChangeEvent (new ChangeEvent (RMIListClientImpl.this)); } 4/12/2005 41 Summary of RMI RMI framework hides low-level networking details in the guise of remote method calls Different style than using streams and sockets Each style has its own uses Sockets are useful when interacting with other socket-based applications and when full control of communication channel is needed RMI is good in designing cleaner high-level protocols, in request-based applications, and in peer-to-peer applications 4/12/2005 42 Next Class Telnet and rlogin File transfer protocol (FTP) Read TI Ch. 26, 27 4/12/2005 43