Case Study: Creating a Distributed System
with RMI
• Four major steps
– Define remote interface
• Describes client/server communication
– Define server application to implement remote interface
• Same name as remote interface, ends with Impl
– Define client application that uses remote interface reference
• Interacts with server implementation
– Compile and execute server and client
Defining the Remote Interface
• First step
– Define remote interface that describes remote methods
• Client calls remote methods, server implements them
• To create a remote interface
– Define interface that extends interface Remote
([Link])
• Tagging interface - no methods to define
• An object of a class that implements interface Remote directly
or indirectly is a remote object and can be accesses from any
JVM.
– Each method in Remote interface must throw
RemoteException
• Potential network errors
Defining the Remote Interface
• Interface TemperatureServer
– Extends Remote
– Describes method getWeatherInfo
1 // Fig. 20.1: [Link]
2 // TemperatureServer interface definition
3 import [Link].*; Interface Remote in [Link]
4
5 public interface TemperatureServer extends Remote { 1. import
6 public WeatherInfo[] getWeatherInfo()
7 throws RemoteException; 1.1 extends Remote
8 }
2. getWeatherInfo
Methods in Remote interface (is a relationship)
must be able to throw a RemoteException. 2.1 throws
RemoteException
Implementing the Remote Interface
• Define TemperatureServerImpl
– Implements Remote interface TemperatureServer
– Client interacts with TemperatureServerImpl object
– Uses array of WeatherInfo objects to store data
• Copy sent to client when calls getWeatherInfo
Implementing the Remote Interface
18 public class TemperatureServerImpl extends UnicastRemoteObject
19 implements TemperatureServer {
– UnicastRemoteObject
• Provides functionality for remote objects
• Constructor exports object so it can receive remote calls
– Wait for client on anonymous port number
22 public TemperatureServerImpl() throws RemoteException
• Subclass constructors must throw RemoteExceptions
37 URL url = new URL(
38 "[Link] );
– URL object
• Contains URL for Traveler's Forecast web page
• Throws MalformedURLException
Implementing the Remote Interface
40 BufferedReader in =
41 new BufferedReader(
42 new InputStreamReader( [Link]() ) );
– Open connection to file specified by URL
– Method openStream (class URL)
• Opens network connection using Http protocol
• If successful, InputStream object returned (else
IOException)
– InputStreamReader
• Translates bytes to Unicode characters
– BufferedReader
• Buffers characters
• Method readLine
– Returns one line as a String
Implementing the Remote Interface
44 String separator = "</PRE><HR> <BR><PRE>";
47 while ( ![Link]().startsWith( separator ) )
48 ; // do nothing
– Sentinel String to find relevant part of HTML code
• readLine until sentinel found
51 String s1 =
52 "CITY WEA HI/LO WEA HI/LO";
– A string used as column head
• Second "WEA HI/LO" is for next day, we do not use
– Locate column head and get first city's info
66 inputLine = [Link](); // get first city's info
Implementing the Remote Interface
70 WeatherInfo w = new WeatherInfo(
71 [Link]( 0, 16 ),
72 [Link]( 16, 22 ),
73 [Link]( 23, 29 ) );
75 [Link]( w ); // add to Vector
– WeatherInfo objects
• City name, temperature, description of weather
– Method substring to extract data from line
• Store all WeatherInfo objects in a Vector
84 weatherInformation[ i ] =
85 ( WeatherInfo ) [Link]( i );
– Store data in WeatherInfo array
• elementAt returns Object (must be cast)
88 [Link](); // close connection to NWS server
– Close connection
Implementing the Remote Interface
116 String serverObjectName = "//localhost/TempServer";
– Name of server object
• Used by clients to connect
• //host:port/remoteObjectName
– host - computer running registry for remote objects
» Where remote object executes
– port - port number of registry on host (1099 default)
– remoteObjectName - client uses to locate object
– Registry managed by rmiregistry (located at host and
port)
• Remote objects register with it, clients use it to locate service
• localhost (same computer)
– Same as IP [Link]
Implementing the Remote Interface
112 TemperatureServerImpl temp =
113 new TemperatureServerImpl();
116 String serverObjectName = "//localhost/TempServer";
117 [Link]( serverObjectName, temp );
– static method rebind (class Naming)
• Binds object to rmiregistry
• Named //localhost/TempServer
– Name used by client
• rebind replaces any previous objects with same name
– Method bind does not
1 // Fig. 20.1: [Link]
2 // TemperatureServer interface definition
3 import [Link].*;
1. Interface
4
5 public interface TemperatureServer extends Remote { ------------------
6 public WeatherInfo[] getWeatherInfo()
7 throws RemoteException; 1. extends
8 } UnicastRemote
9 TemperatureServer interface. Object, implements
10 // Fig. 20.2: [Link] TemperatureServer
11 // TemperatureServerImpl definition
12 import [Link].*;
13 import [Link].*; 1.1 Constructor
14 import [Link].*;
Allows objects to be exported.
15 import [Link].*;
16 import [Link].*;
17
18 public class TemperatureServerImpl extends UnicastRemoteObject
19 implements TemperatureServer {
20 private WeatherInfo weatherInformation[];
21
22 public TemperatureServerImpl() throws RemoteException
23 {
24 super();
25 updateWeatherConditions(); Superclass constructor exports objects, and
26 } this constructor must be able to throw
27 RemoteException.
28 // get weather information from NWS
29 private void updateWeatherConditions()
30 throws RemoteException
31 {
32 try {
2. updateWeather
33 [Link](
URL of web site (URL object). Conditions
34 "Updating weather information..." );
35
2.1 URL
36 // Traveler's Forecast Web Page
37 URL url = new URL(
38 "[Link] ); 2.2 BufferedReader
39
40 BufferedReader in =
41 new BufferedReader( 2.3 readLine
42 new InputStreamReader( [Link]() ) );
43
44 String separator = "</PRE><HR> <BR><PRE>";
45
46 // locate first horizontal line on WebOpen
pageconnection to file.
47 InputStreamReader
while ( ![Link]().startsWith( separator ) ) formats it to Unicode
48 ; // do nothing characters, and BufferedReader buffers the
49
characters.
50 // s1 is the day format and s2 is the night format
51 String s1 =
52 "CITY WEA readLine
HI/LO WEA HI/LO";
until separator found.
53 String s2 =
54 "CITY WEA LO/HI WEA LO/HI";
55 String inputLine = "";
56
57 // locate header that begins weather information
58 do {
59 inputLine = [Link]();
60 } while (  &&
61  ); Create WeatherInfo object, add data
2.4 Locate
(substring), add to Vector. header
Loop until
62
63 blank line reached.
64 Vector cityVector = new Vector(); 2.5 Loop
65
66 inputLine = [Link](); // get first city's info
67 2.5.1 WeatherInfo
68 while (  ) {
69 // create WeatherInfo object for city
2.5.2 readLine
70 WeatherInfo w = new WeatherInfo(
71 [Link]( 0, 16 ),
72 [Link]( 16, 22 ), 2.6 WeatherInfo array
73 [Link]( 23, 29 ) );
74
75 [Link]( w ); // add to Vector
76 inputLine = [Link](); // get next city's info
77 }
78 Create WeatherInfo array, cast
79 // create array to return to client Vector elements.
80 weatherInformation =
81 new WeatherInfo[ [Link]() ];
82
83 for ( int i = 0; i < [Link]; i++ )
84 weatherInformation[ i ] =
85 ( WeatherInfo ) [Link]( i );
86
87 [Link]( "Finished Processing Data." );
88 [Link](); // close connection to NWS server
89 }
90 catch( [Link] ce ) {
91 [Link]( "Connection failed." ); 2.7 close
92 [Link]( 1 );
93 }
3. getWeatherInfo
94 catch( Exception e ) {
95 [Link]();
96 [Link]( 1 ); 4. main
97 }
98 } Return the WeatherInfo array.
4.1 temp
99
100 // implementation for TemperatureServer interface method
101 public WeatherInfo[] getWeatherInfo()
102 {
103 return weatherInformation;
104 }
105
106 public static void main( String args[] ) throws Exception
107 {
108 [Link](
109 "Initializing server: please wait." );
110
111 // create server object
112 TemperatureServerImpl temp =
113 new TemperatureServerImpl();
114
115 // bind TemperatureServerImpl object to the rmiregistry
116 String serverObjectName = "//localhost/TempServer";
117 [Link]( serverObjectName, temp );
118 [Link]( 4.2
119 "The Temperature Server is up and running." );server object. serverObjectName
Name of
120 }
121 } 4.3 rebind
rebind binds object to
rmiregistry.
1 / Fig. 20.3: [Link]
2 // WeatherInfo class definitionThis allows objects to be passed as a
3 import [Link].*; stream of bytes.
4 import [Link];
5 1. Class WeatherInfo
6 public class WeatherInfo implements Serializable { implements
7 private String cityName; Serializable
8 private String temperature;
9 private String description;
10 1. Instance variables
11 public WeatherInfo( String city, String desc, String temp )
12 { 1.1 Constructor
13 cityName = city;
14 temperature = temp;
15 description = desc; 2. Get methods
16 }
17
18 public String getCityName() { return cityName; }
19
20 public String getTemperature() { return temperature; }
21
22 public String getDescription() { return description; }
23 }
Define the client
• Next step
– Client code to get weather info from
TemperatureServerImpl
– Calls getWeatherInfo through RMI
– Graphically display weather info
• Class WeatherItem (extends JLabel) stores info about
each city
• Display name, High/low, and image (depending on conditions)
Define the client
22 private void getRemoteTemp( String ip )
26 String serverObjectName = "//" + ip + "/TempServer";
– Can specify IP address at command line (more later)
30 TemperatureServer mytemp = ( TemperatureServer )
31 [Link]( serverObjectName );
– static method lookup (class Naming)
– Returns reference to Remote object
• Cast to TemperatureServer
– Reference may be used as normal
• Only difference that copy of array returned
34 WeatherInfo weatherInfo[] = [Link]();
Define the client
40 JPanel p = new JPanel();
50 for ( int i = 0; i < [Link]; i++ ) {
51 w[ i ] = new WeatherItem( weatherInfo[ i ]
);
52 [Link]( w[ i ] );
53 }
– Add WeatherItems
• Initialize with WeatherInfo
68 public static void main( String args[] )
69 {
70 TemperatureClient gt = null;
74 if ( [Link] == 0 )
75 gt = new TemperatureClient( "localhost" );
76 else
77 gt = new TemperatureClient( args[ 0 ] );
– main
• Passes command line argument (ip) to constructor
• localhost default
Define the client
• Class WeatherItem
– extends JLabel
– static initializer block
• For complex initialization of static variables
• backgroundImage - ImageIcon, has background
• weatherImages - ImageIcon array, holds weather
images
18 static {
19 backgroundImage = new ImageIcon( "images/[Link]" );
20 weatherImages =
21 new ImageIcon[ [Link] ];
22
23 for ( int i = 0; i < [Link]; ++i )
24 weatherImages[ i ] = new ImageIcon(
25 "images/" + weatherImageNames[ i ] + ".jpg" );
26 }
Define the client
– Array of descriptions and matching array of images
• weatherConditions and weatherImages
32 public WeatherItem( WeatherInfo w )
35 weatherInfo = w;
38 for ( int i = 0; i < [Link];
++i
39 ) if ( weatherConditions[ i ].equals(
40 [Link]().trim() ) )
{
41 weather = weatherImages[ i ];
– Tests WeatherInfo object, loads proper image
1 // Fig. 20.4: [Link]
2 // TemperatureClient definition
3 import [Link].*;
4 import [Link].*;
5 import [Link].*; 1. import
6 import [Link].*;
7
8 public class TemperatureClient extends JFrame 1.1 Constructor
9 {
10 public TemperatureClient( String ip )
11 { 2. getRemoteTemp
12 super( "RMI TemperatureClient..." );
13 getRemoteTemp( ip );
14 2.1
15 setSize( 625, 567 ); serverObjectName
16 setResizable( false );
17 show(); Use ip specified at command line.
18 } 2.2 [Link]
19
20 Lookup remote object in
// obtain weather information from TemperatureServerImpl
21 // remote object registry. Returns Remote
22 private void getRemoteTemp( String ip ) reference, cast to proper
23 { type.
24 try {
25 // name of remote server object bound to rmi registry
26 String serverObjectName = "//" + ip + "/TempServer";
27
28 // lookup TemperatureServerImpl remote object
29 // in rmiregistry
30 TemperatureServer mytemp = ( TemperatureServer )
31 [Link]( serverObjectName );
32
33 // get weather information from server
34 WeatherInfo weatherInfo[] = [Link]();
35 WeatherItem w[] =
36 new WeatherItem[ [Link] ]; likegetWeatherInfo
Call2.3 regular method.
37 ImageIcon headerImage =
38 new ImageIcon( "images/[Link]" );
39 2.4 GUI
40 JPanel p = new JPanel();
41
42 // determine number of rows for the GridLayout;
2.4.1 WeatherItem
43 // add 3 to accommodate the two header JLabels
44 // and balance the columns
45 [Link](
46 new GridLayout( ( [Link] + 3 ) / 2, 2 ) );
47 [Link]( new JLabel( headerImage ) ); // header 1
48 [Link]( new JLabel( headerImage ) ); // header 2
49
50 for ( int i = 0; i < [Link]; i++ ) {
51 w[ i ] = new WeatherItem( weatherInfo[ i ] );
52 [Link]( w[ i ] );
53 }
54
55 getContentPane().add( new JScrollPane( p ),
56 [Link] );
57 }
58 catch ( [Link] ce ) {
59 [Link]( "Connection to server failed. " +
60 "Server may be temporarily unavailable." );
61 }
62 catch ( Exception e ) {
63 [Link]();
64 [Link]( 1 );
65 }
66 }
3. main
67
68 public static void main( String args[] ) 3.1 args[ 0 ]
69 {
70 TemperatureClient gt = null;
71
72 // if no sever IP address or host name specified,
73 // use "localhost"; otherwise use specified host
74 if ( [Link] == 0 )
75 gt = new TemperatureClient( "localhost" );
76 else
args[ 0 ] is the first
77 gt = new TemperatureClient( args[ 0 ] ); argument, which should be
78 the IP address.
79 [Link](
80 new WindowAdapter() {
81 public void windowClosing( WindowEvent e )
82 {
83 [Link]( 0 );
84 }
85 }
86 );
87 }
88 }
1 // Fig. 20.5: [Link]
2 // WeatherItem definition
3 import [Link].*;
4 import [Link].*;
5 1. Class WeatherItem
6 public class WeatherItem extends JLabel {
7 private static ImageIcon weatherImages[], backgroundImage;
8 private final static String weatherConditions[] = 1.1 static variables
9 { "SUNNY", "PTCLDY", "CLOUDY", "MOCLDY", "TSTRMS",
10 "RAIN", "SNOW", "VRYHOT", "FAIR", "RNSNOW",
11 "SHWRS", "WINDY", "NOINFO", "MISG" }; 1.2 Initializer block
12 private final static String weatherImageNames[] =
13 { "sunny", "pcloudy", "mcloudy", "mcloudy", "rain", 1.3 Load ImageIcons
14 "rain", "snow", "vryhot", "fair", "rnsnow",
15 "showers", "windy", "noinfo", "noinfo" };
16
17 // static initializer block to load weather images
18 static {
19 backgroundImage = new ImageIcon( "images/[Link]" );
20 weatherImages =
21 new ImageIcon[ [Link] ];
22
23 for ( int i = 0; i < [Link]; ++i )
24 weatherImages[ i ] = new ImageIcon(
25 "images/" + weatherImageNames[ i ] + ".jpg" );
26 }
27
28 // instance variables Use names in weatherImageNames
29 private ImageIcon weather; array to load ImageIcons.
30 private WeatherInfo weatherInfo;
31
32 public WeatherItem( WeatherInfo w )
33 {
34 weather = null;
35 weatherInfo = w; 2. Constructor
36
37 // locate image for city's weather condition
38 for ( int i = 0; i < [Link]; ++i ) 2.1 Compare
39 if ( weatherConditions[ i ].equals( conditions
40 [Link]().trim() ) ) {
41 weather = weatherImages[ i ];
3. paintComponent
42 break;
43 }
Loop though weatherConditions and
44 compare to getDescription.
3.1 paintIcon
45 // pick the "no info" image if either there is no
46 // weather info or no image for the current
47 // weather condition
48 if ( weather == null ) {
49 weather = weatherImages[ [Link] - 1 ];
50 [Link]( "No info for: " +
51 [Link]() );
52 }
53 }
54
55 public void paintComponent( Graphics g ) Attach background to WeatherItem.
56 {
57 [Link]( g );
58 [Link]( this, g, 0, 0 );
59
60 Font f = new Font( "SansSerif", [Link], 12 );
61 [Link]( f );
62 [Link]( [Link] );
63 [Link]( [Link](), 10, 19 );
3.2 drawString
64 [Link]( [Link](), 130, 19 );
65
3.3 paintIcon
66 [Link]( this, g, 253, 1 );
67 }
68 Draw city name, high/low, and attach
69 // make WeatherItem's preferred size the weather
width and height ofWeatherItem.
image to
70 // the background image
71 public Dimension getPreferredSize()
72 {
73 return new Dimension( [Link](),
74 [Link]() );
75 }
76 }
Compile and Execute the Server and the
Client
• Build and execute application
– All pieces in place
– Compile classes with javac
– Remote server class (TemperatureServerImpl)
compiled with rmic compiler
• Makes a stub class - allows client to access remote methods
and server to provide its services
• Gets remote method calls, passes to RMI system, which
performs networking
• rmic TemperatureServerImpl
Compile and Execute the Server and the
Client
• Start rmiregistry
– Type rmiregistry at command window
• No text in response
Compile and Execute the Server and the
Client
• Must bind remote server object
– Run TemperatureServerImpl application
java TemperatureServerImpl
– Superclass UnicastRemoteObject
• Constructor exports remote object
• main binds object to rmiregistry
• rmiregistry provides host and port number to clients
Compile and Execute the Server and the
Client
• Execute TemperatureClient
– java TemperatureClient
– If server on different machine, specify IP on command line
java TemperatureClient [Link]
– Result on next slide
Program Output