Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
5.4. Automatic Class File Distribution
As discussed till now RMI has an unpleasant
Limitation:
• client and registry need access to stubs of remote service accessed;
• server needs access to stub and skeleton even though user code never
directly accesses these classes;
• client and server need access to all classes they will exchange as
parameters and return values of the remote method calls, i.e. there is a
problem if the server returns an object of a class type the client initially
did not know.
Solution: RMI provides automatic distribution of class files. When an
unknown class name is encountered, the RMI framework automatically
downloads the corresponding class file from a standard location. In JDK
1.2 the mechanisms is exposed through the MarshalledObject class
Fall 2003
CS 667: 5b. RMI - Zlateva
1
Where Does RMI Look for Downloading Classes?
When in an RMI framework either the client or the server encounter
an unknown class name, they attempt to load as follows:
1. Preferred location is the local CLASSPATH.
2. The unknown class is encountered in a remote call, e.g. server does
not know parameter type or client does not know the returned type or
stub returned from registry: the RMI framework includes the location
from which class has been obtained, more specifically the URL if the
class has been downloaded from a remote site, or the directory
specified in 3 below:
3. The unknown class is encountered locally, i.e. not during a remote
call: RMI attempts to download the class file from the URL specified
in the System property java.rmi.server.codebase. This can be used
for a central storage location for common local classes.
Fall 2003
CS 667: 5b. RMI - Zlateva
2
Automatic Class Downloading (continued)
According to rules 2 and 3 from the previous slide RMI automatically
includes class location with the class name it transmits as follows:
i. if the class has been already downloaded from a remote location, e.g.
from a web server, RMI data includes internally the URL from which
the class file can be down loaded. This URL is used for the class as
well as for any other unknown classes that are needed by this new
downloaded class;
Otherwise:
ii. if the class is loaded locally, i.e. from the location set in the System
property java.rmi.server.codebase, it is this location that is
transmitted as a location from which the class can be downloaded.
Thus, to allow an RMI client to automatically download the stub files for
the RMI server, one must specify a codebase from which the class files
can be downloaded, e.g.
java –Djava.rmi.server.codebase =
http: //<host>/<downloadDirectory>/ <ServerName>
Fall 2003
CS 667: 5b. RMI - Zlateva
3
Example: Deploying the Product Info application - a) Staging Deployment Locally
• Make three directories: (HoCo 2000)
server: contains all files needed to run the server
ProductServer.class
Product.class
ProductImpl.class
ProductImpl_Stub.class
ProductImpl_Skeleton.class for JDK 1.1
Note: The stub classes must be included as they are needed when the server
registers the implementation object. Contrary to popular belief, the server does
not locate the stub classes in the download directory even if the codebase is set!
download: contains all class files that will be loaded by client and all the
classes they depend on.
Product.class
ProductImpl_Stub.class
ProductImpl_Skeleton.class for JDK 1.1
Note: All remote interface classes must be in the download directory, even
though they are present at the client site. Otherwise server dies when trying to
register server class.
Fall 2003
CS 667: 5b. RMI - Zlateva
4
Staging Deployment Locally (continued)
client: contains all files needed to start the client
ProductClient.class
Product.class
client.policy (not required for JDK 1.1.)
Note: The classes for the remote interfaces (Product) must be deployed,
otherwise the client does not load. The interface classes are not downloaded!
• Move the download directory to the web documents directory of the web
server (A light weight web server with enough functionality to serve class
files can be obtained from ftp://java.sun.com/pub/jdk1.1/rmi );
• Start web server;
• Start new shell. Make sure the class path is not set to anything. Change to a
directory that does not contain class files. Start RMI registry.
Fall 2003
CS 667: 5b. RMI - Zlateva
5
Staging Deployment Locally (continued)
• Start new shell.
Change to server directory.
Start server, giving URL of download directory as value of the
java.rmi.server.codebase property:
java –Djava.rmi.server.codebase =
http: //localhost/download/ ProductServer
• Change to client directory.
Start client.
java ProductClient
The client can also specify a codebase if the possibility exists that the server
may encounter unknown class types, e.g. in argument type.
If there is a policy file, give the name of the policy file as value of the
java.security.policy property:
java –Djava. java.security.policy = client.policy ProductServer
Fall 2003
CS 667: 5b. RMI - Zlateva
6
b) Distributing to Remote Sites
• Move classes from the download directory to the web server
• Start server, giving URL of the web server directory
java.rmi.server.codebase property:
java –Djava.rmi.server.codebase =
http: //<host>/<webServerDirectory>/ ProductServer
• In client, change all localhost instances to <host> . Recompile and start
client.
Fall 2003
CS 667: 5b. RMI - Zlateva
7
5.5 Security Considerations
Applications, by default, do not have a security manager and code has
unlimited access to resources.
dangerous when automatic class file loading is involved as is the case in
RMI: a user can place arbitrary code in the class file and thus gain undesired
access to recipient (client as well as server) resources.
RMI provides the following defense mechanisms:
Fall 2003
CS 667: 5b. RMI - Zlateva
8
Server Side Security
SecurityManager on server to control access:
RMI does not download remote class files if there is no SecurityManager
installed on the server side. The SecurityManager must be installed before
the object is exposed to remote access; otherwise a SecurityException is
thrown during remote method call requiring downloading.
The RMI SecurityManager sets the default security policy for RMI
applications (not for applets). It is a simple implementation of the
SecurityManager class. For code loaded from a class loader, the security
manager disables all functions except class definition and access for
download, i.e. it permits downloading of remote stub classes, but denies any
sensitive operations such as accessing native code, files, etc.
If the application needs different levels of access one can subclass the
RMISecurityManager and implement appropriate policies.
Fall 2003
CS 667: 5b. RMI - Zlateva
9
Client Side Security
SecurityManager on client to control activity of dynamic loaded stubs: By
default the RMI Security Manager restricts all code from establishing network
connections (this is no problem for the server as the access it through the RMI
registry). However, the client needs to connect to the RMI registry to contact
the server objects.
The solution is to provide the client with a policy file (e.g. client.policy) that
gives permission for a network connection to particular port(s).
(For a general discussion of policy files and their use with RMI see (HoCo
2000, Ch.9 and p.351-2 respectively. )
NOTE: For many applications the ability to remotely download classes is not
necessary. In cases where automatic class file distribution is not central to the
application, the installation of the RMISecurityManager can and should be
omitted.
Fall 2003
CS 667: 5b. RMI - Zlateva
10
Policy File Example: client.policy
grant
{
permission java.net.SocketPermission
"*:1024-65535", "connect";
permission java.awt.AWTPermission
"accessEventQueue";
permission java.net.SocketPermission
"localhost:80", "connect";
};
Fall 2003
CS 667: 5b. RMI - Zlateva
11
Registry Security
If any host is allowed access to the naming registry there is danger that its
content will be manipulated;
The Naming class allows modification of the naming registry (through
various naming methods) only if the caller is running on the same machine.
Therefore, the name of the registry host should be omitted when manipulating
its content, e.g.
// <servicePath> if the default port is used, or
//:port/<servicePath> if a nonstandard port is used.
Fall 2003
CS 667: 5b. RMI - Zlateva
12
5.6. RMI Related Packages - Overview
java.rmi contains classes related to the client side of RMI; classes used
by client to remotely access RMI services; includes interfaces through
which remote objects are accessed and mechanisms to locate RMI
services on a remote machine. (interface Remote, classes Naming and
RMISecurityManager)
java.rmi.server
contains classes related to the server side of RMI;
includes the support classes for exposing an RMI service to direct TCP/IP
and proxied HTTP requests. (class UnicastRemoteObject)
java.rmi.registry contains classes related to the RMI naming registry;
makes it possible to create, locate and manipulate naming registries.
java.rmi.dgc contains classes that support distributed garbage collection.
java.rmi.activation (JDK 1.2) contains support for the JDK 1.2 activation
mechanism; this mechanisms allows RMI servers not to be running
permanently, but instead that they are activated by an activation daemon
only when an actual request arrives. Typically the servers are kept in a
serialized passive state.
Fall 2003
CS 667: 5b. RMI - Zlateva
13
Interface Remote – API Specification
The Remote interface serves to identify all remote objects. Only a marker
interface.
Any object that is a remote object must directly or indirectly implement this
interface. Only those methods specified in a remote interface are
available remotely, i.e. a subclass that does not implement remote can
access remotely only methods of its superclass.
Implementation classes can implement any number of remote interfaces and
can extend other remote implementation classes.
Fall 2003
CS 667: 5b. RMI - Zlateva
14
Class Naming – API Specification
This is the bootstrap mechanism for obtaining references to remote objects
based on Uniform Resource Locator (URL) syntax.
The URL for a remote object is specified using the usual host, port and
name:
rmi://host:port/name
host = host name of registry (defaults to current host)
port = port number of registry (defaults to the registry port number)
name = name for remote object
Note: all arguments are optional
Fall 2003
CS 667: 5b. RMI - Zlateva
15
Class Naming: Public methods– API Specification
bind (String name, Remote obj)
Binds the name to the specified remote object.
list(String name)
Returns an array of strings of the URLs in the registry.
lookup(String name)
Returns the remote object for the URL.
rebind(String name, Remote obj)
Rebind the name to a new object; replaces any existing binding.
unbind(String name)
Unbind the name.
Fall 2003
CS 667: 5b. RMI - Zlateva
16
5.7. Parameter Passing in RMI
Major Difference in RMI's Handling of:
Remote Objects
vs.
Non-Remote
Remote objects are passed
Local objects are passed
by reference
by value
When passing a remote object the client receives a stub object and saves it in
an object variable whose type is the same as the remote interface.
Through the stub, the client accesses the actual remote object. Any changes
the remote method makes to the parameter are reflected in the object, i.e. RMI
passes remote objects by reference.
However, nonremote (local) objects do not have a stub, e.g. the String
returned from the server through the remote interface Product. In order to
transport a nonremote object RMI makes a copy and sends the copy through
the network. The client gets its own copy of the object, i.e. a call by value is
performed. If the client sends a parameter to the remote object, any changes
the remote method makes on this parameter are not reflected in the local
object.
Fall 2003
CS 667: 5b. RMI - Zlateva
17
Notes
Only remote interfaces are accessed through the stub. (A remote interface is
any interface that extends Remote);
No local method is accessible through stubs. (A local method is any method
that is not defined in a remote interface).
Stubs are generated only for classes that implement a remote interface, and
only methods specified in the remote interface are provided in the stub
classes. If a subclass does not implement a remote interface while its
superclass implements the remote interface, only the superclass methods are
accessible through the stub.
RMI uses serialization to transport objects over the network. Thus it can
make copies of any objects as long as they are serializable, i.e. instances of
a class that implements the Serializable interface.
Fall 2003
CS 667: 5b. RMI - Zlateva
18
Local Objects Are Passed Differently in Remote and Local Method Calls
Local calls obtain a reference (memory location in local JVM) to the local
object parameters and thus any changes made by the local methods reflect in
the parameter. (Recall that primitive types in local calls are passed by value.)
But a memory location on the local machine does not do any good to the
remote JVM. To make things worse the local object has no stub on the remote
JVM through which it could be manipulated. This is why the only way to
pass the local object is to make a copy for the remote side
Passing Local Objects in
RMI call
by value
Fall 2003
vs.
CS 667: 5b. RMI - Zlateva
Local calls
by reference
19
Figure: Passing Nonremote Objects
JVM 1
void localMethod (Vector v){
….
}
velocity
void main(){
localMethod ( velocity );
remoteMethod(velocity);
JVM 2
void remoteMethod (Vector v){
….
velocity
}
RMI
(HSH 1999, p.515)
Fall 2003
CS 667: 5b. RMI - Zlateva
20
Parameter Passing Summary
Call
Local
Remote
Object
Local
by reference
(for primitive
by value
types by value)
Remote
Not possible
Fall 2003
CS 667: 5b. RMI - Zlateva
by reference
21
Example: Warehouse gives Product recommendations
centralWarehouse . find(Customer c)
calls remote / sends arguments
Client
Server
returns Vector recommendations
with product descriptions
• Remote Interface Product
• Remote Interface Product
• Remote Interface Warehouse
• Remote Interface Warehouse
• ProductImpl
• WarehouseImpl
• WarehouseClient
• WarehouseServer
• ProductImpl_Stub
• ProductImpl_Stub
• WarehouseImpl_Stub
• WarehouseImpl_Stub
• Customer
• class Customer
(HiCo 2002, p.354 ff)
Fall 2003
CS 667: 5b. RMI - Zlateva
22
Parameter Passing in Warehouse Example (HoCo2002, p.356)
Vector recommendation = centralWarehouse . find(Customer c)
Client
Server
returns Vector of recommendations with
product descriptions
copy
Customer
Customer
copy
ArrayList
ArrayList
ProductImpl
ProductImpl
ProductImpl_Stub
ProductImpl_Stub
Fall 2003
CS 667: 5b. RMI - Zlateva
23
Product – Remote Interface
import java.rmi.*;
/**
interface for remote product objects (HoCo2002, p.357)
*/
public interface Product extends Remote
{
/**
@returns product description
*/
String getDescription() throws RemoteException;
static final int MALE = 1;
static final int FEMALE = 2;
static final int BOTH = MALE + FEMALE;
}
Fall 2003
CS 667: 5b. RMI - Zlateva
24
Warehouse - Remote Interface
import java.rmi.*;
import java.util.*;
/**
remote interface for a warehouse with products (HoCo2002, p.357)
*/
public interface Warehouse extends Remote
{
/**
Gets products that are good matches for a customer.
@param c the customer to match
@return an array list of matching products
*/
ArrayList find(Customer c) throws RemoteException;
}
Fall 2003
CS 667: 5b. RMI - Zlateva
25
ProductImpl.java: constructor
/**
This is the implementation class for the remote product
objects.
*/
public class ProductImpl
extends UnicastRemoteObject
implements Product
{
/**
Constructs a product implementation
@param n the product name
@param s the suggested sex (MALE, FEMALE, or BOTH)
@param age1 the lower bound for the suggested age
@param age2 the upper bound for the suggested age
@param h the hobby matching this product
*/
public ProductImpl(String n, int s, int age1, int age2, String h)
throws RemoteException
{
name = n;
ageLow = age1;
ageHigh = age2;
sex = s;
hobby = h;
CS 667: 5b. RMI - Zlateva
} Fall 2003
26
ProductImpl.java: match()
/**
Checks whether this product is a good match for a
customer. Note that this method is a local method
since it is not part of the Product interface.
@param c the customer to match against this product
@return true if this product is appropriate for the
customer
*/
public boolean match(Customer c)
{
if (c.getAge() < ageLow || c.getAge() > ageHigh)
return false;
if (!c.hasHobby(hobby)) return false;
if ((sex & c.getSex()) == 0) return false;
return true;
}
Fall 2003
CS 667: 5b. RMI - Zlateva
Serializable
+ Customer
-age:int
-sex: int
-hobbies: String[]
+getAge(): int
+getSex(): int
+hasHobby(String): boolean
+reset(): void
27
ProductImpl.java: getDescription()
public String getDescription() throws RemoteException
{
return "I am a " + name + ". Buy me!";
}
private String name; //product description
private int ageLow; //lower bound of age
private int ageHigh; //upper bound of age
private int sex;
private String hobby;
}
Fall 2003
CS 667: 5b. RMI - Zlateva
28
WarehouseImpl.java: constructor
/**
This class is the implementation for the remote
Warehouse interface.
*/
public class WarehouseImpl
extends UnicastRemoteObject
implements Warehouse
{
/**
Constructs a warehouse implementation.
*/
public WarehouseImpl() throws RemoteException
{
products = new ArrayList();
coreJavaBook = new ProductImpl("Core Java Book",
0, 200, Product.BOTH, "Computers");
}
Fall 2003
CS 667: 5b. RMI - Zlateva
29
WarehouseImpl.java: read()
/**
Reads in a set of product descriptions. Each line has the format
name|sex|age1|age2|hobby, e.g.
Blackwell Toaster|BOTH|18|200|Household
@param reader the reader to read from
*/
public void read(BufferedReader reader) throws IOException{
String line;
while ((line = reader.readLine()) != null){
StringTokenizer tokenizer = new StringTokenizer(line, "|");
String name = tokenizer.nextToken();
String s = tokenizer.nextToken();
int sex = 0;
if (s.equals("MALE")) sex = Product.MALE;
else if (s.equals("FEMALE")) sex = Product.FEMALE;
else if (s.equals("BOTH")) sex = Product.BOTH;
int age1 = Integer.parseInt(tokenizer.nextToken());
int age2 = Integer.parseInt(tokenizer.nextToken());
String hobby = tokenizer.nextToken();
add(new ProductImpl(name, sex, age1, age2, hobby));
} Fall 2003
CS 667: 5b. RMI - Zlateva
30
}
WarehouseImpl.java: find(Customer)
/**
Finds all products matching customer, aggregates them in ArrayList result
@param c the Customer to match
@returns result – an ArrayList of matching products
*/
public synchronized ArrayList find(Customer c) throws RemoteException {
ArrayList result = new ArrayList();
// add all matching products
for (int i = 0; i < products.size(); i++){
ProductImpl p = (ProductImpl)products.get(i);
if (p.match(c)) result.add(p);
}
// add the product that is a good match for everyone
result.add(coreJavaBook);
// we reset c just to show that c is a copy of the client object
c.reset();
return result;
}
….
}//endFall
WarehouseImpl.java
2003
CS 667: 5b. RMI - Zlateva
31
product.dat
Blackwell Toaster|BOTH|18|200|Household
ZapXpress Microwave Oven|BOTH|18|200|Household
Jimbo After Shave|MALE|18|200|Beauty
Handy Hand Grenade|MALE|20|60|Gardening
DirtDigger Steam Shovel|MALE|20|60|Gardening
U238 Weed Killer|BOTH|20|200|Gardening
Van Hope Cosmetic Set|FEMALE|15|45|Beauty
Persistent Java Fragrance|FEMALE|15|45|Beauty
Rabid Rodent Computer Mouse|BOTH|6|40|Computers
Learn Bad Java Habits in 21 Days Book|BOTH|20|200|Computers
My first Espresso Maker|FEMALE|6|10|Household
JavaJungle Eau de Cologne|FEMALE|20|200|Beauty
Fast/Wide SCSI Coffee Maker|MALE|20|50|Computers
ClueLess Network Computer|BOTH|6|200|Computers
Fall 2003
CS 667: 5b. RMI - Zlateva
32
WarehouseServer.java
/**
This server program instantiates a remote warehouse
objects, registers it with the naming service, and waits
for clients to invoke methods.
*/
public class WarehouseServer{
public static void main(String[] args){
try{
System.out.println ("Constructing server implementations...");
WarehouseImpl w = new WarehouseImpl();
w.read(new BufferedReader(new FileReader("products.dat")));
System.out.println ("Binding server implementations to registry...");
Naming.rebind("central_warehouse", w);
System.out.println ("Waiting for invocations from clients...");
}
catch(Exception e){
e.printStackTrace();
}
}
}
Fall 2003
CS 667: 5b. RMI - Zlateva
33
WarehouseClient.java
/**
The client for the warehouse program.
*/
public class WarehouseClient{
public static void main(String[] args)
{
System.setProperty("java.security.policy", "client.policy");
System.setSecurityManager(new RMISecurityManager());
JFrame frame = new WarehouseClientFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
Fall 2003
CS 667: 5b. RMI - Zlateva
34
WarehouseClientFrame: constructor
/**
A frame to select the customer's age, sex, and hobbies, and to
show the matching products resulting from a remote call to the
warehouse.
*/
class WarehouseClientFrame extends JFrame{
public WarehouseClientFrame(){
setTitle("WarehouseClient");
setSize(WIDTH, HEIGHT);
initUI();
try{
Properties props = new Properties();
String fileName = "WarehouseClient.properties";
FileInputStream in = new FileInputStream(fileName);
props.load(in);
String url = props.getProperty("warehouse.url");
if (url == null) url = "rmi://localhost/central_warehouse";
centralWarehouse = (Warehouse)Naming.lookup(url);
}
catch(Exception e){
System.out.println("Error: Can't connect to warehouse. " + e);
} Fall 2003
CS 667: 5b. RMI - Zlateva
}
35
WarehouseClientFrame: callWarehouse
/**
Call the remote warehouse to find matching products.
*/
private void callWarehouse(){
try{
Customer c = new Customer(Integer.parseInt(age.getText()), Remote Call:
(male.isSelected() ? Product.MALE : 0)
copy of c sent;
+ (female.isSelected() ? Product.FEMALE : 0),
copy of recommendations
new String[] { (String)hobbies.getSelectedItem() });
and its entries returned
ArrayList recommendations = centralWarehouse.find(c);
result.setText(c + "\n");
Local Call:
for (int i = 0; i < recommendations.size(); i++){
Product p = (Product)recommendations.get(i);
String t = p.getDescription() + "\n";
result.append(t);
Remote Call: remote object
}
p accessed through stub to
}
obtain description
catch(Exception e){
result.setText("Exception: " + e);
}
}
Fall 2003
CS 667: 5b. RMI - Zlateva
36
WarehouseClient.java (continued)
public void actionPerformed(ActionEvent evt)
{ Object[] hobbyObjects = hobbies.getSelectedValues();
String[] hobbyStrings = new String[hobbyObjects.length];
System.arraycopy(hobbyObjects, 0, hobbyStrings, 0,
hobbyObjects.length);
Customer c = new Customer(Integer.parseInt(age.getText()),
(male.isSelected() ? Product.MALE : 0)
+ (female.isSelected() ? Product.FEMALE : 0),
hobbyStrings);
callWarehouse(c);
}
//UI interface code here
private Warehouse centralWarehouse;
private JTextField age;
private JCheckBox male;
private JCheckBox female;
private JList hobbies;
private JTextArea result;
CS 667: 5b. RMI - Zlateva
} Fall 2003
37
5.8. Sockets vs.RMI
Sockets
More efficient
vs.
RMI
Overhead (serialization, synchronization)
Transfer of user defined
data-structures requires explicit
use of serialization
Transparent use of serialization
Need to explicitly take care
of synchronization tasks
when transferring objects
in a distributed procedure
RMI calls appear to work like local calls
Code is bulkier, longer
not very easy to read
Code is more compact, shorter,
easier to read
Security needs to be
implemented in addition
RMISecurityManager available
Fall 2003
CS 667: 5b. RMI - Zlateva
38
5.9. Implementing Factories
Goal: Instead of having the server running indefinitely
create on request a server when needed.
Implementation: Through a server factory that will create one or
more instances of the server on the fly, make them accessible
for the remote client. The result is a dynamical set of remote
objects that can interact with each other.
A factory is a server that has only one method, and this method
returns remote objects that are used as servers by clients.
Example: A City Info Server that give information about the
city's population, temperatures, etc.
Fall 2003
CS 667: 5b. RMI - Zlateva
39
Example: City Info
pop . getPopulation(<cityName>)
calls remote / sends arguments
Client
Server
returns int for population
• Client program CityClient.java
• Server CityServer.java
• Remote Interface City.java
• Remote Interface City.java
• City_Stub.class
• Remote Interface Implementation
CityImpl.java
• City_Stub.class
(adapted from Mah 2000, p.126,ff)
Fall 2003
CS 667: 5b. RMI - Zlateva
40
City.java - Remote Interface
import java.rmi.*;
/**
* @(#)City.java
*/
public interface City extends Remote{
int getPopulation (String cityName) throws RemoteException;
int getTemperature (String cityName) throws RemoteException;
}
Fall 2003
CS 667: 5b. RMI - Zlateva
41
CityImpl.java - Remote Interface Implementation
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
/**
* @(#) CityImpl.java
*/
public class CityImpl extends UnicastRemoteObject implements City {
private String name;
public CityImpl (String name) throws RemoteException{
super();
this.name = name;
}
Fall 2003
CS 667: 5b. RMI - Zlateva
42
CityImpl.java (continued)
public int getPopulation (String cityName) throws RemoteException{
if (cityName.equals("Boston")){
return 4;
}else if (cityName.equals("New York")){
return 20;
}else{
return 0;
}
}
public int getTemperature (String cityName) throws RemoteException{
return 5555;
}
}
Fall 2003
CS 667: 5b. RMI - Zlateva
43
CityServer.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
/**
* @(#) CityServer.java
*/
public class CityServer{
public static void main (String argv []) {
System.setSecurityManager(new RMISecurityManager());
try{
CityImpl anyTown = new CityImpl("CityServer");
Naming.rebind("//localhost/CityServer", anyTown);
System.out.println("CityServer bound in registry");
} catch (Exception e){
e.printStackTrace();
}
}
}
Fall 2003
CS 667: 5b. RMI - Zlateva
44
CityClient.java
import java.rmi.*;
/**
* @(#) CityClient.java
*/
public class CityClient {
public static void main(String argv[]){
int pop = 0;
try{
City anyTown = (City) Naming.lookup("//localhost/CityServer");
pop = anyTown.getPopulation ("Boston");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("The population of Boston is " + pop);
}
}
Fall 2003
CS 667: 5b. RMI - Zlateva
45
Example: City Factory Info
cityFactory . getCityServer()
objCityServer.getPopulation
Client
Server
returns objCityServer
returns int for population
• Client CityFtClient.java
• Server CityFtServer.java
• Remote Interface CityFactory.java
• Remote Interface CityFactory.java
• Remote Interface City2.java
• Remote Interface City2.java
• CityFactoryImpl.java
• City2Impl.java
• CityFactory_Stub.class
• CityFactory_Stub.class
• City2_Stub.class
• City2_Stub.class
Fall 2003
CS 667: 5b. RMI - Zlateva
46
City2.java – Remote Interface
import java.rmi.*;
/**
* @(#) City2.java
*/
public interface City2 extends Remote{
int getPopulation () throws RemoteException;
int getTemperature() throws RemoteException;
}
Fall 2003
CS 667: 5b. RMI - Zlateva
47
City2Impl.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
/**
* @(#) City2Impl.java
*/
public class City2Impl extends UnicastRemoteObject implements City2 {
private String cityName;
public City2Impl () throws RemoteException{
super();
}
public City2Impl(String cityName) throws RemoteException{
super();
this.cityName = cityName;
}
/* This constructor will be used by the factory method to instantiate a server object
for a particular city
*/
Fall 2003
CS 667: 5b. RMI - Zlateva
48
City2Impl (continued)
public int getPopulation () throws RemoteException{
if (cityName.equals("Boston")){
return 4;
}else if (cityName.equals("New York")){
return 20;
}else{
return 0;
}
}
public int getTemperature () throws RemoteException{
return 5555;
}
/* Note: no cityName specified as parameter in the getter methods;
the city name is given by the city server
*/
}
Fall 2003
CS 667: 5b. RMI - Zlateva
49
CityFactory.java - Remote Interface
import java.rmi.*;
/**
* @(#) CityFactory.java: defines method to return an object of type
remote interface City2 - a 'server' object - for a specific city
*/
public interface CityFactory extends Remote{
City2 getCityServer (String cityName) throws RemoteException;
}
Fall 2003
CS 667: 5b. RMI - Zlateva
50
CityFactoryImpl.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
/**
* @(#) CityFactoryImpl.java
*/
public class CityFactoryImpl extends UnicastRemoteObject
implements CityFactory {
private String name;
public CityFactoryImpl() throws RemoteException{
super();
}
public City2 getCityServer( String cityName) throws RemoteException{
City2 cityServer = new City2Impl(cityName);
//constructor for City2 'server' object called
return cityServer;
}
} Fall 2003
CS 667: 5b. RMI - Zlateva
51
CityFtServer.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
/**
* @(#) CityFtServer.java
*/
public class CityFtServer{
public static void main(String argv []) {
try{
System.setSecurityManager(new RMISecurityManager());
System.out.println("Starting server...");
System.out.println("Creating remote CityFactoryImpl object...");
Fall 2003
CS 667: 5b. RMI - Zlateva
52
CityFtServer.java (continued)
try{
CityFactoryImpl obj = new CityFactoryImpl();
/* Note: only one remote object exposed, but it can produce for each city a
separate object for giving information about the city
*/
Naming.rebind("//localhost/CityFactory", obj);
System.out.println("CityFactory bound in registry");
System.out.println("Waiting for client call...");
} catch (Exception e){
e.printStackTrace();
}
}catch (Exception ex){
System.out.println("Server error " + ex);
}
}
}
Fall 2003
CS 667: 5b. RMI - Zlateva
53
CityFtClient.java
import java.rmi.*;
/**
* @(#) CityFtClient.java
*/
public class CityFtClient {
public static void main(String argv[]){
Remote obj = null;
CityFactory cityFactory = null;
City2 boston = null;
City2 newyork = null;
int bostonPopulation = 0;
int newyorkPopulation = 0;
try{
obj = Naming.lookup("//localhost/CityFactory");
} catch (Exception e) {
e.printStackTrace();
}
Fall 2003
CS 667: 5b. RMI - Zlateva
54
CityFtClient.java (continued)
if ( obj instanceof CityFactory) {
cityFactory = (CityFactory) obj;
}
try{
boston = cityFactory.getCityServer("Boston");
newyork = cityFactory.getCityServer("New York");
} catch (RemoteException e) {
e.printStackTrace();
}
try{
bostonPopulation = boston.getPopulation();
newyorkPopulation = newyork.getPopulation();
}catch (RemoteException e) {
e.printStackTrace();
}
System.out.println("The population of Boston is " + bostonPopulation);
System.out.println("The population of New York is "
+ newyorkPopulation);
}
}
Fall 2003
CS 667: 5b. RMI - Zlateva
55