|
A Simple CORBA ExampleThe standard introductory example to any new system is "hello world." and it seems to get more complex with every advance that is made in computing technology! A CORBA version can be defined by the following IDL: module corba { module HelloModule { interface Hello { string getHello(); }; }; }; This code can be compiled into Java using a compiler such as Sun's idltojava (or another CORBA 2.2 compliant compiler). This results in a corba.HelloModule package containing a number of classes and interfaces. Hello is an interface that is used by a CORBA client (in Java). package corba.HelloModule; public interface Hello extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity { String getHello(); } CORBA Server in JavaA server for the hello IDL can be written in any language with a CORBA binding, such as C++. Rather than get diverted into other languages, though, we will stick to a Java implementation. However, this language choice is not forced on us by CORBA. The server must create an object that implements the Hello interface. This is done by creating a servant that inherits from the HelloImplBase and then registering it with the CORBA ORB (Object Request Broker ”this is the CORBA backplane , which acts as the runtime link between different objects in a CORBA system). The servant is the CORBA term for what we have been calling the "backend service" in Jini, and this object is created and run by the server. The server must also find a name server and register the name and the servant implementation. The servant implements the Hello interface. The server can just sleep to continue existence after registering the servant. /** * CorbaHelloServer.java */ package corba; import corba.HelloModule.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; public class CorbaHelloServer { public CorbaHelloServer() { } public static void main(String[] args) { try { // create a Hello implementation object ORB orb = ORB.init(args, null); HelloImpl hello = new HelloImpl(); orb.connect(hello); // get the name server org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext namingContext = NamingContextHelper.narrow(objRef); // bind the Hello service to the name server NameComponent nameComponent = new NameComponent("Hello", ""); NameComponent path[] = {nameComponent}; namingContext.rebind(path, hello); // sleep java.lang.Object sleep = new java.lang.Object(); synchronized(sleep) { sleep.wait(); } } catch(Exception e) { e.printStackTrace(); } } } // CorbaHelloServer class HelloImpl extends _HelloImplBase { public String getHello() { return("hello world"); } } CORBA Client in JavaA standalone client finds a proxy implementing the Hello interface with methods such as one that looks up a CORBA name server. The name server returns a org.omg.CORBA.Object , which is cast to the interface type by the HelloHelper method narrow() (the Java cast method is not used). This proxy object can then be used to call methods back in the CORBA server. /** * CorbaHelloClient.java */ package corba; import corba.HelloModule.*; import org.omg.CosNaming.*; import org.omg.CORBA.*; public class CorbaHelloClient { public CorbaHelloClient() { } public static void main(String[] args) { try { ORB orb = ORB.init(args, null); // get the name server org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext namingContext = NamingContextHelper.narrow(objRef); // get the Hello proxy NameComponent nameComponent = new NameComponent("Hello", ""); NameComponent path[] = {nameComponent}; org.omg.CORBA.Object obj = namingContext.resolve(path); Hello hello = HelloHelper.narrow(obj); // now invoke methods on the CORBA proxy String hello = hello.getHello(); System.out.println(hello); } catch(Exception e) { e.printStackTrace(); } } } // CorbaHelloClient Jini ServiceIn order to make the CORBA object accessible to the Jini world, it must be turned into a Jini service. At the same time it must remain in a CORBA server, so that it can be used by ordinary CORBA clients. So we can do nothing to the CORBA server. Instead, we need to build a Jini service that will act as a CORBA client. This service will then be able to deliver the CORBA service to Jini clients . The Jini service can be implemented as a fat proxy delivered to a Jini client. The Jini service implementation is moved from the Jini server to a Jini client as the service object. Once in the client, the service implementation is responsible for locating the CORBA service by using the CORBA naming service, and it then translates client calls on the Jini service directly into calls on the CORBA service. The processes that run in this, with their associated Jini and CORBA objects, are shown in Figure 18-1. Figure 18-1: CORBA and Jini services The Java interface for this service is quite simple and basically just copies the interface for the CORBA service: /** * JiniHello.java */ package corba; import java.io.Serializable; public interface JiniHello extends Serializable { public String getHello(); } // JiniHello The getHello() method for the CORBA IDL returns a string . In the Java binding this becomes an ordinary Java String , and the Jini service can just use this type. The next example (in the "Room-Booking Example" section) will show a more complex case where CORBA objects may be returned. Note that because this is a fat service, any implementation will get moved across to a Jini client and will run there, so the service only needs to implement Serializable , and its methods do not need to throw Remote exceptions, since they will run locally in the client. The implementation of this Jini interface will basically act as a CORBA client. Its getHello() method will contact the CORBA naming service, find a reference to the CORBA Hello object, and call its getHello() method. The Jini service can just return the string it gets from the CORBA service. /** * JiniHelloImpl.java */ package corba; import org.omg.CosNaming.*; import org.omg.CORBA.*; import corba.HelloModule.*; public class JiniHelloImpl implements JiniHello { protected Hello hello = null; protected String[] argv; public JiniHelloImpl(String[] argv) { this.argv = argv; } public String getHello() { if (hello == null) { hello = getHello(); } // now invoke methods on the CORBA proxy String hello = hello.getHello(); return hello; } protected Hello getHello() { ORB orb = null; // Act like a CORBA client try { orb = ORB.init(argv, null); // get the CORBA name server org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext namingContext = NamingContextHelper.narrow(objRef); // get the CORBA Hello proxy NameComponent nameComponent = new NameComponent("Hello", ""); NameComponent path[] = {nameComponent}; org.omg.CORBA.Object obj = namingContext.resolve(path); Hello hello = HelloHelper.narrow(obj); return hello; } catch(Exception e) { e.printStackTrace(); return null; } } } // JiniHelloImpl Jini Server and ClientThe Jini server that exports the service doesn't contain anything new compared to the other service providers we have discussed. It creates a new JiniHelloImpl object and exports it using a JoinManager : joinMgr = new JoinManager(new JiniHelloImpl(argv), ...) Similarly, the Jini client doesn't contain anything new, except that it catches CORBA exceptions. After lookup discovery, the code is as follows : try { hello = (JiniHello) registrar.lookup(template); } catch(java.rmi.RemoteException e) { e.printStackTrace(); System.exit(2); } if (hello == null) { System.out.println("hello null"); return; } String msg; try { msg = hello.getHello(); System.out.println(msg); } catch(Exception e) { // a CORBA runtime error may occur System.err.println(e.toString()); } Building the Simple CORBA ExampleCompared to the Jini-only examples that have been looked at so far, the major additional step in this CORBA example is to build the Java classes from the IDL specification. There are a number of CORBA IDL-to-Java compilers. One of these is the Sun compiler idltojava , which is available from java.sun.com . This (or another compiler) needs to be run on the IDL file to produce the Java files in the corba.HelloModule package. The files that are produced are standard Java files, and they can be compiled using your normal Java compiler. They may need some CORBA files in the CLASSPATH if required by your vendor's implementation of CORBA. Files produced by idltojava do not need any extra classes. The Jini server, service, and client are also normal Java files, and they can be compiled like earlier Jini files, with the CLASSPATH set to include the Jini libraries. Running the Simple CORBA ExampleThere are a large number of elements and processes that must be set running to get this example working satisfactorily:
CORBA ImplementationsThere are interesting considerations about what is needed in Java to support CORBA. The example discussed previously uses the CORBA APIs that are part of the standard OMG binding of CORBA to Java. The packages rooted in org.omg are in major distributions of JDK 1.2, such as the Sun SDK. This example should compile properly with most Java 1.2 compilers using these OMG classes. Sun's JDK 1.2 runtime includes a CORBA ORB, and the example will run as is, using this ORB. However, there are many implementations of CORBA ORBs, and they do not always behave in quite the same way. This can affect compilation and runtime results. Which CORBA ORB is used is determined at runtime, based on properties. If a particular ORB is not specified, then it defaults to the Sun-supplied ORB (using Sun's SDK). To use another ORB, such as the Orbacus ORB, the following code needs to be inserted before the call to ORB.init() : java.util.Properties props = System.getProperties(); props.put("org.omg.CORBA.ORBClass", "com.ooc.CORBA.ORB"); props.put("org.omg.CORBA.ORBSingletonClass", "com.ooc.CORBA.ORBSingleton"); System.setProperties(props); Similar code is required for the ORBS from IONA and other vendors . Variations in CORBA implementations could affect the runtime behavior of the client: if the proxy expects to use a particular ORB other than the default, then the class files for that ORB must be available to the client or be downloadable across the network. Alternatively, the proxy could be written to use the default Sun ORB, and then may need to make inter-ORB calls between the Sun ORB and the actual ORB used by the CORBA service. Such issues take us beyond the scope of this chapter, though. Vendor documentation for each CORBA implementation should give more information on any additional requirements. |