Using WebLogics RMI over IIOP
Using WebLogic s RMI over IIOP
RMI over IIOP (or RMI-IIOP) enables Java-based RMI objects to interoperate with CORBA-based application components. By using the OMG standard IIOP as the underlying transport protocol, Java clients can invoke CORBA objects, and likewise, CORBA clients can remotely invoke RMI objects. CORBA components may be written in a variety of languages, including C++, Smalltalk, Java, COBOL, and many more. RMI-IIOP combines the ease of use of RMI with cross-language interoperability provided by the CORBA/IIOP architecture.
WebLogic's RMI-IIOP implementation provides several options for implementing Java-based RMI and CORBA/IDL clients:
Standalone RMI clients
You can implement an RMI client that uses the JDK's IIOP implementation. This is ORB-based, and will not use any WebLogic libraries. As a result, the client can be kept quite trim, although this approach cannot make use of J2EE features such as transactions.
WebLogic fat clients
By simply changing the context factory used in the standalone RMI client, and including weblogic.jar, you can create a client that still communicates using IIOP, but doesn't use a client-side ORB. Instead, it uses an optimized WebLogic-specific RMI-IIOP implementation. As a result, the client is faster and more scalable, and can benefit from WebLogic features. Of course, the client will be quite large now.
J2EE clients
J2EE clients are application clients that are typically bundled with J2EE applications. These clients make use of the JDK 1.4 client-side ORB, and need to have WebLogic's thin client support library. As a result, these clients support WebLogic clustering and other J2EE features such as transactions and security.
CORBA/IDL clients
CORBA/IDL clients are typically clients written in some other language, using interfaces generated by an IDL compiler. These clients would not include WebLogic libraries, and would use IIOP with standard ORBs.
4.4.1 Standalone RMI Clients
By default, an RMI client uses WebLogic's T3 protocol when talking with RMI objects hosted by WebLogic Server. The J2EE 1.3 framework also requires that an RMI client is able to talk to RMI objects using the industry-standard IIOP as the underlying protocol. In principle, such a client is similar to Example 4-5, except that it uses the IIOP protocol and therefore must have access to an ORB. For instance, it could use the CORBA 2.3-compliant ORB shipped with Sun's Java SDK 1.3 distribution. Furthermore, the client doesn't require any of the WebLogic classes. It's simply an RMI client that communicates over the IIOP protocol. For this reason, it does not support enterprise features such as transactions or security.
Earlier we developed a simple RMI client-server program that used WebLogic's T3 protocol as the underlying transport mechanism. In order for the client to communicate with the RMI object over IIOP, you need to execute the following steps:
- After you've compiled the remote interface Add.java and the implementation class AddImpl.java, run the RMI compiler over the implementation class AddImpl.class using the -iiop option:
java weblogic.rmic -iiop com.oreilly.rmi.AddImpl
- Make sure that the class files generated from the remote interface, the implementation classes, and the stub classes are available to the server's classpath. This type of client does not use dynamic proxies.
- Modify the RMI client AddClient.java in the following way:
- Use com.sun.jndi.cosnaming.CNCtxFactory as the value for the JNDI context factory when creating the initial JNDI context. In this way, the client relies on Sun's JNDI client, which defaults to Sun's RMI-IIOP ORB implementation.
- Make sure you've specified an iiop:// scheme as the value for the client's Context.PROVIDER_URL property. This allows the client to tunnel RMI requests over IIOP. For example, we will connect to the local server using the URL iiop://localhost:7001.
- After the client performs a JNDI lookup, make sure it invokes the narrow( ) method on the javax.rmi.PortableRemoteObject class. This method checks to see whether the object of the remote interface may be cast to the desired type:
Add obj = (Add) javax.rmi.PortableRemoteObject.narrow( ic.lookup("AddServer"), Add.class);
The following code fragment encapsulates all the code changes needed to AddClient.java, before it can talk over IIOP:
public static void main(String[] argv) throws Exception { try { Hashtable env = new Hashtable( ); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory"); env.put(Context.PROVIDER_URL, "iiop://localhost:7001"); InitialContext ctx = new InitialContext(env); Add obj = (Add) javax.rmi.PortableRemoteObject.narrow( ic.lookup("AddServer"), Add.class); System.out.println("Successfully connected to AddServer " + obj.add(3,4) ); } catch (Throwable t) { t.printStackTrace( ); } }
Once you've registered the RMI object to the server's JNDI tree, you should get the following output when you run the client com.oreilly.rmi.AddClient:
Successfully connected to AddServer 7
|
We have already seen a use of the -iiop option for WebLogic's rmic compiler. The compiler supports additional IIOP-related options, as documented in Table 4-3.
Option |
Description |
---|---|
-idl |
This option instructs the RMI compiler to generate IDL files for the remote interfaces. |
-idlOverwrite |
This option directs the RMI compiler to overwrite any existing IDL files. |
-idlDirectory |
This option specifies the location of the folder where the IDL files should be generated. |
-idlStrict |
This option generates IDL files that conform to the OMG standard. |
-idlFactories |
This option directs the RMI compiler to generate factory methods for all value types. |
-idlNoValueTypes |
This option directs the RMI compiler to ignore all value types and any methods or attributes that refer to them. |
-idlOrbix |
This option instructs the RMI compiler to generate IDL files compliant with Orbix 2000 C++. |
-idlVisibroker |
This option directs the RMI compiler to generate IDL files compliant with Visibroker 4.5 C++. |
-iiop |
This option generates IIOP stubs for the server objects. |
-iiopDirectory |
This option specifies the location of the folder where the IIOP stubs ought to be generated. |
Make sure that you include %JAVA_HOME%lib ools.jar in your CLASSPATH before you attempt to generate the IIOP stubs for the RMI objects. WebLogic's RMI compiler relies on Sun's RMI compiler to generate the IIOP stubs.
4.4.2 WebLogic Fat Clients
The previous approach used the standard JDK classes, including the ORB supplied with the JDK. You also could vary this by using WebLogic's RMI-IIOP implementation on the client instead. In addition, the client must use WebLogic's initial context factory when contacting the server's JNDI:
Hashtable env = new Hashtable( ); env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); env.put(Context.PROVIDER_URL, "iiop://myserver:8001"); Context ctx = new InitialContext(env);
In return, though, you will find that the resulting client will no longer use an ORB, scales better, and can make use of all the standard WebLogic features available to clients.
4.4.3 J2EE Thin Clients
The J2EE supports application clients, which typically are shipped with a J2EE application and which can make use of J2EE features such as contexts and user transactions. This distinguishes these J2EE clients from ordinary Java clients. You can augment these clients with a WebLogic library, in which case the clients can utilize WebLogic features such as clustering and SSL. These clients (which in WebLogic 8.1 must run on a JDK 1.4 JVM) will use standard IIOP and the JVM's CORBA 2.4 ORB. J2EE thin clients created using this approach look similar to the fat clients. The only difference lies in the underlying mechanism:
Hashtable env = new Hashtable( ); env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); env.put(Context.PROVIDER_URL, "iiop://myserver:8001"); Context ctx = new InitialContext(env);
Note that regardless of the protocol specified in the provider URL, WebLogic will always use IIOP (or IIOPS as appropriate). If the client does not use JMS, simply bundle it with the wlcient.jar library, located in the WL_HOME/server/lib directory. If it does use JMS, include the wljmsclient.jar located in the same folder. Because early versions of the JDK 1.4 had errors in the CORBA implementation, we recommend you use the latest JVM edition for running your clients.
4.4.4 CORBA/IDL Clients
Let's now examine how you can write a CORBA/IDL client that can communicate with an RMI object through its IDL interface. WebLogic's RMI compiler (rmic) allows you to generate the IDL interface from a given RMI implementation class. You then can use a vendor-specific IDL compiler to generate the IIOP stubs and skeletons using the IDL interface. A CORBA/IDL client can use these generated classes to contact WebLogic Server, and access the remote interface exposed by the RMI object. WebLogic's ORB implements the objects-by-value specification. If you decide to use this feature, ensure that your client ORB also follows the specification.
In the following example, we will develop a Java-based CORBA client that uses the ORB implementation that comes with a standard JDK distribution. Let's assume that you've generated the class files for the remote interface and implementation class for some RMI object. In our earlier example, we generated the class files for com/oreilly/rmi/Add.java and com/oreilly/rmi/AddImpl.java. You can derive the IDL interface file from the implementation class using WebLogic's RMI compiler as follows:
java weblogic.rmic -idl com.oreilly.rmi.AddImpl
The RMI compiler generates the file com/oreilly/rmi/Add.idl, which captures the IDL interface for the RMI object. This IDL interface then can be passed through an IDL compiler to generate the IIOP stubs needed by our Java-based CORBA/IDL client. In this case, we will use the IDL compiler (idlj) that is included with Sun's Java SDK distribution:
%JAVA_HOME%inidlj comoreilly miAdd.idl
If you examine the IDL interface generated for the RMI object, you will see that it contains an include directive:
#include orb.idl
This IDL file is supplied by the ORB vendor. Because we are using Sun's Java SDK, we use the IDL located at %JAVA_HOME%liborb.idl. The IDL file orb.idl in turn contains another include directive:
#include ir.idl
This file also is located in the same folder. You must copy these two IDL files to the folder from which you intend to run the IDL compiler.
Now, all that remains is your Java-based CORBA client that will invoke the RMI object. Example 4-8 lists the code for a Java-based CORBA client AddIIOPClient.java that will invoke the RMI object.
Example 4-8. Java-based CORBA client for the RMI object
package com.oreilly.rmi; import org.omg.CosNaming.*; // AddClient will use the naming service. import org.omg.CORBA.*; // All CORBA applications need these classes. public class AddIIOPClient { public static void main(String args[]) { try { // Create and initialize the ORB ORB orb = ORB.init(args, null); // Get the root naming context org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); // Look up the naming service for the RMI object NameComponent nc = new NameComponent("AddServer", ""); NameComponent path[] = {nc}; Add obj = AddHelper.narrow(ncRef.resolve(path)); // Invoke the remote method on the RMI object System.out.println("Successfully invoked AddServer " + obj.add(3,4)); } catch(Exception e) { System.out.println("ERROR : " + e); e.printStackTrace(System.out); } } }
The code fragment in Example 4-8 is very similar to the RMI-IIOP version of AddClient.java. Like its RMI-IIOP counterpart, the CORBA client first attempts to acquire the root naming context, uses it to obtain a reference to the RMI object from the naming service, and finally invokes the methods exposed by its remote IDL interface. When you compile com/oreilly/rmi/AddClient.java, you find that the auxiliary source files generated previously by the IDL compiler are also compiled. Now, in order to run the client, you need to specify arguments for the hostname and port that identify where the naming service can be found:
java com.oreilly.rmi.AddClient -OrbInitialHost localhost -ORBInitialPort 7001
Here, the hostname and port refer to the listen address and listen port on which your WebLogic Server instance is running. If the client executes successfully, you should get the following output:
Successfully invoked AddServer 7
4.4.5 Configuring RMI-IIOP
In order to view or adjust the IIOP configuration settings for WebLogic Server, select a server from the left pane of the Administration Console and then choose the Protocols/IIOP tab.[1] Select the Enable IIOP checkbox to enable the server to listen for IIOP requests. You also can specify the username and password to set up a default identity for all clients who have established IIOP connections with the particular server. By default, the anonymous user will be used. Use the IIOP Max Message Size field to set the maximum size (in bytes) of an IIOP request. Use the IIOP Message Timeout field to set the timeout duration (in seconds) for an IIOP request. These two fields help prevent denial-of-service (DOS) attacks to WebLogic Server.
[1] In WebLogic 7.0, choose the Connections/Protocols tab.
No additional configuration is needed to set up RMI-over-IIOP. If your RMI objects have been bound to the JNDI tree properly, they will be available automatically to all (authorized) clients that can talk over RMI or RMI-over-IIOP. Typically, RMI objects are bound to the JNDI tree when the server starts up, and EJB home objects are bound when the actual EJB component is deployed to the server instance. WebLogic also supports RMI-IIOP with SSL for RMI and CORBA/IDL clients. Chapter 16 provides information on how you can configure SSL support for WebLogic Server.