Download RMI - Department of Computer Science

Document related concepts
no text concepts found
Transcript
Remote Objects
From notes originally prepared by
Gareth Lee
Department of Electrical and Electronic Engineering,
University of Western Australia
Overview
• First - look at remote loading of software
components
• Then - adapt the example to use RMI
• Finally - the RemoteWorker system
• Using a network of PEs for solving problems
• Distributes a task from a master to a set of
workers (slaves)
• Programmers write a Solver class
• Actually solves the problem (or sub-problem)
• System handles distribution of these classes
• Slaves can be started on remote machines
and left running
Network becomes a powerful computing
resource!
Example Application - Image viewer
• Requirements
• Able to display a wide range of image formats
• Imaging a picture library
• Extensible
• Support new image formats without
redistributing the entire application
• New image decoders prepared by the IT
department (or external suppliers)
• Allow bug fixes to the existing code without
updating every desk machine
Software components
• Allows designers to build applications
from substitutable (reusable) components
• Components can be loaded as they are
needed, not when the application is started
•
•
•
•
Minimizes memory footprint at any time
Maximizes versatility of application
Makes an application extensible
Minimises development cost (by allowing
reuse)
Remote Class loading
• Remote Class Loading is a half way house
• Deploy a simple shell application onto
clients’ desks
• This shell loads software components on
demand from a shared server
• Users never need know that this is going
on behind the scenes
• Demonstrated by the picture viewer
example
Implementing components
• We need a way of abstracting Java classes
• We cannot mention a component class
directly otherwise it will be loaded at the
outset
• An indirect way of creating components
• Components must implement agreed interface
• We must be able to create a component without
hard-coding its name in the source
• Here we create a specific family of
software component
• Java generalizes components as JavaBeans
The ImageCreator interface
• We need to create a family of software
components that know how to decode
various image file formats
• ImageCreator is the standard interface
for accessing components. . .
• . . . so each of the components must
implement the interface
The ImageCreator interface
/**
This provides an interface for components which are
able to create image objects from files.
@author Gareth Lee
@version 0.1, March 11th, 2000.
*/
public interface ImageCreator {
/**
Read the contents of the specified source file
and create an Image object containing the file
contents
*/
public Image createImage(File source);
}
Abstracting Java classes
• Java provides us with a pool of objects of
type java.lang.Class
• These abstract the data types that Java
supports
• Class types as found in the standard libraries
(API classes)
• User defined classes
• Software components written by users
• Built in primitive types
• int, boolean, etc
Remote Class Loading
? Deploy applications using applets
• Overcomes distributions costs for bug
fixes and upgrades
• Downside:
• Most browsers don’t trust applets and impose
severe restrictions
• Severe UI restrictions when running applets
• Difficult to deploy groups of applets which are
able to cooperate (for example a word
processor and a spell checker)
java.lang.Class
• Allows types (classes) to be accessed by name
• Strings giving the fully qualified name
• Class name must be prefixed by the package in
which it is loaded
• eg java.lang.Integer
• Objects may be created (instantiated) from the
instances of the Class
• Zero argument construction is trivial
• Constructors with arguments a little trickier
• java.lang.Class API
• Has methods which allow properties of the
class type to be obtained
• Constructors, fields, methods, etc
java.lang.Class
• Constructing (loading) a class
• Class forName(String qualifiedName)
eg
• Class c = Class.forName( “RemoteWorker” );
• Reflection API methods
•
•
•
•
•
Object newInstance() // construct obj
Constructor[] getConstructors()
Method[] getMethods()
Field[] getFields()
Class[] getInterfaces()
. . but this is local loading
• When we call Class.forName(String) we use
the default class loader
• The JVM uses objects of type
java.lang.ClassLoader to load classes
dynamically
• The default loader uses the standard class path
• Specified by
• Environment variable CLASSPATH
• Command line option -classpath
Remote class loading - using HTTP
• To load classes from some remote source
we must create a new class loader that can
load remotely
• java.net.URLClassLoader is able to
load classes from URLs
• Allows us to load classes using the HTTP
protocol from any web server
java.net.URLClassLoader
• Constructor
• URLClassLoader(URL[] classPath)
• Useful methods:
• Class findClass(String qualifiedName)
• Does the same job as Class.forName()
• URL[] getURLs()
• … and a few others
java.net.URL
• Abstracts a universal resource locator
• Constructor
• URL(String urlName)
eg new URL(“http://asp/index.html”)
• Methods to take the URL apart,
such as
• String getHost()
• int getPort()
• String getPath()
Different ImageCreators
• Assume we have different ImageCreator
objects available on some remote system
• ImageCreator_GIF
• Decodes GIF image formats
• ImageCreator_JPG
• Decodes JPEG format images
• ImageCreator_BMP
• Decodes (256 colour) MS-Windows Device
Independent Bitmap files
• We want to be able to download and use the
appropriate one on demand
Loading Viewer classes
public ImageCreator loadImageCreator(String type) {
try {
// Get a URL as a text string from ...
String urlTextString = sourceURLText.getText();
// Form an array of URLs
URL[] sourceURLs =
new URL[] { new URL(urlTextString) };
// Construct the class loader
URLClassLoader loader =
new URLClassLoader(sourceURLs);
// Load the class
Class componentType = loader.loadClass(
"ImageCreator_" + type);
// Make an object of the class
return (ImageCreator) componentType.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
Exceptions, exceptions!
• java.net.MalformedURLException
• The (complex) format of the URL is invalid
• java.lang.ClassNotFoundException
• The class could not be loaded from the remote
location
• java.lang.ClassCastException
• The loaded class does not implement the
interface that we require
Remote loading alternative ...
• Remote Procedure Calls
• Idea has been around for at least 20 years
since Sun introduced RPC to SunOS
• RPC involves hiding a network communication
protocol so that programmers appear to simply
be calling procedures
• This idea adapts very easily to OO
programming as distributed objects
A Little History
• IBM lead the way with DSOM (late 80s)
• Microsoft developed this into the
distributed common object model (DCOM)
(ca.1995)
• Common Object Request Broker
Architecture (CORBA) developed by OMG
to provide platform and language
independence (1991/94)
• Sun developed Remote Method Invocation
(RMI) as a simpler alternative (1997)
Remote Method Invocation
• First introduced into JDK 1.1
• Java specific protocol aimed at simplicity
• Java is already platform independent
• Closely linked to the idea of client/server
• A server application provides some form of
service to zero or more clients
• A client program uses the service
• A Java interface defines the contract between
the two
The Object Registry
• Server advertises its services using a service
label
• A string naming the service
• It registers the label with a object registry
(rmiregistry) which runs as a daemon
• Clients connect to the object registry and ask
for the service they require
• Identifying it with the service label
• Clients must know where the object registry is
located (unlike in JINI)
• Clients obtain a reference to the desired
interface and can then call its methods
Loading remote components using RMI
• As an alternative we can use RMI to allow
us to load remotely
• We will look at the following parts:
• The service interface
• ImageCreatorService
• A server implementation class
• RMIComponentServer
• A client implementation class
• RMIClientViewer
RMI versus HTTP
• HTTP is really intended for document
downloads
• Using HTTP POST you can provide
parameters as part of a request
• Too specific for communication between
distributed objects
• RMI allows any object to
• Call any method in another object (locally or
remotely)
• Pass any list of parameters (not just Strings)
• Receive back any Java type as the return value
The ImageCreatorService interface
public interface ImageCreatorService
extends java.rmi.Remote
{
/**
Deliver the byte codes for an ImageCreator
component which will deal with images of the
specified type.
*/
public byte[] loadClassData(String compName)
throws RemoteException;
}
The component server
• Just a few simple steps to write the server:
• STEP ONE: Create a server class which
implements your interface and subclasses
java.rmi.server.UnicastRemoteObject
• STEP TWO: Make the server register itself
with the object registry
• STEP THREE: Implement the methods
cited in the service interface
The RMIComponentServer class
STEP ONE
public class RMIComponentServer
extends java.rmi.server.UnicastRemoteObject
implements ImageCreatorService
{
STEP TWO
public RMIComponentServer()
throws RemoteException
{
Service label
try {
java.rmi.Naming.rebind(
"rmi://localhost/ImageCreatorService", this);
} catch (MalformedURLException mue) {
mue.printStackTrace();
}
}
. . . .
The RMIComponentServer class
public byte[] loadClassData(String className)
throws RemoteException
{ // Implementation edited out for brevity. . .
}
public static void main(String[] args)
{
try {
System.out.println("RMIComponentServer: started.");
RMIComponentServer server =
new RMIComponentServer();
}
catch (Exception e) {
STEP THREE
e.printStackTrace();
}
}
The client viewer implementation
• This is in the form of RMIClientViewer
but the interesting part is the inner class
called RMIClassLoader
• This subclasses java.lang.ClassLoader
• The parent of all classes capable loading byte
codes
• RMIClassLoader loads byte codes with RMI
• Rather than HTTP (as in the previous example)
• Distributed memory space (all parameters are
passed by value, rather than by reference)
• RMI requires a different design discipline
Reliability Issues
• When calling a method locally there are
only two possible outcomes:
• The method succeeds
• The method fails with an exception
• When calling an RMI method there is a
third category:
• It was impossible to call the method, since the
RMI mechanism failed in some way
How does RMI work?
• It uses proxy classes called stubs and
skeletons
• RMI calls from the client are intercepted by
a proxy class called a stub
• They are passed to another proxy called a
skeleton residing on the server which calls
the server class on the client’s behalf
• Stubs and skeletons can be generated
using rmic
Proxy stubs
• Implements the chosen service interface
so it looks like the remote server as far as
the client is concerned
• Packages up (marshals) arguments for
dispatch across the network
• Sends them using the Java Remote
Method Protocol (JRMP)
• Waits for and unpacks the return value
Proxy skeletons
• Waits for JRMP request to be received
from a TCP/IP connection
• Unmarshals the arguments and passes
them on to server implementation
• Awaits a return value and marshals it to be
returned through the TCP/IP connection
• Not needed by JDK 1.2
How it all fits together
Client VM
Server VM
Client Obj
x=if.m()
Stub
Call
Skeleton
TCP/IP
link
int m() {
....
}
Retn
Service Interface
Server Impl.
Service Interface
rmic
• Remote interface compiler
• Specify your server implementation class
as a command line argument
eg rmic -classpath . RMIComponentServer
• Ascertains the service interfaces
• Creates a stub and a skeleton class for
each interface
eg RMIComponentServer_Stub.class
RMIComponentServer_Skel.class
• Recreate stubs and skeletons when you
modify the interfaces for your server
RMI Method Arguments
• What restrictions are there on RMI
arguments?
• By default parameters are passed by value
• NOTE: This is the opposite of the conventions
when calling a local method
• This is the normal behavior for primitive
types: byte, short, char, int,
long, float, double, boolean
• Objects must be pickled before being sent!
• They are marked as implementing the
Serializable interface
java.io.Serializable
• Contains no methods!
• Just a marker for those classes which are
may be serialized
• Into a file or
• Sent across the net to a different VM by RMI
• Many Java classes implement
java.io.Serializable
• Some notable exceptions: Runtime system
and Reflection API classes and some I/O
classes
Passing objects by reference
• It is possible to pass objects be reference,
but only if you design them specifically for
RMI
• STEP ONE: Make the object implement the
java.rmi.Remote interface
• STEP TWO: Export the object by
registering it using methods in
java.rmi.Naming
• In other words you are turning the object
into another RMI server in its own right
Inner class RMIClassLoader
• Part of the client side application which
wants to load the appropriate viewer class
• STEP ONE
• Create a reference to the required service
interface
• STEP TWO
• Lookup the service by connecting to the
chosen object registry
• STEP THREE
• Call a method through the interface
sea.picturelib.RMIClientViewer
public class RMIClassLoader extends ClassLoader
{
ImageCreatorService remoteService = null;
public RMIClassLoader(String serverName) STEP ONE
throws NotBoundException, MalformedURLException,
RemoteException
{
remoteService = (ImageCreatorService)
java.rmi.Naming.lookup(
"rmi://" + serverName + "/ImageCreatorService");
}
. . . .
STEP TWO
sea.picturelib.RMIClientViewer
public Class findClass(String name)
throws ClassNotFoundException
STEP THREE
{
try {
byte[] byteCodes =
remoteService.loadClassData(name);
return defineClass(
name, byteCodes, 0, byteCodes.length);
}
catch (RemoteException re) {
throw new ClassNotFoundException(
"failed to load class " + name + " using RMI");
}
}
}
It’s that simple. . .
• STEP ONE
• Define the service interface
• STEP TWO
• Write a server that implements the interface
• STEP THREE
• Make the server register with an object registry
• STEP FOUR
• Write a client that looks up the desired service
in the object registry
• STEP FIVE
• The client can call methods in its interface
. . . not quite!
• Some general RMI issues …
• RPC (RMI) can lull the designer into a false
sense of security!
• Beware! They may look like method calls but
they’re really network communications
• You will need a design that take into account
• Reliability issues
• Latency issues
Reliability Issues
• When a remote method cannot be called it throws
an exception in the java.rmi.RemoteException
hierarchy
• java.rmi.ConnectionException when the
network connection could not be established
• java.rmi.ConnectionIOException when the
network connection failed
• . . . and there are plenty of things that can go
wrong (17 other exception types)
Latency Issues
• Calling methods locally
• 100% reliable and
• only requires a few nanoseconds
• Not true for RMI
• Network might be congested (or down)
• Remote server may be busy (or down)
• RMI calls take a long time:
• About 1 ms in the best scenario (one million
times as long as a local method call!)
• Up to a 3 minute time-out
• DNS lookup fails
Latency Issues
• It is unwise to make RMI method calls from
any time-sensitive code
• User interface callback handlers
• Process/hardware controllers
• Control the network environment
• Make RMI calls in a separate thread
• Design an interface with coarse-grained
methods to minimize round trip delays
Accessing remote objects
• Why does an object need to be called
remotely?
• Only because it needs some resource that
the remote machine can offer
•
•
•
•
Some custom peripheral (a scanner?)
CPU/Memory resources
Intimate access to a database
Some other resource that you wish to manage
centrally
• If not, then copy back the bytes codes and
execute locally!
• This is starting to sound like JINI
Design Issues
• Work out where objects need to be within
the system architecture
• Why not get the RMI server to support the
ImageCreator interface directly?
• We could have passed the File object
across to the server but not the file!
• File implements Serializable
• We could need to create a remotely accessible
stream object
• Must then pass the image object back to
the client
• It is expensive to transfer large arrays of bytes
Other sources of information
• Lots of RMI information at Sun’s site
http://www.javasoft.com/products/jdk/rmi
• JRMP (RMI’s wire protocol) is described in
the downloadable documentation available
for each Java 1.2.X or 1.3.X VM or from
http://java.sun.com/j2se/1.3/docs/guide/rmi/..
spec/rmi-protocol#60
RemoteWorker
• Model
•
•
•
•
Master + n slave processors
Slaves do the work
Master distributes it and receives results
Work is done in a class which implements the
Solver interface
RemoteWorker
• Solver methods
• public void init( TaskDescriptor init_parms )
• Set up initial parameters (if any)
• public Result executeTask( TaskDescriptor td
)
• Solve the problem
• TaskDescriptor
• Marker interface
• Wrapper for arguments for init and executeTask
• Result
• Marker interface
• Wrapper for return value(s) from executeTask
RemoteWorker
• Setting up
• Start rmiregistry on each slave
• start rmiregistry
• Start RemoteWorker on each slave
• java -cp .
scl.RemoteWorker.RemoteWorker
• On master
• Run program which
• creates task descriptors
• puts them in a Q
• fires up a proxy for each slave
• send solver class to slave
• extract task descriptors from Q and send them to slaves
Creating a Class object
public ImageCreator loadCreator(String className)
throws ClassNotFoundException
{
Class type = Class.forName(className);
Class imageCreatorType = ImageCreator.class;
ImageCreator component = null;
Class[] interfaces = type.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].equals(imageCreatorType)) {
return (ImageCreator) type.newInstance();
}
}
return null;
}
Alternative approaches
• There are two other ways to test this:
if (ImageCreator.class.isAssignableFrom(type))
return (ImageCreator) type.newInstance();
else
return null;
• Or:
try {
return (ImageCreator) type.newInstance();
} catch (java.lang.ClassCastException cce) {
return null;
}
The price of deferred loading
• Compiler errors become exceptions!
• java.lang.ClassNotFoundException
• no (byte code) definition for the specified class
can be found
• java.lang.IllegalAccessException
• the constructor/method is private
• java.lang.InstantiationException
• the class does not have a valid constructor or
an attempt was made to instantiate a primitive:
• int i = new int(); // this is an error!