Chapter 14. Servers III—RMI/IIOP

  • Introduction—CORBA—EJBs—PortableRemoteObject—Writing the server—Building the server—Java/IDL tool—Supporting both jrmp and IIOP—Restrictions—Implementing the service in another language—IIOP Clients—Implementing the client in another language—Exercises

In this chapter

We have discussed simple “unicast” servers in Chapter 7, and activatable servers in Chapter 10. This chapter describes how to write and implement RMI over IIOP (Internet Inter-ORB protocol). It discusses IIOP servers, dual-mode JRMP+IIOP servers, implementing the service and/or the client in another language, and lists the restrictions imposed by IIOP as compared to JRMP.

Introduction

IIOP is the transport protocol adopted by the Object Management Group (OMG) for CORBA. It provides interoperability with CORBA object implementations in various languages.[1]

Normally, the underlying transport for RMI is JRMP, [2] which is only understood by Java RMI programs.

RMI over IIOP allows Java programmers to program to the RMI interfaces but use IIOP as the underlying transport, so as to be interoperable with CORBA, and with any services which are interoperable with CORBA. Java RMI programmers can therefore participate in CORBA services networks with services and clients implemented in any of the languages supported by CORBA, subject to the restrictions defined in § 14.10.

The reason that RMI over IIOP is possible is that, in RMI, the stub implements the protocol, and ultimately the server provides its own stub. An RMI client has no knowledge of the protocol used by the stub to communicate with the server. An RMI over IIOP client is not very different from an RMI over JRMP client: it just obtains the remote reference in a different way: from a COS Naming service, rather than an RMI registry or a previously obtained and serialized activatable stub.

RMI/IIOP and CORBA

Using Java RMI over IIOP allows developers to work completely in the Java programming language, without having to learn or use CORBA IDL. Having done so, they can then generate IDL from the working Java application or prototype, and proceed to develop other components in other languages. CORBA IDL can be produced automatically from remote RMI/IIOP interfaces, and these can be generated into stubs/skeletons/frameworks/whatever for any other programming languages supported by your Object Request Broker (ORB).

RMI/IIOP and Enterprise Java Beans

Enterprise Java Beans (EJBs) are server-side components of applications based on the J2EE platform. EJBs communicate via RMI interfaces—they are RMI remote objects. The EJB 1.1 specification recommends, and the 2.0 specification will require, that EJB implementations support RMI/IIOP.[3]

PortableRemoteObject

The javax.rmi.PortableRemoteObject class is provided to help you define “portable remote objects”: RMI servers which communicate over RMI/IIOP. It is a precise analogue of java.rmi.server.UnicastRemoteObject, discussed in Chapter 7: it provides a constructor, an exportObject method, and an unexportObject method. The differences between portable remote objects and unicast or activatable remote objects are as follows:

  • portable remote objects communicate via IIOP instead of JRMP

  • portable remote objects do not participate in DGC

  • portable remote objects must be compiled by rmic with the -iiop flag

  • portable remote objects do not support explicit port numbers or socket factories.

Writing the server

In writing portable remote objects, you have three choices.

Extend PortableRemoteObject

A portable remote object can extend PortableRemoteObject, as shown in Example 14.1.

Example 14.1. Extending PortableRemoteObject

import javax.rmi.PortableRemoteObject;

public class MyIIOPServer extends PortableRemoteObject
       implements MyRemote
{
       public MyIIOPServer() throws RemoteException {}
       // implementations of remote methods not shown
}

Extend RemoteObject

A portable remote object can extend RemoteObject (but not RemoteServer: see § 14.10), as shown in Example 14.2.

Example 14.2. Extending RemoteObject

import javax.rmi.PortableRemoteObject;

public class MyIIOPServer extends RemoteObject implements MyRemote
{
       public MyIIOPServer() throws RemoteException
       {
              PortableRemoteObject.exportObject(this);
       }
       // implementations of remote methods not shown
}

Extend another class

A portable remote object can extend any other class except UnicastRemoteObject and Activatable. Such a server must either export itself or be exported by someone else. Normally such a server would export itself on construction by calling PortableRemoteObject.exportObject, as shown in Example 14.3.

Example 14.3. Extending another class

import javax.rmi.PortableRemoteObject;

public class MyIIOPServer /*extends java.lang.Object*/ implements MyRemote
{
       public MyIIOPServer() throws RemoteException
       {
             PortableRemoteObject.exportObject(this);
       }
       // implementations of remote methods not shown
}

Building the server

As usual, you run rmic against the server class, but for IIOP you must specify the -iiop flag. This causes rmic to produce CORBA stub and “tie” classes, instead of the JRMP stub (and skeleton) classes.

In CORBA, tie classes are used on the server side to process incoming calls, and dispatch the calls to the proper implementation class. Each implementation class requires a tie class.

If you need to generate IDL, run rmic with the -idl flag. You will need IDL if non-Java clients are to be produced. You may also need IDL with ORBs other than the one provided with Java.

Java/IDL tool

Java also provides the idlj tool.[4] This generates Java bindings from CORBA IDL interface definitions. The idlj tool operates in the IDL-to-Java direction, whereas rmic -idl operates in the Java-to-IDL direction. idlj is not used in RMI/IIOP. For more information about this tool consult the JDK documentation.

Supporting both JRMP and IIOP

It is possible to write a portable remote object in such a way that it supports both IIOP and JRMP clients. You need to do the following:

  1. Do not extend either UnicastRemoteObject or PortableRemoteObject.

  2. Such an object will not automatically export itself on construction. Normally you would export the object by calling UnicastRemoteObject.exportObject or PortableRemoteObject.exportObject, depending on which protocol you wanted to support. In this case you want to support both protocols, so call both methods.

  3. Use JNDI with both the RMI registry and the COS Naming plugins: create two InitialContexts, one to allow binding to the RMI registry and one to the COS Naming service, and bind the server in both.

  4. Do not pass the naming service as a command line argument using the -D option.

Part of a dual-protocol RMI server for a remote interface MyRemote is shown in Example 14.4.

Example 14.4. Dual-protocol RMI server

import java.rmi.*;
import java.rmi.server.*;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.rmi.*;

public class MyDualServer /*extends java.lang.Object*/ implements MyRemote
{
       public MyDualServer() throws RemoteException
       {
              UnicastRemoteObject.exportObject(this);    // Export to JRMP
              PortableRemoteObject.exportObject(this);   // Export to IIOP
       }

       // implementations of remote methods not shown

       public static void    main(String[] args) throws Exception
       {
              System.setSecurityManager(new RMISecurityManager());
              MyDualServerserver = new MyDualServer();

              // Bind to RMI Registry
              Properties      jrmpProps = new Properties();
              jmpProps.put("java.naming.factory.initial",
                    "com.sun.jndi.rmi.registry.RegistryContextFactory");
              InitialContextjrmpCtx = new InitialContext(jrmpProps);
              jrmpCtx.rebind("MyRemote",server);

              // Bind to COSNaming
              Properties    iiopProps = new Properties();
              iiopProps.put("java.naming.factory.initial",
                  "com.sun.jndi.cosnaming.CNCtxFactory");
              InitialContextiiopProps = new InitialContext(iiopProps);
              iiopProps.rebind("MyRemote",server);
       }
}

Restrictions

RMI/IIOP is designed as the intersection of RMI and CORBA. It is not intended to contain all the features—the union—of both.

RMI/IIOP provides the ability to define services (servers) written in Java and export them to CORBA, to write Java clients for CORBA services, or both. The following restrictions apply to RMI/IIOP as compared to RMI/JRMP.

  1. All the remote interfaces concerned must originally have been defined as Java RMI interfaces. It is not possible to “import” interfaces previously defined in other languages, or in CORBA IDL, into the RMI/IIOP scheme.

  2. The ORB must support the Objects By Value feature of CORBA 2.3, introduced to support Java.

  3. You must use JNDI with the COS Naming plugin, instead of the RMI registry as the naming service. Refer to Chapter 13 for more information.

  4. Portable remote objects cannot be activatable. The activation protocol is only supported over JRMP.

  5. Remote interfaces must not be cast just by inline Java casts; instead they must be cast by calls to the PortableRemoteObject.narrow method. A CORBA network operation is required to perform the cast.

  6. Constant definitions in remote interfaces may only be of primitive or String type, and must be evaluated at compile time.

  7. The same method name cannot be inherited into a remote interface from more than one base remote interface.

  8. Java names that conflict with IDL “mangled” names generated by the Java-to-IDL mapping must be avoided, as must method names inherited from more than one remote interface, and names that differ only in case. The case of a type name and a variable of that type whose name differs only in case is supported, but most other combinations are not supported.

  9. Derivation from UnicastRemoteObject and Activatable, explicit port numbers, RMI socket factories, and the DGC interfaces are not supported. IIOP does not support DGC, hence the Unreferenced interface is not supported—you can still implement it, but your unreferenced method will never be invoked via IIOP.

  10. As discussed in § 3.9.3, RMI/IIOP only properly supports the class versioning features of Serialization from JDK 1.3.1.

  11. Runtime sharing of remote object references is not preserved exactly when transmitting object references across IIOP. Runtime sharing of other objects is preserved correctly. In the terminology introduced in § 3.4.2, object graphs containing remote references of in-degree > 1 are not transmitted correctly, but all other object graphs, including those containing non-remote references of in-degree > 1, are transmitted correctly.

  12. rmic -iiop enforces an undocumented rule that server classes cannot just implement java.rmi.Remote: they must implement a concrete remote interface which contains methods. In consequence, a server class cannot be derived from java.rmi.server.RemoteServer, although it can be derived from java.rmi.server.RemoteObject.

Implementing the service in another language

In theory, once you have produced the IDL for the remote service, you can implement the service in another language. In practice this depends whether your ORB vendor supports the Objects By Value feature of CORBA 2.3 for the language required. The Objects By Value feature is only defined for Java and C++.

IIOP clients

As we have seen, an RMI client is remarkably like the client of a local object. The only real differences are the source of the object and the use of an intermediate interface to access the object so obtained.

Similarly, an RMI/IIOP client is remarkably like an RMI/JRMP client. Again, the only real differences are the source of the object and the use of an intermediate interface to access the object so obtained.

Naming services

RMI/IIOP clients must use JNDI with the COS Naming plugin as their naming service, rather than the RMI registry. IIOP servers must be registered with COS Naming, not with the RMI registry.

This is due to the CORBA Inter-Object Reference (IOR) mechanism. Briefly, the intervention of the COS Naming service is initially required to obtain the IIOP remote stub from its IOR.

Using the remote interface

When a remote object has been obtained, either from COS Naming or via another RMI/IIOP call, it must be cast to the type of the remote interface expected. The corresponding RMI/JRMP operation is accomplished by a simple Java language cast as shown in Example 14.5.

Example 14.5. RMI/JRMP cast

MyRemote myRemote = (MyRemote)object;

In RMI/IIOP, a CORBA network operation is required to check and implement the cast, as shown in Example 14.6.

Example 14.6. RMI/IIOP cast

MyRemote myRemote = (MyRemote)PortableRemoteObject
                    .narrow(object,MyRemote.class);

An RMI/IIOP client for the service of Example 14.4 is illustrated in Example 14.7.

Example 14.7. RMI/IIOP client

import java.rmi.*;
import java.util.Properties;
import javax.naming.InitialContext;

public class MyRemoteClient
{
       public static voidmain(String[] args) throws Exception
       {
              System.setSecurityManager(new RMISecurityManager());

              // Lookup CosNaming via JNDI
              Properties  props = new Properties();
              props.put("java.naming.factory.initial",
                    "com.sun.jndi.cosnaming.CNCtxFactory");
              InitialContextctx = new InitialContext(props);
              Objectobj = ctx.lookup("MyRemote");

              // Got the object: perform the CORBA cast
              MyRemote      mr = (MyRemote)PortableRemoteObject
                                      .narrow(obj,MyRemote.class);

              // methods on mr can now be invoked
       }
}

Implementing the client in another language

A non-Java client can be written for a Java RMI/IIOP server. How you actually do this is dependent on your ORB. You will need to use an ORB other than the one provided with Java 2, and you will need the IDL to be generated from the remote interface, by using rmic -idl. Consult your ORB vendor's documentation for further information about how to write a client in your choice of language starting from an IDL interface definition.

Exercises

1:

Adapt the remote date/time server exercises of Chapter 7 to use IIOP instead of JRMP, and JNDI with the COS Naming plugin instead of the RMI registry. Create a new client as well, which looks up the service in the COS Naming service via JNDI. Run the system and show all output.

2:

Adapt the remote date/time server of the previous exercise to use JRMP and IIOP. Write yet another client for this service which uses JRMP: i.e. which looks up the service in the RMI registry (or JNDI with the RMI registry plugin), not JNDI/COS Naming. Run the IIOP client from the previous exercise and show all output.

3:

Using, successively, the servers of the previous exercises, run the original date/time client of Chapter 7, which uses the RMI registry. In each case, does it work? If so, why? If not, why not?

4:

Run the server of the previous exercise with the property java.rmi.server.logCalls set to true. Run the IIOP client and note the output at the server. Run the JRMP client and note the output at the server. Comment.



[1] CORBA defines three layered protocols: (a) the Common Data Representation (CDR), (b) the General Inter-ORB protocol (GIOP), which includes CDR and in addition specifies GIOP message formats and transport assumptions, and (c) IIOP, which specializes GIOP to TCP/IP, specifying how agents open connections and use them for GIOP message transfer.

[2] “The RMI Wire Protocol”, RMI specification, §10. This incorporates the Object Serialization Stream Protocol, Serialization specification, §6.

[3] Enterprise JavaBeans Specification, version 1.1, § 4.4; proposed final draft 2.0, § 4.4.

[4] Prior to JDK 1.3, an idltojava tool was also provided. This tool dated from before RMI/IIOP, and is superseded by idlj in JDK 1.3.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.184.200