RMI Introduction

Remote Method Invocation (RMI) represents a higher level view of networking than sockets. Much of the low level system is hidden from the programmer. In particular, a protocol, the RMI protocol, is provided for you. A difficult and error prone programming situation is avoided. RMI is a pure Java implementation for distributed computing. It is similar to, but much simpler than CORBA (Common Object Request Broker Architecture) because CORBA is built to operate in a multilingual environment with legacy systems. RMI is somewhat similar to RPC (Remote Procedure Calls) or procedural languages. But RMI is object oriented. Remote Method Invocation (RMI) facilitates object function calls between Java Virtual Machines (JVMs). JVMs can be located on separate computers - yet one JVM can invoke methods belonging to an object stored in another JVM. Methods can even pass objects that a foreign virtual machine has never encountered before, allowing dynamic loading of new classes as required. This is a powerful feature! Consider the follow scenario : • • Developer A writes a service that performs some useful function. He regularly updates this service, adding new features and improving existing ones. Developer B wishes to use the service provided by Developer A. However, it's inconvenient for A to supply B with an update every time.

Java RMI provides a very easy solution! Since RMI can dynamically load new classes, Developer B can let RMI handle updates automatically for him. Developer A places the new classes in a web directory, where RMI can fetch the new updates as they are required.

- Connections made when client uses RMI

The RMI Architecture

These layers are independent of one another. Each implements its own interface and protocol. Each could be replaced with other implementations without affecting the others.

The Transport Layer
At the present time this is the standard TCP layer on IP.

Remote Reference Layer
This middle layer sets up connections to remote address spaces, manages connections, listens for incoming calls, and various other purposes.

Stub and Skeleton Layer
The RMI programmer does not see the transport and remote reference layers. The stubs and skeletons do appear to the programmer. (One of the most annoying bugs in RMI programming is losing track of the stub!). The stubs and skeletons are not written by the programmer. They are generated by a special compiler called rmic. Stubs and skeletons represent the interface between the RMI system and the application programs. The stub is a proxy at the client side for a remote object. The skeleton represents information about the client at the server side.
Responsibilities of the stub

The client side stub representing a remote object does the following:
• • initiating remote calls marshaling arguments to be sent

• • •

informing the remote reference layer that a call should be invoked on the server unmarshalling a return value (or exception) informing the remote reference layer that the call is complete

Responsibities of the skeleton

On the server, the skeleton,
• • • unmarshals incoming arguments calling the actual remote object implementation marshaling return values for transport to the client

Operation of an RMI Distributed System: summary
In a typical distributed system using RMI we have a server and a number of clients, usually running on different hosts. The server advertises to the clients which of its methods may be called from remote locations. Such methods must extend the class java.rmi.Remote, and be defined in an interface. The server implements this interface. The server developer must also run the rmic compiler on the server class to create the stub and skeleton classes. The clients must also have access to the interface containing the remotelycallable methods. The client must also have access to the stub class (but not the skeleton) generated on the server by the rmic. With all these files in place, the rmi registry is run on the server. The registry provides a naming service accessible to the clients. Then the server is run and it must register itself with the registry. The server side of the system is now ready to do its thing. The clients now access the server facilites by contacting the registry to get a reference to the server object. Once this reference is obtained, the remotely accessible methods on the server can be invoked just as if they were local on the client. Of course, they execeute on the server. The stub is a proxy, or represntative, on the client, representing the actual method which resides on the server.
RMI Implementation We will start by coding the remote object. import java.rmi.*; public interface AddServer extends Remote { public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException; }

We will now start coding the remote object implementation. This is the class that would implement the remote object and contain all of the method bodies. import java.rmi.*; import java.rmi.server.UnicastRemoteObject; import java.rmi.RemoteException; public class AddServerImpl extends UnicastRemoteObject implements AddServer { public AddServerImpl() throws RemoteException { super(); } public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException { return firstnumber + secondnumber; } } At this point we have two Java files: the remote object and the remote object implementation. We will now compile both of these file using the Javac command We end up with two Java files and two class files. We are now going to create our stub and skeleton. For creating the stub and skeleton files we have to use the rmic compiler on the remote object implementation file. rmic AddServerImpl After following the above step you will see that two newer class files have been created. They are AddServerImpl_Stub.class (the stub which will reside on the client side) and AddServerImpl_Skel.class (the skeleton which will reside on the server side). Since we have the entire source compiled, let's create our client and server to see this demo in action. import java.rmi.*; import java.net.*;

public class RmiServer { public static void main (String args[]) throws RemoteException, MalformedURLException { AddServerImpl add = new AddServerImpl(); Naming.rebind("addnumbers",add); } } From now on, whenever the client wants to make a reference to the remote object it would use the string addnumbers to do so. The rebind method takes two parameters: first, the string variable and second the object of the remote object implementation class. Let's create the client. import java.rmi.*; import java.net.*; public class RmiClient { public static void main(String args[]) throws RemoteException, MalformedURLException, NotBoundException { String url="rmi://127.0.0.1/addnumbers"; AddServer add; add = (AddServer)Naming.lookup(url); int result = add.AddNumbers(10,5); System.out.println(result); } } The lookup method takes the complete URL name of the remote object, which consists of the complete machine I.P. address and the string which the object is

associated to. This is the binding name of the object. As you can see, we use the RMI protocol to reference the remote object. This lookup method returns an object to us that we will have to typecast to the remote object data type before it can be used. Typecasting is a process through which we convert data from one data type to the other. Since we have both our server and client source ready, let's compile them both: Before we start testing our code we have to start the RMI Registry. The RMI registry is the place where all the bound data will be stored. Without it RMI wouldn't work! Start Rmi Registry Server: C:\jdk\bin\start rmiregistry You will notice a new blank DOS prompt window will open. That's the RMI registry running. Make sure you leave it open as it is. Just like client server code, we first run the Rmi server in one DOS Prompt and then the RMI client in the other. If everything worked out well then you should get the output of 15. We passed two integer values 10 and 5 to the AddNumbers method, which added them and returned an integer 15 back to us. If you got 15 then you have successfully executed a remote method. Of course, its not remote in the true sense as in this case you are the client and the server, but if you have a network then you can easily try this remotely. CORBA Distributed Applications Data are Distributed Computation is Distributed Users are Distributed Distributed Object Systems

Distributed object systems are distributed systems in which all entities are modeled as objects. Distributed object systems are a popular paradigm for object-oriented distributed applications. Since the application is modeled as a set of cooperating objects, it maps very naturally to the services of the distributed system. In spite of the natural mapping from object-oriented modeling to distributed object systems, do not forget the realities of distributed systems described above. Process boundaries really do matter and they will impact your design. That said, the next section of this course discusses the CORBA standard for distributed object systems.

What is CORBA?

CORBA, or Common Object Request Broker Architecture, is a standard architecture for distributed object systems. It allows a distributed, heterogeneous collection of objects to interoperate.
The OMG

The Object Management Group (OMG) is responsible for defining CORBA. The OMG comprises over 700 companies and organizations, including almost all the major vendors and developers of distributed object technology, including platform, database, and application vendors as well as software tool and corporate developers.
CORBA Architecture

CORBA defines an architecture for distributed objects. The basic CORBA paradigm is that of a request for services of a distributed object. Everything else defined by the OMG is in terms of this basic paradigm. The services that an object provides are given by its interface. Interfaces are defined in OMG's Interface Definition Language (IDL). Distributed objects are identified by object references, which are typed by IDL interfaces. The figure below graphically depicts a request. A client holds an object reference to a distributed object. The object reference is typed by an interface. In the figure below the object reference is typed by the Rabbit interface. The Object Request Broker, or ORB, delivers the request to the object and returns any results to the client. In the figure, a jump request returns an object reference typed by the AnotherObject interface.

The ORB

The ORB is the distributed service that implements the request to the remote object. It locates the remote object on the network, communicates the request to the object, waits for the results and when available communicates those results back to the client. The ORB implements location transparency. Exactly the same request mechanism is used by the client and the CORBA object regardless of where the object is located. It might be in the same process with the client, down the hall or across the planet. The client cannot tell the difference. The ORB implements programming language independence for the request. The client issuing the request can be written in a different programming language from the implementation of the CORBA object. The ORB does the necessary translation between programming languages. Language bindings are defined for all popular programming languages.

CORBA as a Standard for Distributed Objects

One of the goals of the CORBA specification is that clients and object implementations are portable. The CORBA specification defines an application programmer's interface (API) for clients of a distributed object as well as an API for the implementation of a CORBA object. This means that code written for one vendor's CORBA product could, with a minimum of effort, be rewritten to work with a different vendor's product. However, the reality of CORBA products on the market today is that CORBA clients are portable but object implementations need some rework to port from one CORBA product to another. CORBA 2.0 added interoperability as a goal in the specification. In particular, CORBA 2.0 defines a network protocol, called IIOP (Internet Inter-ORB Protocol), that allows clients using a CORBA product from any vendor to communicate with objects using a CORBA product from any other vendor. IIOP works across the Internet, or more precisely, across any TCP/IP implementation. Interoperability is more important in a distributed system than portability. IIOP is used in other systems that do not even attempt to provide the CORBA API. In particular, IIOP is used as the transport protocol for a version of Java RMI (so called "RMI over IIOP"). Since EJB is defined in terms of RMI, it too can use IIOP. Various application servers available on the market use IIOP but do not expose the entire CORBA API. Because they all use IIOP, programs written to these different API's can interoperate with each other and with programs written to the CORBA API.
CORBA Services

Another important part of the CORBA standard is the definition of a set of distributed services to support the integration and interoperation of distributed objects. As depicted in the graphic below, the services, known as CORBA Services or COS, are defined on top of the ORB. That is, they are defined as standard CORBA objects with IDL interfaces, sometimes referred to as "Object Services."

There are several CORBA services. The popular ones are described in detail in another module of this course. Below is a brief description of each: Service Object life cycle Naming Description Defines how CORBA objects are created, removed, moved, and copied Defines how CORBA objects can have friendly symbolic names

Events Relationships Externalization Transactions Concurrency Control Property Trader Query

Decouples the communication between distributed objects Provides arbitrary typed n-ary relationships between CORBA objects Coordinates the transformation of CORBA objects to and from external media Coordinates atomic access to CORBA objects Provides a locking service for CORBA objects in order to ensure serializable access Supports the association of name-value pairs with CORBA objects Supports the finding of CORBA objects based on properties describing the service offered by the object Supports queries on objects

Example : The Stock Application CORBA Objects are Described by IDL Interfaces

The OMG Interface Definition Language IDL supports the specification of object interfaces. An object interface indicates the operations the object supports, but not how they are implemented. That is, in IDL there is no way to declare object state and algorithms. The implementation of a CORBA object is provided in a standard programming language, such as the Java programming language or C++. An interface specifies the contract between code using the object and the code implementing the object. Clients only depend on the interface. IDL interfaces are programming language neutral. IDL defines language bindings for many different programming languages. This allows an object implementor to choose the appropriate programming language for the object. Similarly, it allows the developer of the client to choose the appropriate and possibly different programming language for the client. Currently, the OMG has standardized on language bindings for the C, C++, Java, Ada, COBOL, Smalltalk, Objective C, and Lisp programming languages. So by using OMG IDL, the following can be described without regards to any particular programming language:
• • • • Modularized object interfaces Operations and attributes that an object supports Exceptions raised by an operation Data types of an operation return value, its parameters, and an object's attributes Basic data types (long, short, string, float...) Constructed data types (struct, union, enum, sequence) Typed object references

The IDL data types are:
• • •

The any type, a dynamically typed value

Again, IDL says nothing about object implementations. Here's the IDL interface for the example stock objects:
module StockObjects { struct Quote { string symbol; long at_time; double price; long volume; }; exception Unknown{}; interface Stock { // Returns the current stock quote. Quote get_quote() raises(Unknown); // Sets the current stock quote. void set_quote(in Quote stock_quote); // Provides the stock description, // e.g. company name. readonly attribute string description;

};

interface StockFactory { Stock create_stock( in string symbol, in string description );

}; };

Note that the above example defines an IDL module named StockObjects, which contains the:
• • • • Data structure Quote Exception Unknown Interface Stock Interface StockFactory

The module defines a scope for these names. Within the module, a data structure Quote and an exception Unknown are defined and then used in the Stock interface. The Stock interface is used in the definition of the StockFactory interface. Also note that the parameters to operations are tagged with the keywords in, out, or inout. The in keyword indicates the data are passed from the client to the object. The out keyword indicates that the data are returned from the object to

the client, and inout indicates that the data are passed from the client to the object and then returned to the client. IDL declarations are compiled with an IDL compiler and converted to their associated representations in the target programming languages according to the standard language binding.

Sign up to vote on this title
UsefulNot useful