70
2002 Prentice Hall. All rights reserved. Chapter 13: Remote Method Invocation Outline 13.1 Introduction 13.2 Case Study: Creating a Distributed System with RMI 13.3 Defining the Remote Interface 13.4 Implementing the Remote Interface 13.5 Compiling and Executing the Server and the Client 13.6 Case Study: Deitel Messenger with Activatable Server 13.6.1 Activatable Deitel Messenger ChatServer 13.6.2 Deitel Messenger Client Architecture and Implementation 13.6.3 Running the Deitel Messenger Server and Client Applications 13.7 Internet and World Wide Web Resources

2002 Prentice Hall. All rights reserved. Chapter 13: Remote Method Invocation Outline 13.1 Introduction 13.2 Case Study: Creating a Distributed System

  • View
    213

  • Download
    0

Embed Size (px)

Citation preview

2002 Prentice Hall. All rights reserved.

Chapter 13: Remote Method Invocation

Outline13.1 Introduction13.2 Case Study: Creating a Distributed System with RMI13.3 Defining the Remote Interface13.4 Implementing the Remote Interface13.5 Compiling and Executing the Server and the Client13.6 Case Study: Deitel Messenger with Activatable Server

13.6.1 Activatable Deitel Messenger ChatServer13.6.2 Deitel Messenger Client Architecture and

Implementation13.6.3 Running the Deitel Messenger Server and

Client Applications13.7 Internet and World Wide Web Resources

2002 Prentice Hall. All rights reserved.

13.1 Introduction

• Remote Procedure Calls (RPCs)– Call functions residing on another computer

– Communicate over a network

– Marshal of data

– Limited data types

– Lean interface definition language (IDL)

• Remote Method Invocation (RMI)– Java’s implementation of RPC

– Handle the marshaling of data across the network

– Transfer Java objects

– No IDL is required

2002 Prentice Hall. All rights reserved.

13.2 Case Study: Creating a Distributed System with RMI

• Creating a distributed system with RMI– Define a remote interface

– Define the remove object implementation

– Define the client application

– Compile and execute the remove object and the client

2002 Prentice Hall. All rights reserved.

13.3 Defining the Remote Interface

• Remote interface– Describes the remote methods

– Extends interface java.rmi.Remote

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.1 WeatherService interface.

Line 10

Line 13

1 // WeatherService.java2 // WeatherService interface declares a method for obtaining3 // wether information.4 package com.deitel.advjhtp1.rmi.weather;5 6 // Java core packages7 import java.rmi.*;8 import java.util.*;9 10 public interface WeatherService extends Remote {11 12 // obtain List of WeatherBean objects from server13 public List getWeatherInformation() throws RemoteException;14 15 }

Interface WeatherService extends interface Remote.

Declares method getWeatherInformation, which clients can invoke to retrieve weather information from the remote object.

2002 Prentice Hall. All rights reserved.

13.4 Implementing the Remote Interface

• Remote object implementation– WeatherServiceImpl

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.2 WeatherServiceImpl class implements remote interface WeatherService.

Lines 13-14

Line 21

Lines 32-33

1 // WeatherServiceImpl.java2 // WeatherServiceImpl implements the WeatherService remote3 // interface to provide a WeatherService remote object.4 package com.deitel.advjhtp1.rmi.weather;5 6 // Java core packages7 import java.io.*;8 import java.net.URL;9 import java.rmi.*;10 import java.rmi.server.*;11 import java.util.*;12 13 public class WeatherServiceImpl extends UnicastRemoteObject14 implements WeatherService {15 16 private List weatherInformation; // WeatherBean object List17 18 // initialize server19 public WeatherServiceImpl() throws RemoteException20 {21 super();22 updateWeatherConditions();23 }24 25 // get weather information from NWS26 private void updateWeatherConditions()27 {28 try {29 System.out.println( "Update weather information..." );30 31 // National Weather Service Traveler’s Forecast page32 URL url = new URL(33 "http://iwin.nws.noaa.gov/iwin/us/traveler.html" );34

Extends class UnicastRemoteObject to obtain basic functionality required for all remote objects and implements interface WeatherService.

Invokes the default constructor for class UnicastRemoteObject.

Create a URL object for the Traveler’s Forecast Web page.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.2 WeatherServiceImpl class implements remote interface WeatherService.

Line 42-43

Line 57

35 // create BufferedReader for reading Web page contents36 BufferedReader in = new BufferedReader(37 new InputStreamReader( url.openStream() ) );38 39 // separator for starting point of data on Web page40 String separator = "TAV12"; 41 42 // locate separator string in Web page43 while ( !in.readLine().startsWith( separator ) )44 ; // do nothing45 46 // strings representing headers on Traveler’s Forecast47 // Web page for daytime and nighttime weather48 String dayHeader =49 "CITY WEA HI/LO WEA HI/LO";50 String nightHeader =51 "CITY WEA LO/HI WEA LO/HI";52 53 String inputLine = "";54 55 // locate header that begins weather information56 do {57 inputLine = in.readLine();58 } while ( !inputLine.equals( dayHeader ) &&59 !inputLine.equals( nightHeader ) );60 61 weatherInformation = new ArrayList(); // create List62 63 // create WeatherBeans containing weather data and 64 // store in weatherInformation List65 inputLine = in.readLine(); // get first city's info66

Read through the Traveler’s Forecast Web page until reaching the sentinel.

Read next line from the Web page.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.2 WeatherServiceImpl class implements remote interface WeatherService.

Lines 70-85

Lines 76-79

Line 82

Line 87

67 // The portion of inputLine containing relevant data is68 // 28 characters long. If the line length is not at 69 // least 28 characters long, done processing data.70 while ( inputLine.length() > 28 ) {71 72 // Create WeatherBean object for city. First 16 73 // characters are city name. Next, six characters74 // are weather description. Next six characters75 // are HI/LO or LO/HI temperature.76 WeatherBean weather = new WeatherBean(77 inputLine.substring( 0, 16 ), 78 inputLine.substring( 16, 22 ), 79 inputLine.substring( 23, 29 ) );80 81 // add WeatherBean to List82 weatherInformation.add( weather ); 83 84 inputLine = in.readLine(); // get next city's info85 }86 87 in.close(); // close connection to NWS Web server 88 89 System.out.println( "Weather information updated." );90 91 } // end method updateWeatherConditions92 93 // handle exception connecting to National Weather Service94 catch( java.net.ConnectException connectException ) {95 connectException.printStackTrace();96 System.exit( 1 );97 }98

Read each city’s weather information and place this information in WeatherBean objects.

Construct a WeatherBean object for the current city.

Adds the WeatherBean object to the List.

Closes the BufferedReader and its associated InputStream.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.2 WeatherServiceImpl class implements remote interface WeatherService.

Lines 107-110

Line 121

Line 124

99 // process other exceptions100 catch( Exception exception ) {101 exception.printStackTrace();102 System.exit( 1 );103 }104 }105 106 // implementation for WeatherService interface remote method107 public List getWeatherInformation() throws RemoteException 108 {109 return weatherInformation;110 }111 112 // launch WeatherService remote object113 public static void main( String args[] ) throws Exception114 { 115 System.out.println( "Initializing WeatherService..." );116 117 // create remote object118 WeatherService service = new WeatherServiceImpl();119 120 // specify remote object name121 String serverObjectName = "rmi://localhost/WeatherService";122 123 // bind WeatherService remote object in RMI registry124 Naming.rebind( serverObjectName, service );125 126 System.out.println( "WeatherService running." );127 }128 }

Implementing method defined in interface to respond to remote request.

Defines the URL that a client can use to obtain a remote reference to the server object.

Invokes static method rebind of class Naming to bind the remote WeatherServiceImpl object service to the RMI registry with the specified URL.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.3 WeatherBean stores weather forecast for one city.

Lines 25-45

1 // WeatherBean.java2 // WeatherBean maintains weather information for one city.3 package com.deitel.advjhtp1.rmi.weather;4 5 // Java core packages6 import java.awt.*;7 import java.io.*;8 import java.net.*;9 import java.util.*;10 11 // Java extension packages12 import javax.swing.*;13 14 public class WeatherBean implements Serializable {15 16 private String cityName; // name of city17 private String temperature; // city's temperature18 private String description; // weather description19 private ImageIcon image; // weather image20 21 private static Properties imageNames; 22 23 // initialize imageNames when class WeatherBean 24 // is loaded into memory25 static {26 imageNames = new Properties(); // create properties table27 28 // load weather descriptions and image names from 29 // properties file30 try {31 32 // obtain URL for properties file33 URL url = WeatherBean.class.getResource( 34 "imagenames.properties" );35

Load a property file that contains image names for displaying the weather information.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.3 WeatherBean stores weather forecast for one city.

36 // load properties file contents37 imageNames.load( new FileInputStream( url.getFile() ) );38 }39 40 // process exceptions from opening file41 catch ( IOException ioException ) { 42 ioException.printStackTrace();43 }44 45 } // end static block46 47 // WeatherBean constructor48 public WeatherBean( String city, String weatherDescription, 49 String cityTemperature )50 {51 cityName = city;52 temperature = cityTemperature;53 description = weatherDescription.trim();54 55 URL url = WeatherBean.class.getResource( "images/" + 56 imageNames.getProperty( description, "noinfo.jpg" ) ); 57 58 // get weather image name or noinfo.jpg if weather 59 // description not found60 image = new ImageIcon( url );61 }62 63 // get city name64 public String getCityName() 65 { 66 return cityName; 67 }68

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.3 WeatherBean stores weather forecast for one city.

69 // get temperature70 public String getTemperature() 71 {72 return temperature; 73 }74 75 // get weather description76 public String getDescription() 77 {78 return description; 79 }80 81 // get weather image82 public ImageIcon getImage() 83 { 84 return image; 85 }86 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.4 WeatherServiceClient client for WeatherService remote object.

Line 24

Lines 27-28

Lines 31-32

1 // WeatherServiceClient.java 2 // WeatherServiceClient uses the WeatherService remote object3 // to retrieve weather information.4 package com.deitel.advjhtp1.rmi.weather;5 6 // Java core packages7 import java.rmi.*; 8 import java.util.*;9 10 // Java extension packages11 import javax.swing.*;12 13 public class WeatherServiceClient extends JFrame14 {15 // WeatherServiceClient constructor16 public WeatherServiceClient( String server ) 17 {18 super( "RMI WeatherService Client" ); 19 20 // connect to server and get weather information21 try {22 23 // name of remote server object bound to rmi registry24 String remoteName = "rmi://" + server + "/WeatherService";25 26 // lookup WeatherServiceImpl remote object27 WeatherService weatherService = 28 ( WeatherService ) Naming.lookup( remoteName );29 30 // get weather information from server31 List weatherInformation = 32 weatherService.getWeatherInformation(); 33

Creates a String that contains the URL for this remote object.

Invoke Naming’s static method lookup to obtain a remote reference to the WeatherService remote object at the specified URL.

Invoke remote method getWeatherInformation on the weatherService remote reference.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.4 WeatherServiceClient client for WeatherService remote object.

Lines 35-36

Line 40

Line 68

34 // create WeatherListModel for weather information35 ListModel weatherListModel = 36 new WeatherListModel( weatherInformation );37 38 // create JList, set ListCellRenderer and add to layout39 JList weatherJList = new JList( weatherListModel );40 weatherJList.setCellRenderer( new WeatherCellRenderer());41 getContentPane().add( new JScrollPane( weatherJList ) );42 43 } // end try44 45 // handle exception connecting to remote server46 catch ( ConnectException connectionException ) {47 System.err.println( "Connection to server failed. " +48 "Server may be temporarily unavailable." );49 50 connectionException.printStackTrace();51 }52 53 // handle exceptions communicating with remote object54 catch ( Exception exception ) {55 exception.printStackTrace();56 }57 58 } // end WeatherServiceClient constructor59 60 // execute WeatherServiceClient61 public static void main( String args[] )62 {63 WeatherServiceClient client = null;64 65 // if no sever IP address or host name specified,66 // use "localhost"; otherwise use specified host67 if ( args.length == 0 )68 client = new WeatherServiceClient( "localhost" );

Create a WeatherListModel to facilitate displaying the weather information in a JList.

Sets a ListCellRenderer for the JList.

Creates a new WeatherServiceClient that connects to an RMI registry running on localhost.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.4 WeatherServiceClient client for WeatherService remote object.

69 else70 client = new WeatherServiceClient( args[ 0 ] );71 72 // configure and display application window73 client.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );74 client.pack(); 75 client.setResizable( false ); 76 client.setVisible( true ); 77 }78 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.5 WeatherListModel is a ListModel implementation for storing weather information.

1 // WeatherListModel.java2 // WeatherListModel extends AbstractListModel to provide a 3 // ListModel for storing a List of WeatherBeans.4 package com.deitel.advjhtp1.rmi.weather;5 6 // Java core packages7 import java.util.*;8 9 // Java extension packages10 import javax.swing.AbstractListModel;11 12 public class WeatherListModel extends AbstractListModel {13 14 // List of elements in ListModel15 private List list;16 17 // no-argument WeatherListModel constructor18 public WeatherListModel()19 {20 // create new List for WeatherBeans21 list = new ArrayList();22 }23 24 // WeatherListModel constructor25 public WeatherListModel( List elementList ) 26 {27 list = elementList;28 }29 30 // get size of List31 public int getSize() 32 {33 return list.size();34 }35

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.5 WeatherListModel is a ListModel implementation for storing weather information.

36 // get Object reference to element at given index37 public Object getElementAt( int index ) 38 {39 return list.get( index );40 }41 42 // add element to WeatherListModel43 public void add( Object element )44 {45 list.add( element );46 fireIntervalAdded( this, list.size(), list.size() );47 }48 49 // remove element from WeatherListModel50 public void remove( Object element )51 {52 int index = list.indexOf( element );53 54 if ( index != -1 ) {55 list.remove( element );56 fireIntervalRemoved( this, index, index );57 }58 59 } // end method remove60 61 // remove all elements from WeatherListModel62 public void clear()63 {64 // get original size of List65 int size = list.size();66 67 // clear all elements from List68 list.clear();69

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.5 WeatherListModel is a ListModel implementation for storing weather information.

70 // notify listeners that content changed71 fireContentsChanged( this, 0, size );72 }73 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.6 WeatherCellRenderer is a custom ListCellRenderer for displaying WeatherBeans in a JList.

1 // WeatherCellRenderer.java2 // WeatherCellRenderer is a custom ListCellRenderer for 3 // WeatherBeans in a JList.4 package com.deitel.advjhtp1.rmi.weather;5 6 // Java core packages7 import java.awt.*;8 9 // Java extension packages10 import javax.swing.*;11 12 public class WeatherCellRenderer extends DefaultListCellRenderer {13 14 // returns a WeatherItem object that displays city's weather15 public Component getListCellRendererComponent( JList list, 16 Object value, int index, boolean isSelected, boolean focus )17 {18 return new WeatherItem( ( WeatherBean ) value );19 }20 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.7 WeatherItem displays weather information for one city.

Lines 22-29

1 // WeatherItem.java2 // WeatherItem displays a city's weather information in a JPanel.3 package com.deitel.advjhtp1.rmi.weather;4 5 // Java core packages6 import java.awt.*;7 import java.net.*;8 import java.util.*;9 10 // Java extension packages11 import javax.swing.*;12 13 public class WeatherItem extends JPanel { 14 15 private WeatherBean weatherBean; // weather information16 17 // background ImageIcon18 private static ImageIcon backgroundImage;19 20 // static initializer block loads background image when class21 // WeatherItem is loaded into memory22 static {23 24 // get URL for background image25 URL url = WeatherItem.class.getResource( "images/back.jpg" );26 27 // background image for each city's weather info28 backgroundImage = new ImageIcon( url );29 }30 31 // initialize a WeatherItem32 public WeatherItem( WeatherBean bean )33 {34 weatherBean = bean;35 }

The static block loads the ImageIcon backgroundImage into memory when the virtual machine loads the WeatherItem class itself.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.7 WeatherItem displays weather information for one city.

Lines 38-56

36 37 // display information for city's weather38 public void paintComponent( Graphics g )39 {40 super.paintComponent( g );41 42 // draw background43 backgroundImage.paintIcon( this, g, 0, 0 );44 45 // set font and drawing color,46 // then display city name and temperature47 Font font = new Font( "SansSerif", Font.BOLD, 12 );48 g.setFont( font );49 g.setColor( Color.white );50 g.drawString( weatherBean.getCityName(), 10, 19 );51 g.drawString( weatherBean.getTemperature(), 130, 19 );52 53 // display weather image54 weatherBean.getImage().paintIcon( this, g, 253, 1 );55 56 } // end method paintComponent57 58 // make WeatherItem's preferred size the width and height of59 // the background image60 public Dimension getPreferredSize()61 {62 return new Dimension( backgroundImage.getIconWidth(),63 backgroundImage.getIconHeight() );64 }65 }

Draws the backgroundImage, the city name, the temperature and the WeatherBean’s ImageIcon.

2002 Prentice Hall. All rights reserved.

13.5 Compiling and Executing the Server and the Client

• Compile the remote object class – Generate a stub class using rmic compiler

• Start the RMI registry

• Run the WeatherServiceImpl application

• Run the WeatherServiceClient application

2002 Prentice Hall. All rights reserved.

13.5 Compiling and Executing the Server Client (Cont.)

Fig. 13.10 WeatherServiceClient application window.

2002 Prentice Hall. All rights reserved.

13.6 Case Study: Deitel Messenger with Activatable Server

• Standard RMI objects– Run continuously on the server

• Activatable RMI objects– Invoked by client

– Persistent

– RMI activation daemon (rmid)

2002 Prentice Hall. All rights reserved.

13.6 Case Study: Deitel Messenger with Activatable Sever (Cont.)

Name Role ChatServer Remote interface through which clients register for a

chat, leave a chat, and post chat messages. StoppableChatServer Administrative remote interface for terminating the

chat server. ChatServerImpl Implementation of the ChatServer remote interface that

provides an RMI-based chat server. ChatServerAdministrator Utility program for launching and terminating the

activatable ChatServer. ChatClient Remote interface through which the ChatServer

communicates with clients. ChatMessage Serializable object for sending messages

between ChatServer and ChatClients. MessageManager Interface that defines methods for managing

communication between the client’s user interface and the ChatServer.

RMIMessageManager ChatClient and MessageManager implementation for managing communication between the client and the ChatServer.

MessageListener Interface for classes that wish to receive new chat messages.

DisconnectListener Interface for classes that wish to receive notifications when the server disconnects.

ClientGUI GUI for sending and receiving chat messages using a MessageManager.

DeitelMessenger Application launcher for Deitel Messenger client. Fig. 13.11 Participants of DeitelMessenger case study.

2002 Prentice Hall. All rights reserved.

13.6.1 Activatable Deitel Messenger ChatServer

• Remote interface• Activatable remote object implementation• Utility program for registering and unregistering

remote object

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.12 ChatServer remote interface for Deitel Messenger chat server.

Line 13

Lines 16-17

Lines 20-21

Lines 24-25

1 // ChatServer.java2 // ChatServer is a remote interface that defines how a client 3 // registers for a chat, leaves a chat and posts chat messages.4 package com.deitel.messenger.rmi.server;5 6 // Java core packages7 import java.rmi.*;8 9 // Deitel packages10 import com.deitel.messenger.rmi.ChatMessage;11 import com.deitel.messenger.rmi.client.ChatClient;12 13 public interface ChatServer extends Remote {14 15 // register new ChatClient with ChatServer16 public void registerClient( ChatClient client )17 throws RemoteException;18 19 // unregister ChatClient with ChatServer20 public void unregisterClient( ChatClient client )21 throws RemoteException;22 23 // post new message to ChatServer24 public void postMessage( ChatMessage message ) 25 throws RemoteException;26 }

Declares that interface ChatServer extends interface Remote, which RMI requires for all remote interface.Enables a ChartClient to register

with the ChatServer and take part in the chat session.Enables clients to remove themselves from the chat session.

Enables clients to post new messages to the chat session.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.13 StoppableChatServer remote interface for stopping a ChatServer remote object.

1 // StoppableChatServer.java2 // StoppableChatServer is a remote interface that provides a 3 // mechansim to terminate the chat server.4 package com.deitel.messenger.rmi.server;5 6 // Java core packages7 import java.rmi.*;8 9 public interface StoppableChatServer extends Remote {10 11 // stop ChatServer12 public void stopServer() throws RemoteException;13 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.14 ChatServerImpl implementation of remote interfaces ChatServer and StoppableChatServer as Activatable remote objects.

Line 23

Line 33

1 // ChatServerImpl.java2 // ChatServerImpl implements the ChatServer remote interface3 // to provide an RMI-based chat server.4 package com.deitel.messenger.rmi.server;5 6 // Java core packages7 import java.io.*;8 import java.net.*;9 import java.rmi.*;10 import java.rmi.activation.*;11 import java.rmi.server.*;12 import java.rmi.registry.*;13 import java.util.*;14 15 // Deitel packages16 import com.deitel.messenger.rmi.ChatMessage;17 import com.deitel.messenger.rmi.client.ChatClient;18 19 public class ChatServerImpl extends Activatable 20 implements ChatServer, StoppableChatServer {21 22 // Set of ChatClient references23 private Set clients = new HashSet();24 25 // server object's name26 private String serverObjectName;27 28 // ChatServerImpl constructor29 public ChatServerImpl( ActivationID id, MarshalledObject data )30 throws RemoteException {31 32 // register activatable object and export on anonymous port33 super( id, 0 );34 }35

Creates a Set for maintaining remote references to registered ChatClients.

Invokes the superclass constructor to complete activation.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.14 ChatServerImpl implementation of remote interfaces ChatServer and StoppableChatServer as Activatable remote objects.

Lines 42-43

Lines 52-53

Line 57

Line 64

36 // register ChatServerImpl object with RMI registry.37 public void register( String rmiName ) throws RemoteException,38 IllegalArgumentException, MalformedURLException39 {40 // ensure registration name was provided41 if ( rmiName == null )42 throw new IllegalArgumentException( 43 "Registration name cannot be null" );44 45 serverObjectName = rmiName;46 47 // bind ChatServerImpl object to RMI registry48 try {49 50 // create RMI registry51 System.out.println( "Creating registry ..." );52 Registry registry = 53 LocateRegistry.createRegistry( 1099 );54 55 // bind RMI object to default RMI registry56 System.out.println( "Binding server to registry ..." );57 registry.rebind( serverObjectName, this );58 } 59 60 // if registry already exists, bind to existing registry61 catch ( RemoteException remoteException ) {62 System.err.println( "Registry already exists. " +63 "Binding to existing registry ..." );64 Naming.rebind( serverObjectName, this ); 65 }66 67 System.out.println( "Server bound to registry" );68 69 } // end method register70

Throw an IllegalArgumentException if the provided name for the remote object is null.

Use static method createRegistry of class LocateRegistry to create a new Registry on the local machine at port 1099.

Invokes method rebind of class Registry to bind the activatable object to the Registry.

Invokes static method rebind of class Naming to bind the remote object to the existing RMI registry.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.14 ChatServerImpl implementation of remote interfaces ChatServer and StoppableChatServer as Activatable remote objects.

Lines 72-82

Line 77

Lines 85-95

Lines 90

71 // register new ChatClient with ChatServer72 public void registerClient( ChatClient client ) 73 throws RemoteException 74 {75 // add client to Set of registered clients76 synchronized ( clients ) {77 clients.add( client );78 }79 80 System.out.println( "Registered Client: " + client );81 82 } // end method registerClient83 84 // unregister client with ChatServer85 public void unregisterClient( ChatClient client ) 86 throws RemoteException 87 {88 // remove client from Set of registered clients89 synchronized( clients ) {90 clients.remove( client );91 }92 93 System.out.println( "Unregistered Client: " + client );94 95 } // end method unregisterClient96 97 // post new message to chat server98 public void postMessage( ChatMessage message ) 99 throws RemoteException 100 { 101 Iterator iterator = null;102 103 // get Iterator for Set of registered clients104 synchronized( clients ) {105 iterator = new HashSet( clients ).iterator();

Method registerClient enables ChatClient remote objects to register with the ChatServer to participate in the chat session.

Adds the ChatClient remote reference to the Set of ChatClients participating in the chat session.

Enables ChatClients to leave the chat session.

Removes the given ChatClient remote reference from the Set of ChatClient references.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.14 ChatServerImpl implementation of remote interfaces ChatServer and StoppableChatServer as Activatable remote objects.

Lines 109-123

Lines 128-170

106 }107 108 // send message to every ChatClient109 while ( iterator.hasNext() ) {110 111 // attempt to send message to client112 ChatClient client = ( ChatClient ) iterator.next();113 114 try {115 client.deliverMessage( message );116 }117 118 // unregister client if exception is thrown119 catch( Exception exception ) {120 System.err.println( "Unregistering absent client." );121 unregisterClient( client );122 }123 124 } // end while loop125 126 } // end method postMessage127 128 // notify each client that server is shutting down and 129 // terminate server application130 public void stopServer() throws RemoteException131 {132 System.out.println( "Terminating server ..." );133 134 Iterator iterator = null;135 136 // get Iterator for Set of registered clients137 synchronized( clients ) {138 iterator = new HashSet( clients ).iterator();139 }140

Iterate through the Set of ChatClient references and invoke remote method deliverMessage of interface ChatClient to deliver the new ChatMessage to each client.

Implements method stopServer required by interface StoppableChatServer.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.14 ChatServerImpl implementation of remote interfaces ChatServer and StoppableChatServer as Activatable remote objects.

Lines 142-145

Lines 149-170

141 // send message to every ChatClient142 while ( iterator.hasNext() ) {143 ChatClient client = ( ChatClient ) iterator.next(); 144 client.serverStopping();145 } 146 147 // create Thread to terminate application after 148 // stopServer method returns to caller149 Thread terminator = new Thread(150 new Runnable() {151 152 // sleep for 5 seconds, print message and terminate153 public void run()154 {155 // sleep156 try {157 Thread.sleep( 5000 );158 }159 160 // ignore InterruptedExceptions161 catch ( InterruptedException exception ) { 162 }163 164 System.err.println( "Server terminated" );165 System.exit( 0 );166 }167 }168 );169 170 terminator.start(); // start termination thread171 172 } // end method stopServer173 }

Iterate through the Set of ChatClient references and invoke method serverStopping of interface ChatClient to notify each ChatClient that the server is shutting down.

Create and start a new Thread to ensure that the ChatServerAdministrator can unbind the remote object from the RMI Registry before the remote object terminates.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.15 ChatServerAdministrator application for starting and stopping the ChatServer remote object.

Lines 14-52

Lines 21-22

Lines 25-26

Lines 29-30

Line 33

1 // ChatServerAdministrator.java2 // ChatServerAdministrator is a utility program for launching3 // and terminating the Activatable ChatServer.4 package com.deitel.messenger.rmi.server;5 6 // Java core packages7 import java.rmi.*;8 import java.rmi.activation.*;9 import java.util.*;10 11 public class ChatServerAdministrator {12 13 // set up activatable server object14 private static void startServer( String policy, 15 String codebase ) throws Exception16 {17 // set up RMI security manager18 System.setSecurityManager( new RMISecurityManager() );19 20 // set security policy for ActivatableGroup JVM21 Properties properties = new Properties(); 22 properties.put( "java.security.policy", policy );23 24 // create ActivationGroupDesc for activatable object25 ActivationGroupDesc groupDesc = 26 new ActivationGroupDesc( properties, null );27 28 // register activation group with RMI activation system 29 ActivationGroupID groupID = 30 ActivationGroup.getSystem().registerGroup( groupDesc );31 32 // create activation group33 ActivationGroup.createGroup( groupID, groupDesc , 0 );34

Method startServer launches the activatable ChatServer.

Create a Properties object and add a property that specifies the policy file under which the ActivationGroup’s JVM should run.Create an ActivationGroupDesc object,

which is an activation group descriptor.

Obtain an ActivationSystem by invoking static method getSystem of class ActivationGroup.

Invokes static method createGroup of class ActivationGroup to create the ActivationGroup.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.15 ChatServerAdministrator application for starting and stopping the ChatServer remote object.

Lines 36-38

Lines 41-42

Line 46

Line 61

Line 65

Line 69

35 // activation description for ChatServerImpl36 ActivationDesc description = new ActivationDesc( 37 "com.deitel.messenger.rmi.server.ChatServerImpl", 38 codebase, null );39 40 // register description with rmid41 ChatServer server = 42 ( ChatServer ) Activatable.register( description ); 43 System.out.println( "Obtained ChatServerImpl stub" );44 45 // bind ChatServer in registry46 Naming.rebind( "ChatServer", server ); 47 System.out.println( "Bound object to registry" ); 48 49 // terminate setup program50 System.exit( 0 );51 52 } // end method startServer53 54 // terminate server55 private static void terminateServer( String hostname ) 56 throws Exception57 {58 // lookup ChatServer in RMI registry59 System.out.println( "Locating server ..." );60 StoppableChatServer server = ( StoppableChatServer ) 61 Naming.lookup( "rmi://" + hostname + "/ChatServer" );62 63 // terminate server64 System.out.println( "Stopping server ..." );65 server.stopServer();66 67 // remove ChatServer from RMI registry68 System.out.println( "Server stopped" ); 69 Naming.unbind( "rmi://" + hostname + "/ChatServer" );

Create an ActivationDesc object for the ChatServer remote object.

Invokes static method register of class Activatable to register the Activatable remote object.

Invokes static method rebind of class Naming to bind the ChatServer in the RMI Registry.

Invokes static method lookup of class Naming to obtain a remote reference to the ChatServer.

Invokes method stopServer to notify clients that the ChatServer is shutting down.

Invokes static method unbind of class Naming to remove the ChatServer remote object from the RMI Registry.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.15 ChatServerAdministrator application for starting and stopping the ChatServer remote object.

Line 80

Line 91

70 71 } // end method terminateServer72 73 // launch ChatServerAdministrator application74 public static void main( String args[] ) throws Exception75 {76 // check for stop server argument77 if ( args.length == 2 ) {78 79 if ( args[ 0 ].equals( "stop" ) )80 terminateServer( args[ 1 ] );81 82 else printUsageInstructions();83 }84 85 // check for start server argument86 else if ( args.length == 3 ) {87 88 // start server with user-provided policy, codebase89 // and Registry hostname90 if ( args[ 0 ].equals( "start" ) )91 startServer( args[ 1 ], args[ 2 ] );92 93 else printUsageInstructions();94 }95 96 // wrong number of arguments provided, so print instructions97 else printUsageInstructions();98 99 } // end method main100

Invokes method terminateServer to shut down the ChatServer on the specified host if the user passes argument stop.

Invokes method startServer with the given policy file location and codebase if the user passes argument start.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.15 ChatServerAdministrator application for starting and stopping the ChatServer remote object.

101 // print instructions for running ChatServerAdministrator102 private static void printUsageInstructions()103 {104 System.err.println( "\nUsage:\n" +105 "\tjava com.deitel.messenger.rmi.server." +106 "ChatServerAdministrator start <policy> <codebase>\n" +107 "\tjava com.deitel.messenger.rmi.server." +108 "ChatServerAdministrator stop <registry hostname>" );109 }110 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.16 Policy file for ChatServer’s ActivationGroup.

1 // allow ActivationGroup to terminate the virtual machine2 grant {3 permission java.lang.RuntimePermission "exitVM";4 };

2002 Prentice Hall. All rights reserved.

13.6.2 Deitel Messenger Client Architecture and Implementation

• Communication Interfaces and Implementation• Client GUI Interfaces and Implementation

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.17 ChatClient remote interface to enable RMI callbacks.

Lines 16-17

Line 20

1 // ChatClient.java2 // ChatClient is a remote interface that defines methods for a3 // chat client to receive messages and status information from4 // a ChatServer.5 package com.deitel.messenger.rmi.client;6 7 // Java core packages8 import java.rmi.*;9 10 // Deitel packages11 import com.deitel.messenger.rmi.ChatMessage;12 13 public interface ChatClient extends Remote {14 15 // method called by server to deliver message to client16 public void deliverMessage( ChatMessage message )17 throws RemoteException;18 19 // method called when server shuting down20 public void serverStopping() throws RemoteException;21 }

Enables the ChatServer to send new ChatMessages to the ChatClient.

Enables the ChatServer to notify the ChatClient when the ChatServer is shutting down.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.18 ChatMessage is a serializable class for transmitting messages over RMI.

1 // ChatMessage.java2 // ChatMessage is a Serializable object for messages in the RMI3 // ChatClient and ChatServer.4 package com.deitel.messenger.rmi;5 6 // Java core packages7 import java.io.*;8 9 public class ChatMessage implements Serializable {10 11 private String sender; // person sending message12 private String message; // message being sent13 14 // construct empty ChatMessage15 public ChatMessage() 16 { 17 this( "", "" ); 18 }19 20 // construct ChatMessage with sender and message values21 public ChatMessage( String sender, String message )22 {23 setSender( sender );24 setMessage( message );25 }26 27 // set name of person sending message28 public void setSender( String name ) 29 { 30 sender = name; 31 }32

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.18 ChatMessage is a serializable class for transmitting messages over RMI.

33 // get name of person sending message 34 public String getSender() 35 { 36 return sender; 37 }38 39 // set message being sent40 public void setMessage( String messageBody ) 41 { 42 message = messageBody; 43 }44 45 // get message being sent46 public String getMessage() 47 { 48 return message; 49 } 50 51 // String representation of ChatMessage52 public String toString() 53 {54 return getSender() + "> " + getMessage();55 }56 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.19 MessageManager interface for classes that implement communication logic for a ChatClient.

Lines 10-11

Liness 15-16

Lines 19-20

Lines 23-24

1 // MessageManager.java2 // MessageManger is an interface for objects capable of managing3 // communications with a message server.4 package com.deitel.messenger;5 6 public interface MessageManager { 7 8 // connect to message server and route incoming messages9 // to given MessageListener10 public void connect( MessageListener listener ) 11 throws Exception;12 13 // disconnect from message server and stop routing14 // incoming messages to given MessageListener15 public void disconnect( MessageListener listener )16 throws Exception;17 18 // send message to message server19 public void sendMessage( String from, String message )20 throws Exception; 21 22 // set listener for disconnect notifications23 public void setDisconnectListener( 24 DisconnectListener listener );25 }

Connects to the ChatServer and takes as an argument the MessageListener to which the MessageManager should deliver new incoming messages.

Disconnects the MessageManager from the ChatServer and stops routing messages to the given MessageListener.Sends a message to

the ChatServer.

Registers a DisconnectListener to be notified when the ChatServer disconnects the client.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.20 RMIMessageManager remote object and MessageManager implementation for managing Chatclient communication.

1 // RMIMessageManager.java2 // RMIMessageManager implements the ChatClient remote interface3 // and manages incoming and outgoing chat messages using RMI.4 package com.deitel.messenger.rmi.client;5 6 // Java core packages7 import java.awt.*;8 import java.awt.event.*;9 import java.rmi.*;10 import java.rmi.server.*;11 import java.util.*;12 13 // Deitel packages14 import com.deitel.messenger.*;15 import com.deitel.messenger.rmi.*;16 import com.deitel.messenger.rmi.server.ChatServer;17 18 public class RMIMessageManager extends UnicastRemoteObject 19 implements ChatClient, MessageManager {20 21 // listeners for incoming messages and disconnect notifications22 private MessageListener messageListener;23 private DisconnectListener disconnectListener;24 25 private String serverAddress;26 private ChatServer chatServer;27 28 // RMIMessageManager constructor29 public RMIMessageManager( String server ) throws RemoteException30 { 31 serverAddress = server;32 }33

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.20 RMIMessageManager remote object and MessageManager implementation for managing Chatclient communication.

Lines 39-40

Line 43

Line 58

34 // connect to ChatServer35 public void connect( MessageListener listener ) 36 throws Exception37 { 38 // look up ChatServer remote object39 chatServer = ( ChatServer ) Naming.lookup(40 "//" + serverAddress + "/ChatServer" );41 42 // register with ChatServer to receive messages43 chatServer.registerClient( this );44 45 // set listener for incoming messages46 messageListener = listener;47 48 } // end method connect49 50 // disconnect from ChatServer51 public void disconnect( MessageListener listener ) 52 throws Exception53 {54 if ( chatServer == null ) 55 return;56 57 // unregister with ChatServer58 chatServer.unregisterClient( this );59 60 // remove references to ChatServer and MessageListener61 chatServer = null;62 messageListener = null;63 64 } // end method disconnect65

Invoke static method lookup of class Naming to retrieve a remote reference to the ChatServer.

Passes the this reference as the argument to method registerClient.

Invokes method unregisterClient of remote interface ChatServer to unregister the RMIMessageManager from the ChatServer.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.20 RMIMessageManager remote object and MessageManager implementation for managing Chatclient communication.

Lines 74-75

Line 78

Lines 87-88

Line 95

66 // send ChatMessage to ChatServer67 public void sendMessage( String fromUser, String message ) 68 throws Exception69 {70 if ( chatServer == null )71 return;72 73 // create ChatMessage with message text and userName74 ChatMessage chatMessage = 75 new ChatMessage( fromUser, message );76 77 // post message to ChatServer78 chatServer.postMessage( chatMessage );79 80 } // end method sendMessage 81 82 // process delivery of ChatMessage from ChatServer83 public void deliverMessage( ChatMessage message ) 84 throws RemoteException85 {86 if ( messageListener != null )87 messageListener.messageReceived( message.getSender(), 88 message.getMessage() );89 } 90 91 // method called when server shutting down92 public void serverStopping() throws RemoteException 93 {94 chatServer = null;95 fireServerDisconnected( "Server shut down." );96 }97

Create a new ChatMessage object to obtain the user name from whom the message came and the message body.Invokes method postMessage

of remote interface ChatServer to post the new ChatMessage to the ChatServer.

Invoke method messageReceived of interface MessageListener to notify the MessageListener of the incoming ChatMessage.

Invokes method fireServerDisconnected of class RMIMessageManager to notify the registered DisconnectListener that the ChatServer has disconnected the ChatClient.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.20 RMIMessageManager remote object and MessageManager implementation for managing Chatclient communication.

Lines 99-103

Lines 106-110

98 // register listener for disconnect notifications99 public void setDisconnectListener( 100 DisconnectListener listener )101 {102 disconnectListener = listener;103 }104 105 // send disconnect notification106 private void fireServerDisconnected( String message )107 {108 if ( disconnectListener != null )109 disconnectListener.serverDisconnected( message );110 }111 }

Enables a DisconnectListener to register for notifications when the ChatServer disconnects the client.

Sends serverDisconnected messages to the DisconnectListener.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.21 MessageListener interface for receiving new messages.

1 // MessageListener.java2 // MessageListener is an interface for classes that wish to3 // receive new chat messages.4 package com.deitel.messenger;5 6 public interface MessageListener {7 8 // receive new chat message9 public void messageReceived( String from, String message );10 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.22 DisconnectListener interface for receiving server disconnect notifications.

1 // DisconnectListener.java2 // DisconnectListener defines method serverDisconnected, which3 // indicates that the server has disconnected the client. 4 package com.deitel.messenger;5 6 public interface DisconnectListener {7 8 // receive notification that server disconnected9 public void serverDisconnected( String message );10 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

1 // ClientGUI.java2 // ClientGUI provides a GUI for sending and receiving 3 // chat messages using a MessageManager.4 package com.deitel.messenger;5 6 // Java core packages7 import java.awt.*;8 import java.awt.event.*;9 import java.util.*;10 11 // Java extension packages12 import javax.swing.*;13 import javax.swing.border.*;14 import javax.swing.text.*;15 16 public class ClientGUI extends JFrame {17 18 // JLabel for displaying connection status19 private JLabel statusBar;20 21 // JTextAreas for displaying and inputting messages 22 private JTextArea messageArea;23 private JTextArea inputArea; 24 25 // Actions for connecting and disconnecting MessageManager 26 // and sending messages27 private Action connectAction;28 private Action disconnectAction;29 private Action sendAction;30 31 // userName to add to outgoing messages32 private String userName = "";33 34 // MessageManager for communicating with server35 MessageManager messageManager;

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 41-141

36 37 // MessageListener for receiving new messages38 MessageListener messageListener;39 40 // ClientGUI constructor41 public ClientGUI( MessageManager manager )42 { 43 super( "Deitel Messenger" ); 44 45 messageManager = manager;46 47 messageListener = new MyMessageListener();48 49 // create Actions50 connectAction = new ConnectAction();51 disconnectAction = new DisconnectAction();52 disconnectAction.setEnabled( false );53 sendAction = new SendAction();54 sendAction.setEnabled( false );55 56 // set up File menu57 JMenu fileMenu = new JMenu ( "File" ); 58 fileMenu.setMnemonic( 'F' );59 fileMenu.add( connectAction );60 fileMenu.add( disconnectAction );61 62 // set up JMenuBar and attach File menu63 JMenuBar menuBar = new JMenuBar();64 menuBar.add ( fileMenu ); 65 setJMenuBar( menuBar ); 66 67 // set up JToolBar68 JToolBar toolBar = new JToolBar();69 toolBar.add( connectAction );70 toolBar.add( disconnectAction );

The constructor creates and lays out the various user interface components.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

71 72 // create JTextArea for displaying messages 73 messageArea = new JTextArea( 15, 15 ); 74 75 // disable editing and wrap words at end of line76 messageArea.setEditable( false );77 messageArea.setLineWrap( true );78 messageArea.setWrapStyleWord( true );79 80 JPanel panel = new JPanel();81 panel.setLayout( new BorderLayout( 5, 5 ) );82 panel.add( new JScrollPane( messageArea ), 83 BorderLayout.CENTER );84 85 // create JTextArea for entering new messages86 inputArea = new JTextArea( 3, 15 );87 inputArea.setLineWrap( true );88 inputArea.setWrapStyleWord( true );89 inputArea.setEditable( false );90 91 // map Enter key in inputArea to sendAction92 Keymap keyMap = inputArea.getKeymap();93 KeyStroke enterKey = KeyStroke.getKeyStroke( 94 KeyEvent.VK_ENTER, 0 );95 keyMap.addActionForKeyStroke( enterKey, sendAction );96 97 // lay out inputArea and sendAction JButton in BoxLayout 98 // and add Box to messagePanel99 Box box = new Box( BoxLayout.X_AXIS );100 box.add( new JScrollPane( inputArea ) );101 box.add( new JButton( sendAction ) );102 103 panel.add( box, BorderLayout.SOUTH );104

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 119-138

105 // create statusBar JLabel with recessed border106 statusBar = new JLabel( "Not Connected" );107 statusBar.setBorder( 108 new BevelBorder( BevelBorder.LOWERED ) );109 110 // lay out components111 Container container = getContentPane();112 container.add( toolBar, BorderLayout.NORTH );113 container.add( panel, BorderLayout.CENTER );114 container.add( statusBar, BorderLayout.SOUTH );115 116 // disconnect and exit if user closes window117 addWindowListener(118 119 new WindowAdapter() {120 121 // disconnect MessageManager when window closes122 public void windowClosing( WindowEvent event ) 123 {124 // disconnect from chat server125 try {126 messageManager.disconnect( messageListener );127 }128 129 // handle exception disconnecting from server130 catch ( Exception exception ) {131 exception.printStackTrace();132 }133 134 System.exit( 0 );135 136 } // end method windowClosing137 138 } // end WindowAdapter inner class139 );

A WindowAdapter inner class ensures that the MessageManager disconnects from the ChatServer when the user closes the application window.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 144-205

Lines 170-174

140 141 } // end ClientGUI constructor142 143 // Action for connecting to server144 private class ConnectAction extends AbstractAction {145 146 // configure ConnectAction 147 public ConnectAction() 148 {149 putValue( Action.NAME, "Connect" );150 putValue( Action.SMALL_ICON, new ImageIcon( 151 ClientGUI.class.getResource( 152 "images/Connect.gif" ) ) );153 putValue( Action.SHORT_DESCRIPTION, 154 "Connect to Server" );155 putValue( Action.LONG_DESCRIPTION, 156 "Connect to server to send Instant Messages" );157 putValue( Action.MNEMONIC_KEY, new Integer( 'C' ) );158 }159 160 // connect to server161 public void actionPerformed( ActionEvent event ) 162 { 163 // connect MessageManager to server164 try { 165 166 // clear messageArea167 messageArea.setText( "" ); 168 169 // connect MessageManager and register MessageListener170 messageManager.connect( messageListener );171 172 // listen for disconnect notifications173 messageManager.setDisconnectListener( 174 new DisconnectHandler() );

Inner class implements an Action for connecting to the Deitel Messenger server.Sends serverDisconnected messages to the DisconnectListener.

Invoke method connect of interface MessageManager and register a DisconnectListener for receiving serverDisconnected notifications.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 177-186

Lines 188-189

175 176 // get desired userName177 userName = JOptionPane.showInputDialog( 178 ClientGUI.this, "Please enter your name: " );179 180 // update Actions, inputArea and statusBar181 connectAction.setEnabled( false );182 disconnectAction.setEnabled( true );183 sendAction.setEnabled( true );184 inputArea.setEditable( true );185 inputArea.requestFocus(); 186 statusBar.setText( "Connected: " + userName ); 187 188 // send message indicating user connected189 messageManager.sendMessage( userName, userName + 190 " joined chat" );191 192 } // end try193 194 // handle exception connecting to server195 catch ( Exception exception ) {196 JOptionPane.showMessageDialog( ClientGUI.this,197 "Unable to connect to server.", "Error Connecting",198 JOptionPane.ERROR_MESSAGE );199 200 exception.printStackTrace();201 }202 203 } // end method actionPerformed 204 205 } // end ConnectAction inner class206 207 // Action for disconnecting from server208 private class DisconnectAction extends AbstractAction {209

Prompt the user for a name to use in the chat session and update the user-interface components to allow the user to send messages and disconnect from the Deitel Messenger server.

Invoke method sendMessage of interface MessageManager to send a ChatMessage that announces the user’s arrival in the chat session.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 211-258

Lines 231-232

Line 236

Lines 239-243

210 // configure DisconnectAction211 public DisconnectAction()212 {213 putValue( Action.NAME, "Disconnect" );214 putValue( Action.SMALL_ICON, new ImageIcon( 215 ClientGUI.class.getResource( 216 "images/Disconnect.gif" ) ) );217 putValue( Action.SHORT_DESCRIPTION, 218 "Disconnect from Server" );219 putValue( Action.LONG_DESCRIPTION, 220 "Disconnect to end Instant Messaging session" );221 putValue( Action.MNEMONIC_KEY, new Integer( 'D' ) );222 }223 224 // disconnect from server225 public void actionPerformed( ActionEvent event ) 226 { 227 // disconnect MessageManager from server228 try {229 230 // send message indicating user disconnected231 messageManager.sendMessage( userName, userName + 232 " exited chat" );233 234 // disconnect from server and unregister 235 // MessageListener236 messageManager.disconnect( messageListener ); 237 238 // update Actions, inputArea and statusBar239 sendAction.setEnabled( false );240 disconnectAction.setEnabled( false );241 inputArea.setEditable( false );242 connectAction.setEnabled( true );243 statusBar.setText( "Not Connected" );244

Inner class implements an Action for disconnecting the MessageManager from the Deitel Messenger server.

Send a ChatMessage to announce the user’s departure from the chat session.

Invokes method disconnect of interface MessageManager to disconnect from the server.

Update the user-interface components to disable the message inputArea and display a message in the status bar.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 261-299

245 } // end try246 247 // handle exception disconnecting from server248 catch ( Exception exception ) {249 JOptionPane.showMessageDialog( ClientGUI.this,250 "Unable to disconnect from server.", 251 "Error Disconnecting", JOptionPane.ERROR_MESSAGE );252 253 exception.printStackTrace();254 } 255 256 } // end method actionPerformed257 258 } // end DisconnectAction inner class259 260 // Action for sending messages261 private class SendAction extends AbstractAction {262 263 // configure SendAction264 public SendAction()265 {266 putValue( Action.NAME, "Send" ) ;267 putValue( Action.SMALL_ICON, new ImageIcon( 268 ClientGUI.class.getResource( "images/Send.gif" ) ) );269 putValue( Action.SHORT_DESCRIPTION, "Send Message" );270 putValue( Action.LONG_DESCRIPTION, 271 "Send an Instant Message" );272 putValue( Action.MNEMONIC_KEY, new Integer( 'S' ) ); 273 }274

Inner class implements an Action for sending messages to the server.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 282-283

Lines 304-315

275 // send message and clear inputArea276 public void actionPerformed( ActionEvent event ) 277 {278 // send message to server279 try {280 281 // send userName and text in inputArea282 messageManager.sendMessage( userName, 283 inputArea.getText() );284 285 inputArea.setText( "" );286 }287 288 // handle exception sending message289 catch ( Exception exception ) {290 JOptionPane.showMessageDialog( ClientGUI.this,291 "Unable to send message.", "Error Sending Message", 292 JOptionPane.ERROR_MESSAGE ); 293 294 exception.printStackTrace();295 } 296 297 } // end method actionPerformed298 299 } // end SendAction inner class300 301 // MyMessageListener listens for new messages from the302 // MessageManager and displays the messages in messageArea303 // using a MessageDisplayer.304 private class MyMessageListener implements MessageListener {305 306 // when new message received, display in messageArea307 public void messageReceived( String from, String message ) 308 {

Invoke method sendMessage of interface MessageManager and pass the contents of inputArea and the user’s userName as arguments.

Inner class listens for incoming ChatMessages.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 311-312

Lines 321-346

Lines 337-338

Lines 342-343

309 // append message using MessageDisplayer and invokeLater 310 // to ensure thread-safe access to messageArea311 SwingUtilities.invokeLater( 312 new MessageDisplayer( from, message ) );313 } 314 315 } // end MyMessageListener inner class 316 317 // MessageDisplayer displays a new messaage by appending318 // the message to the messageArea JTextArea. This Runnable 319 // object should be executed only on the event-dispatch 320 // thread, as it modifies a live Swing component.321 private class MessageDisplayer implements Runnable {322 323 private String fromUser;324 private String messageBody;325 326 // MessageDisplayer constructor327 public MessageDisplayer( String from, String body )328 {329 fromUser = from;330 messageBody = body;331 }332 333 // display new message in messageArea334 public void run() 335 {336 // append new message337 messageArea.append( "\n" + fromUser + "> " + 338 messageBody ); 339 340 // move caret to end of messageArea to ensure new 341 // message is visible on screen342 messageArea.setCaretPosition( 343 messageArea.getText().length() );

Invoke static method invokeLater of class SwingUtilities with a MessageDisplayer argument to display the new message.

Inner class MessageDisplayer is a Runnable implementation that appends a new message to the messageArea JTextArea to display that message to the user.

Append the message text and sender’s user name to messageArea.

Move the cursor to the end of messageArea.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.23 ClientGUI provides a graphical user interface for the Deitel Messenger client.

Lines 350-375

Lines 356-371

344 } 345 346 } // end MessageDisplayer inner class 347 348 // DisconnectHandler listens for serverDisconnected messages349 // from the MessageManager and updates the user interface.350 private class DisconnectHandler implements DisconnectListener {351 352 // receive disconnect notifcation353 public void serverDisconnected( final String message ) 354 {355 // update GUI in thread-safe manner356 SwingUtilities.invokeLater( 357 358 new Runnable() {359 360 // update Actions, inputs and status bar361 public void run() 362 { 363 sendAction.setEnabled( false );364 disconnectAction.setEnabled( false );365 inputArea.setEditable( false );366 connectAction.setEnabled( true );367 statusBar.setText( message );368 }369 370 } // end Runnable inner class371 );372 373 } // end method serverDisconnected 374 375 } // end DisconnectHandler inner class376 }

Inner class receives serverDisconnected notifications from the MessageManager when the server disconnects.

Update the user-interface components to indicate that the server disconnected.

2002 Prentice Hall. All rights reserved.

13.6.3 Running the Deitel Messenger Server and Client Application

• Running the Deitel Messenger case study– RMI registry

• rmiregistry

– RMI activation daemon• rmid –J-Djava.security.policy=rmid.policy

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.24 DeitelMessenger launches a chat client using classes ClientGUI and RMIMessageManager.

1 // DeitelMessenger.java2 // DeitelMessenger uses a ClientGUI and RMIMessageManager to3 // implement an RMI-based chat client.4 package com.deitel.messenger.rmi.client;5 6 // Java core packages7 import java.rmi.RMISecurityManager;8 9 // Deitel packages10 import com.deitel.messenger.*;11 12 public class DeitelMessenger {13 14 // launch DeitelMessenger application15 public static void main ( String args[] ) throws Exception 16 { 17 // install RMISecurityManager18 System.setSecurityManager( new RMISecurityManager() );19 20 MessageManager messageManager;21 22 // create new DeitelMessenger23 if ( args.length == 0 )24 messageManager = new RMIMessageManager( "localhost" );25 else26 messageManager = new RMIMessageManager( args[ 0 ] ); 27 28 // finish configuring window and display it29 ClientGUI clientGUI = new ClientGUI( messageManager );30 clientGUI.pack();31 clientGUI.setResizable( false );32 clientGUI.setVisible( true ); 33 }34 }

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.25 Policy file for the RMI activation daemon.

1 // allow ActivationGroup to specify C:\activationGroup.policy 2 // as its VM’s security policy3 grant {4 permission com.sun.rmi.rmid.ExecOptionPermission5 "-Djava.security.policy=file:///C:/activationGroup.policy";6 };

2002 Prentice Hall. All rights reserved.

13.6.3 Running the Deitel Messenger and Client Applications (Cont.)

Directory File Name com\deitel\messenger\rmi\server\

ChatServer.class ChatServerImpl.class ChatServerImpl$1.class ChatServerImpl_Stub.class StoppableChatServer.class com\deitel\messenger\rmi\client\ ChatClient.class RMIMessageManager_Stub.class com\deitel\messenger\rmi\ ChatMessage.class Fig. 13.26 File listing for the HTTP server’s download directory.

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.27 Policy file for ChatServerAdministrator.

1 // allow ChatServerAdministrator to connect to2 // activation daemon3 grant {4 permission java.net.SocketPermission "hostname:1024-", 5 "connect, accept, resolve";6 7 permission java.lang.RuntimePermission "setFactory";8 };

2002 Prentice Hall.All rights reserved.

Outline

Fig. 13.28 Policy file for the DeitelMessenger client.

1 // allow client to connect to network resources on hostname2 // at ports above 10243 grant {4 permission java.net.SocketPermission "hostname:1024-", 5 "connect, accept, resolve";6 };

2002 Prentice Hall. All rights reserved.

13.6.3 Running the Deitel Messenger Server and Client Applications (Cont.)

Fig. 13.29 Sample conversation using Deitel Messenger.

2002 Prentice Hall. All rights reserved.

13.6.3 Running the Deitel Messenger Server and Client Applications

Fig. 13.29 Sample conversation using Deitel Messenger.

2002 Prentice Hall. All rights reserved.

13.6.3 Running the Deitel Messenger Server and Client Applications

Fig. 13.29 Sample conversation using Deitel Messenger.