william grosso, [email protected] (c) 1999, all rights reserved basic rmi

52
Grosso, [email protected] (C) 1999, all rights re Basic RMI

Upload: karen-carr

Post on 30-Dec-2015

220 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

William Grosso, [email protected] (C) 1999, all rights reserved

Basic RMI

Page 2: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Remote Method InvocationBasic ExampleActivationDouble-Checked Locking Socket FactoriesSystem Properties

Page 3: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Recall: SocketsGood

Efficient, well-understood Language/platform independent Easy to customize for security and

compressionLess Good

Not very abstract “Stream” data model isn’t very OO Relies on application-level protocol being

defined (and implemented)

Page 4: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

The VisionIf the code on both sides is Java, then

the way to send data across the wire should also “be Java”

Send messages to objects (independent of location)

Caution: In the long-run, this is a pipe dream Objects across the wire have a much

greater latency, and can fail in ways that in-process objects cannot

Page 5: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

What is RMI ?[R]emote [M]ethod [I]nvocationA way to send messages to objects

over the network Built on top of sockets Friendly and easy to use for Java

programmersAn entire framework for building

distributed applicationsInfrastructure for the really cool stuff

Page 6: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Definition Layering

java.net

RMI

Jini

Javaspaces

Page 7: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Implementation Layering

java.net

RMI

Jini

Javaspaces

Servlets

EJB

Page 8: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Shared Assumptionsabout the world

Our Example

Dispatcher

Client

Client

ClientLimo

Limo

Limo

Page 9: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Putting this on a Network

Dispatcher

Client

Client

ClientLimo

Limo

Limo

Page 10: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Stubs and Skeletons

Dispatcher

Client

Limo

Limo Stub

Dispatcher Stub

Dispatcher SkeletonLimo Skeleton

Page 11: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Making a Callclient clientSideStub serverSide

Skeletonserver

fooforward call along wire

foo

client "thinks" it is talking directly to server

All the arguments (and the method name) get wrapped up and sent over the wire

Skeleton unwraps everything and calls the servers implementatiof foo

Page 12: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Basic Development ProcedureDefine InterfacesDefine Serializable Value ObjectsStop and Think about Object Identity Implement ServerImplement ClientGenerate Stubs and Skeletons Write Security Policy(Run System)

Page 13: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Our Classes in UML

Remote

RemoteObject

UnicastRemoteObject Dispatcher Limo

DispatcherImpl LimoImpl

DriverLocationPassenger

Serializable

RemoteServer

Page 14: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Our Main Interfacespackage grosso.rmi;import java.rmi.*;

public interface Limo extends Remote { public void setDispatcher(Dispatcher d) throws RemoteException; public Location getLocation() throws RemoteException; public boolean getIsCarryingPassenger() throws RemoteException; public boolean wantPassenger(Passenger passenger) throws RemoteException; public boolean pickupPassenger(Passenger passenger) throws RemoteException; public Driver getDriver() throws RemoteException;}

package grosso.rmi;import java.rmi.*;

public interface Dispatcher extends Remote { public Limo hailLimo(Passenger passenger) throws RemoteException; public void limoAvailable(Limo limo)throws RemoteException; public void limoUnavailable(Limo limo)throws RemoteException;}

Page 15: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Serializable, Primitive, RemoteThe only value types referred to in the

interfaces are: Serializable objects Instances of a class that implements the

Remote interface Primitive values (byte, int, ...)

You can have non-serializable, non-remote objects in your applications. But they cannot be referred to in the code RMI will touch

Page 16: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Serialized ObjectsAre only used as arguments to method

calls (cannot be messaged)Are sent “by value”

The RMI mechanism uses a subclass of ObjectOutputStream to serialize the instance and send it over the wire

The receiving JVM creates a duplicate of the original object using the serialized information

A single ObjectOutputStream is used per method call

Page 17: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Remote ObjectsThe Remote interface is a marker

interface Objects which implement Remote are

“passed by reference”Typically you extend it by another

interface (declaring the server methods)

And then implement it by subclassing from UnicastRemoteObject

Remote

RemoteMethodDeclarations

LocalImpl

UnicastRemoteObject

Page 18: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Pass by Reference ?How do you pass a pointer to an object

in another process space?You don’t. Remote objects have stubs

and skeletons. RMI serializes out the Remote object

RMI uses a subclass of ObjectOutputStreamwhich over-rides replaceObject to swap the stub in

E.g. you serialize out a stub and send it over the wire

Page 19: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Object Identity is an IssueSuppose I callWhat happens in the server object ?

10 instances of Passenger are created They all have the same data inside them

(assuming a single-threaded client) But they are not the same object

They give different answers to hashcode and equals

Good practice is to over-ride equals and hashcode in your (immutable) value objects

for (int i = 0; i<10;i++) { limo.pickupPassenger(passenger)}

Page 20: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Locationpublic class Location implements Serializable { private int _x; private int _y; public Location(Point p) { _x = p.x; _y = p.y; }

// more constructors, getX() and getY() defined//(but, mercifully, omitted from slide)

public boolean equals(Object object) { if (object instanceof Location) { Location location = (Location)object; return ((_x == location.getX()) && (_y == location.getY())); } return false; } public String toString(){ return ("X:" + _x +"Y:" + _y); } public int hashCode() { return toString().hashCode(); }}

Page 21: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Passengerpublic class Passenger implements Serializable { private Location _startingLocation; private Location _destination;

public Passenger(Location startingLocation, Location destination) { _startingLocation = startingLocation; _destination = destination; }// getStartingLocation and getDestination defined but omitted

public boolean equals(Object object){ if (object instanceof Passenger ) { Passenger passenger= (Passenger)object; return ((_startingLocation.equals(passenger.getStartingLocation()))

&& (_destination.equals(passenger.getDestination()))); } return false; } public String toString() { return "Start:" + _startingLocation.toString() +

":end:" + _destination.toString(); } public int hashCode() { return toString().hashCode(); }}

Page 22: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Basic Development ProcedureDefine InterfacesDefine Serializable Value ObjectsStop and think about object identity Implement ServerImplement ClientGenerate Stubs and Skeletons Write Security PolicyRun System

Page 23: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Two Types of ServersNamed, universally locateable ones

Implement Remote (and extend UnicastRemoteObject)

Listed in a registry somewhere Example: DispatcherImpl

Servers that clients must be told about Implement Remote (and extend

UnicastRemoteObject) But not in listed in any registry Example: LimoImpl

Page 24: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Distinction is not in the ServerUsually, there is some factory object,

or launching code, that knows whether a given server needs to be registered

You can’t tell from the interface, and usually can’t tell from the implementation, how a server will make itself available This is part of the “background

assumptions” which appeared on our architecture diagram

Page 25: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

NamingSimple interface to (already running)

registry Implemented via 5 static methods

public static String[] list(String name) public static Remote lookup(String name) public static void bind(String name, Remote obj) public static void rebind(String name, Remote obj) public static void unbind(String name)

Page 26: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

What’s in a NameAll the arguments to Naming take a

String with the following format: Host defaults to the local machine Port defaults to 1099 name is intended to be human readable

”Find the rmiregistry listening on [port] of [machine]. Register me there as [name].” ”Find the rmiregistry listening on [port] of

[machine]. Get me the registered oject named [name]”

//host:port/name

Page 27: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

DispatcherImplpublic class DispatcherImpl extends UnicastRemoteObject implements Dispatcher{ private ArrayList _availableLimos;

public DispatcherImpl() throws RemoteException { _availableLimos= new ArrayList(); } public Limo hailLimo(Passenger passenger) throws RemoteException{ Collections.shuffle(_availableLimos); Iterator i = _availableLimos.iterator(); while(i.hasNext()){ Limo limo = (Limo) i.next(); if (limo .pickupPassenger(passenger)){ return limo; } } return null; } public void limoAvailable(Limo limo) throws RemoteException{ if (false==_availableLimos.contains(limo)) { _availableLimos.add(limo); } } public void limoUnavailable(Limo limo) throws RemoteException{ _availableLimos.remove(limo); }}

Page 28: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

LaunchDispatcher

package grosso.rmi;import java.rmi.server.*;import java.rmi.*;

public class LaunchDispatcher { public static void main(String[] args) { System.setSecurityManager(new RMISecurityManager()); try { Dispatcher dispatcher = new DispatcherImpl(); Naming.rebind("Dispatcher ", dispatcher); } catch (Exception e){} }}

Page 29: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

LimoImplpackage grosso.rmi;import java.rmi.*;import java.rmi.server.*;

public class LimoImpl extends UnicastRemoteObject implements Limo { private boolean _havePassenger; private Dispatcher _dispatcher; private Location _currentLocation; private Driver _driver; public LimoImpl(Dispatcher dispatcher, Driver driver)

throws RemoteException { _havePassenger = false; _dispatcher = dispatcher; _driver = driver; dispatcher.limoAvailable(this); }

public Location getLocation() throws RemoteException { return _currentLocation; }

public boolean getIsCarryingPassenger() throws RemoteException { return _havePassenger; }

Page 30: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

LimoImpl IIpublic void setDispatcher(Dispatcher dispatcher) throws RemoteException{ if ((false==_havePassenger) &&(null!=_dispatcher)) { _dispatcher.limoUnavailable(this); if(null!=dispatcher){ dispatcher.limoAvailable(this); } } _dispatcher = dispatcher; }

public boolean wantPassenger(Passenger passenger) throws RemoteException { return (false ==_havePassenger); // a very simple model of

// cabbie decision making }

public Driver getDriver() throws RemoteException { return _driver; }}

Page 31: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

LimoImpl III

public boolean pickupPassenger(Passenger passenger) throws RemoteException

{ if (true==_havePassenger) { return false; } _havePassenger = true; _dispatcher.limoUnavailable(this); _currentLocation=passenger.getDestination(); _dispatcher.limoAvailable(this); return true; }}

Page 32: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

LaunchLimopublic class LaunchLimo { public static void main(String[] args) {// In reality, we'd probably do something a little cleverer // here (use more command line args or use a factory server) System.setSecurityManager(new RMISecurityManager()); try { Dispatcher dispatcher = (Dispatcher) Naming.lookup("Dispatcher");

// name bootstrap issue for (int currentTaxiDriver=0; currentTaxiDriver < args.length;

currentTaxiDriver++) { Driver driver = new Driver(args[currentTaxiDriver]); Limo currentLimo = new LimoImpl(dispatcher, driver); System.out.println("Driver " + driver.name + " is on the road"); } System.out.println("All drivers have been launched"); } catch (Exception e){} }}

Page 33: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Registration Timing Sequence

launchLimo dispatcher registry particularLimo:LimoImpl

Naming

lookup(dispatcher)

create

add in limo

Page 34: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

SimpleClientpublic class SimpleClient extends SelfCleaningFrame{ private JTextArea _reportsBack; private JTextField _startX; private JTextField _startY; private JTextField _destinationX; private JTextField _destinationY; private JButton _hailCab;

public SimpleClient(){ // set up GUI. The key point here is that all the action is // keyed around an event on the hailcab button. }

public static void main(String[] args){ System.setSecurityManager(new RMISecurityManager()); new SimpleClient().show(); }}

Page 35: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

SimpleClientII private class ButtonAction implements ActionListener { public void actionPerformed(ActionEvent e){ try { Dispatcher dispatcher = (Dispatcher) Naming.lookup("Dispatcher"); Limo limo = dispatcher.hailLimo(getPassenger()); if (null!=limo) { Driver driver = limo.getDriver(); _reportsBack.append("Limo is driven by " + driver.name +"\n"); } else { _reportsBack.append("No limos available \n"); } } catch (Exception ee){} }

private Passenger getPassenger() { Location startingLocation = new Location(1,4); Location destination = new Location(2,5); return new Passenger(startingLocation, destination); } }

Page 36: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Method Call Timing Sequence

client Naming dispatcher limo

lookup

hailLimo

pickup passenger

returns limo

Page 37: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Generating Stubs / SkeletonsRMIC -- [RMI] [C]ompilerAutomatically builds stubs and

skeletons from .class files of server implementations“rmic -d outputpath fully.qualified.class.name”

Page 38: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Running The Current System

start java -Djava.security.policy=java.policy grosso.rmitalk.LaunchLimo Bob Al Fred Kerry

Start the registry going

Launch the Dispatcher

Launch the Limos

Run the Client App

start rmiregistry

start java -Djava.security.policy=java.policy grosso.rmi.LaunchDispatcher

java -Djava.security.policy=java.policy grosso.rmi.SimpleClient

Page 39: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

SimpleClient

Page 40: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

What We didDefine InterfacesDefine Serializable Value ObjectsStop and think about object identity Implement ServerImplement ClientGenerate Stubs and Skeletons Write Security PolicyRun System

We’ll talk about this another day

Page 41: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Homework Make this a multi-threaded applicationStart with dispatcher-- should be able

to handle multiple requests Limos will have to be able to handle

multiple simultaneous requests as wellBe efficient ! Synchronizing pickupPassenger()

is not a good idea

You may need to be careful with limoAvailable() / limoUnavailable() as well

Page 42: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Making Things More SecureSo what we’ve been talking about is a

way for objects to be transparently made persistent

This involved Sending serialized object states over the wire Lots of reflection The occasional loading of bytecode from

serversWe didn’t really discuss this because only so

much fits in an overview. But part of the magic is that class definitions travel across the wire too

Page 43: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Socket FactoriesOne way to make things more secure

is not to use the standard (“cleartext”) sockets.

Fortunately, this is really easy to do Simply write the socket factory objects And rewrite the constructor in the server

objects that will use the custom sockets

Page 44: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

The Factories

public class ClientSocketFactory implements RMIClientSocketFactory, Serializable { public Socket createSocket(String host, int port) throws IOException { return new CompressingSocket(host, port); }}

public class ServerSocketFactory implements RMIServerSocketFactory, Serializable{ public ServerSocket createServerSocket(int port) throws IOException { return new CompressingServerSocket(port); } }

Page 45: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Changing Dispatcher

public class DispatcherImpl extends UnicastRemoteObject implements Dispatcher { private ArrayList _availableLimos;

public DispatcherImpl() throws RemoteException { super(0, new ClientSocketFactory(), new ServerSocketFactory()); _availableLimos= new ArrayList();// binding to registry happens in Factory code }

public Limo hailLimo(Passenger passenger) throws RemoteException{ Collections.shuffle(_availableLimos); Iterator i = _availableLimos.iterator(); while(i.hasNext()) {

Page 46: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Why are the Factories Serializable ?When a connection is made,

Naming.lookup is called

The factory is serialized and downloaded to the registry and, from there, to the client

This is actually a little tricky-- you have to relax the security policy at the registry for this to work

Dispatcher dispatcher = (Dispatcher) Naming.lookup("Dispatcher");

Page 47: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Security Policy Teaser

grant { permission java.net.SocketPermission ":0-", "accept,connect,listen";};

Page 48: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Useful System PropertiesSystem Property Values Usage Noteshttp.proxyHost internet address Set on the client side, to let RMI know that HTTP

tunneling is available (from the internet addresslisted). What will happen is that RMI will attempt tomake connections in the normal way. If that fails, itwill attempt to use HTTP tunnelling to send themessage. This usually winds up devolving to

http://internetaddress:80/java-rmi.cgi?port=xxx?arg1=value1?....

java.rmi.dgc.leaseValue number of milliseconds How long is a default lease for ?

java.rmi.server.hostname internet address The issue here is—how does RMI figure out wherethe server is. Which starts out life as “how does theserver figure out where it is ?”This used to be a call to a naming server, but waschanged in JDK1.1 to be a native call instead. Saidnative call can sometimes return the wrong answer(e.g. an unqualified host name).

If you set this property, RMI will use this valueinstead of the value the server returns.

java.rmi.server.useLocalHostname true, false Setting this to true (it defaults to false) and no valuefor java.rmi.server.hostname will force RMI to use afully qualified hostname obtained from a nameservice.

java.rmi.server.codebase url Set on servers. This allows clients to download theclass definitions (e.g. bytecode) on the fly. The wayRMI does this is: First: Check the local classpath Second: Use contextual classpath (e.g. codebase tag in applets) Third: Use the url indicated by this flag.

Page 49: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Useful System PropertiesSystem Property Values Usage Notes

java.rmi.server.logCalls true, false Defaults to false. If true, all calls to remote objectswill be logged in a log file. For greater control overthe log file, use RemoteServer’s getLog() andsetlog(...) methods.

Activation sets this to true for the VMs it launches.java.security.policy filesun.rmi.transport.connectionTimeout number of milliseconds How long before an attempt to connect will timeout

.(SUN specific)sun.rmi.server.activation.debugExec true, false When Activation launches a VM, this prints out all

the parameters used. Can be handy for spotting aconfiguration error. (SUN specific)

Page 50: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

Advanced Questions

Why does rmic require an implementation rather than an interface to generate stubs and skeletons ?

Server objects can support multiple interfaces, but only have one skeleton/stub pair.

Doing things this way allows reflective calls to succeed on the client side. E.g. the stub has all the information that is necessary to determine whether or not a server implements a particular interface (otherwise using instanceof or other forms of reflection would require a round-trip across the wire)

QQ

AA

Page 51: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI

ReferencesThe RMI FAQ:

http://java.sun.com/products/jdk/rmi/faq.html

Archives of the RMI mailing list

http://archives.java.sun.com/archives/rmi-users.html

The RMI Specification

http://java.sun.com/products/jdk/1.2/docs/guide/rmi/spec/rmiTOC.doc.html

Page 52: William Grosso, grosso@pacbell.net (C) 1999, all rights reserved Basic RMI