Defining the Interface Generating Stubs and Skeletons

Object Adapter POA. The POA lies between the wire and the skeleton and plays a role analogous to the RMI runtime. That is, it pulls requests off the wire, demarshalls the data, and forwards the requests to the skeletons. The POA is, however, vastly more flexible than the RMI runtime and allows programmers much more control over things like thread creation. Another important aspect of the CORBA specification is the definition of standard services. The CORBA specification contains IDL interfaces, and fairly thorough discussions, of many of the common architectural components of a distributed application. For example, the CORBA specification contains a complete definition in IDL of a naming service, an event service, and a transactions-management service. For more information on CORBA, see Java Programming with CORBA by Andrew Vogel and Keith Duddy John Wiley Sons and Advanced CORBA Programming with C++ by Michi Henning and Steve Vinosky Addison-Wesley.

23.2 The Bank Example in CORBA

In order to make this more concrete, we will briefly walk through how to build the bank example using CORBA. However, since this is an RMI book, we will not dwell on the details™if youre interested, the complete code for this chapter is contained in the com.ora.rmibook.chapter23.corbaaccounts package.

23.2.1 Defining the Interface

The first step is to define the interface using IDL: pragma prefix com.ora.rmibook.chapter23.corbaaccounts struct Money { long cents; }; exception NegativeAmountException{}; exception OverdraftException{}; interface Account{ Money getBalance ; void makeDepositin Money amount raises NegativeAmountException; void makeWithdrawalin Money amount raises NegativeAmountException, OverdraftException; }; There are several things to note here. Perhaps the most important is that this is actually quite readable. We declare a struct, we declare some exceptions, and we define an interface. The IDL for our account servers looks quite a bit like the Java definitions weve used up until now. This shouldnt be a surprise. Chapt er 5 through Chapt er 7 , which contained a fair number of design guidelines, werent at all RMI-specific. When you add in the fact that both IDL and Java syntax are descended from C, it would be surprising if RMI programmers couldnt easily understand IDL interfaces.

23.2.2 Generating Stubs and Skeletons

The IDL contains all the information that defines how clients talk to servers. This means that, once we have the IDL, we can generate stubs and skeletons. In Java 2, this is accomplished through the use of the idlj program. For example, the command: idlj -fall Account.idl will compile our IDL file into a set of Java classes, including stubs, skeletons, and value objects. These classes can then be used to build our application. There is an important difference between CORBA and RMI here. RMI, via rmic , requires the server classes to generate stubs and skeletons, not just the interfaces. CORBA requires only the IDL. Since the client and server can be written in different programming languages, its hard to see how the details of the server implementation could be used by the IDL compiler. The IDL compiler generates a lot of classes. Even the simple IDL file we used for our account server generates the following classes: Account.java AccountHelper.java AccountHolder.java AccountOperations.java Account_Impl.java Money.java MoneyHelper.java MoneyHolder.java NegativeAmountException.java NegativeAmountExceptionHelper.java NegativeAmountExceptionHolder.java OverdraftException.java OverdraftExceptionHelper.java OverdraftExceptionHolder.java _AccountImplBase.java _AccountStub.java Among these classes are a stun, a skeleton, a value object Money , and a lot of classes whose role is to help the CORBA runtime translate between Java datatypes and IDL datatypes. Accounts in C++ What happens when we compile Account.idl into other languages? Pretty much the same thing. Whereas the Java stub contains method definitions such as: public void makeWithdrawal Money amount throws NegativeAmountException, OverdraftException { org.omg.CORBA.portable.InputStream _in = null; try { org.omg.CORBA.portable.OutputStream _out = _request makeWithdrawal, true; MoneyHelper.write _out, amount; _in = _invoke _out; } catch org.omg.CORBA.portable.ApplicationException _ex { _in = _ex.getInputStream ; String _id = _ex.getId ; if _id.equals IDL:com.ora.rmibook.chapter23.corbaaccounts + NegativeAmountException:1.0 throw NegativeAmountExceptionHelper.read _in; else if _id.equals IDL:com.ora.rmibook.chapter23.corbaaccounts + OverdraftException:1.0 throw OverdraftExceptionHelper.read _in; else throw new org.omg.CORBA.MARSHAL _id; } catch org.omg.CORBA.portable.RemarshalException _rm { makeWithdrawal amount; } finally { _releaseReply _in; } } makeWithdrawal the C++ version of the stub contains: void Account::makeWithdrawal const Money _amount { CORBA_MarshalInBuffer_var _ibuf; CORBA::MarshalOutBuffer_var _obuf; while 1 { _obuf = __ _root- _create_requestmakeWithdrawal, 1, 627418; VISostream _ostrm = VISostream CORBA::MarshalOutBuffer_obuf; _ostrm _amount; try { _ibuf = __ _root-_invoke_obuf; } catch const CORBA::TRANSIENT { continue; } break; } } Its not really all that different.

23.2.3 The Server