Taming CORBA Dynamic Invocation with JavaBeans

 

IN LINE WITH Java's move into enterprise systems, release 1.2 of the Java Development Kit (JDK 1.2) marks the first release of the Java core Application Programming Interface (API) to include support for the Common Object Request Broker Architecture (CORBA). This article explores how to use the CORBA Dynamic Invocation Interface (DII) delivered with JDK 1.2 to build CORBA-enabled Java clients. Furthermore, it demonstrates how to encapsulate the complexity associated with the JDK 1.2 implementation of CORBA DII using JavaBeans to produce a reusable component for rapid application development (RAD) of distributed enterprise systems.

The CORBA Dynamic Invocation Interface
CORBA is a standard infrastructure for distributed object systems. It allows objects to interact with each other at a high level, and hides complexities inherent in distributed systems; where objects may be implemented in different coding languages and can run on different operating systems, hardware, or network nodes. Static invocation is the standard approach for CORBA clients to interact with CORBA servers. However, it requires the CORBA client to use, and therefore, be in the possession of, code stubs associated with the server. This requirement is undesirable in certain situations where acquiring or distributing these stubs may be impractical, for example, in the following situations:
  • The server stubs are not freely published.
  • Clients may need to talk to a large variety of servers with different interfaces.
  • Server interfaces may change frequently.
  • To rapidly compose and execute a request on a CORBA server, for example, in a testing scenario.

Dynamic invocation addresses this problem by allowing CORBA clients to form and execute requests on CORBA servers on the fly, without having to first acquire any code stubs. However, the power that CORBA and DII bring to the table comes at a price, namely, increased complexity. This results in slower adoption, increased training and implementation costs, and longer implementation times. To accelerate the adoption of CORBA DII and ultimately the realization of its benefits, while minimizing the associated costs and negative impacts on schedules, it is desirable to encapsulate the implementation complexity of CORBA DII. This encapsulation has the added advantage of decoupling the system from the particular CORBA implementation that is used. This allows a developer to change from the JDK 1.2 CORBA implementation to a different CORBA implementation at minimal cost, because any differences between the implementations would be hidden by encapsulation.

CORBA-Enabled JavaBeans
JavaBeans is the Java software component architecture first released in JDK 1.1. It defines a set of standards for Java component interfaces that cover methods, properties, and events. JavaBeans also provides a framework to facilitate rapid development and deployment of these components. JavaBeans advocates a building block approach to software in which each component, or bean, may be visually configured during development and then archived. The bean may then be instantiated in the same configured state later at runtime. The advantage of this approach is that the configuration of the bean is not hardcoded into the code of the system being deployed. Rather, the configuration of the bean is stored in the archive. This means that if one wanted to make a change to the bean properties at some later stage, the bean would simply need to be visually reconfigured and a new archive created, as opposed to making a software change to the system code and then recompiling it. This advantage of the JavaBean paradigm is particularly valuable for components that are most likely to change in a system, such as graphical user interface (GUI) components, or components that are used to decouple systems. A component encapsulating a CORBA DII request may be viewed as such a decoupling component and is therefore particularly well-suited to implementation as a JavaBean.

Much of the JavaBeans power stems from the fact that these components may be configured visually at a high level where the user is aware of what the component does, but not necessarily how the component does it. This effectively encapsulates, or hides, the implementation complexity of the component, resulting in lower training and development costs, shorter implementation times, and increased reuse. Furthermore, an added benefit of this encapsulation and visual configuration is that non-programmers are now able to participate more in the development and maintenance of software systems.

The Life Of The CORBA DII JavaBean
To illustrate the principles of CORBA DII and demonstrate how this functionality is effectively encapsulated as a JavaBean, this document first walks through the lifecycle of the bean developed to encapsulate the JDK 1.2 implementation of CORBA DII—from configuration during development to execution at runtime. This is followed by highlighting some of the key low-level implementation details of the JDK 1.2 implementation of CORBA DII.

The CORBA DII JavaBean is implemented in the DynamicRequest class. This bean is supported by two other classes, namely, Parameter and Flag as shown in Figure 1.

From the Pages

The Parameter class implements the Abstract Factory pattern to hide the CORBA DII complexity associated with method return and argument parameters. Similarly, the Flag class implements the Abstract Factory pattern to hide the CORBA DII complexity associated with method argument direction flags. These direction flags are used by CORBA to indicate the direction in which information is being passed by method arguments during method invocation, and are summarized in Table 1.

The classes that derive from the Parameter and Flag classes (examples are shown in Figure 1) are not public and are therefore invisible to the user.

From the Pages

The DynamicRequest class is also supported by the DynamicRequestEvent class and the DynamicRequestListener interface shown in Figure 2. The DynamicRequestEvent class defines the objects that encapsulate information about new events originating from the DynamicRequest bean. Components that wish to listen to events from the DynamicRequest bean must implement the DynamicRequestListener interface. Note that to configure the DynamicRequest bean visually, some additional JavaBean-related classes will be required that define, for example, the configuration GUI. These classes involve standard JavaBean and GUI development and are therefore outside the scope of this article.

Configuring and Archiving the DynamicRequest Bean at Development Time
The life of the CORBA DII JavaBean starts with configuring and archiving the bean at development time. CORBA Interface Definition Language (IDL) specifies the services a CORBA object provides. To configure our DynamicRequest bean, it is first required to know the IDL for the CORBA object on which you want to invoke a method. For example, a CORBA object may have the IDL interface shown in Listing 1.

The DynamicRequest bean may be configured to invoke the CORBA request in Listing 1 by setting its properties. These properties are listed with descriptions and appropriate values in Table 2.

For illustration purposes, the DynamicRequest bean may be configured at the software level (as opposed to visually) to invoke the "placeItemOrder" method as shown in the Listing 1. After the bean is configured, it may be archived to a file using the standard java.io.ObjectOutputStream.writeObject (Object) method.

Executing The DynamicRequest Bean At Runtime
Later, the archived object may be instan-tiated from the archive file using the java.beans.Beans.instantiate(ClassLoader,String) method. After instantiation the bean can be "wired" to other beans that want to listen to its events using the DynamicRequest.addDynamic- RequestListener(DynamicRequestListener) method. Finally, the dynamic request it encapsulates may be invoked using the DynamicRequest.invoke() method. When the invocation completes, a JavaBean event DynamicRequestEvent is sent to all other beans that are registered listeners to events from the instantiated Dynamic- Request bean. These listeners should first check the status of the invocation using the DynamicRequest.getStatus() method. If successful, this method will return true. Otherwise it will return false, and a textual message explaining the failure can be retrieved from the DynamicRequest.getStatusMessage() method. After a successful invocation, values of the return parameters and argument parameters that have "inout" or "out" direction flags can be retrieved through the appropriate "get" methods on the DynamicRequest and Parameter classes.

The JDK 1.2 Implementation Of CORBA DII
When the DynamicRequest is invoked, the CORBA DII request is built up and executed. The results of the request are then extracted before other beans are notified that the request is complete. This section highlights key steps in this process to illustrate the JDK 1.2 implementation of CORBA DII.

The first step in building the request is to initialize the Object Request Broker (ORB) in the DynamicRequest.buildRequest() method.


Properties orbProperties = new Properties();
orbProperties.put( "org.omg.CORBA.ORBInitialHost",
		getNameServerHost() );
orbProperties.put("org.omg.CORBA.ORBInitialPort",
		Integer.toString(getNameServerPort() ) );
ORB orb = ORB.init( new String[ 0 ] /* args */,
orbProperties );

The InitialHost and InitialPort properties with which the ORB is initialized tell it where the CORBA NameService is. This NameService is later used to find the CORBA server object on which we want to make a request. The String array argument used to initialize the ORB is used to convey application-specific arguments to the ORB. In this case, none exist.

The next step is to get an object reference for the NameService as follows. Note that the NameService has the standard name "NameService" by convention.


org.omg.CORBA.Object namingServiceObjRef = orb.resolve_initial_references( "NameService" );
NamingContext nameContextRef = NamingContextHelper.narrow( namingServiceObjRef );

Using the object reference for the NameService, we can then get an object reference for the server on which we want to make a request.

NameComponent path[] = { new NameComponent( getServerObjectName(), "" ) };
org.omg.CORBA.Object serverObjRef = 
nameContextRef.resolve( path );

Using the object reference we obtained for the CORBA server, a DII request object is created for the method we want to invoke.


request = serverObjRef._request( getMethodName() );

This request object is then configured to reflect the signature of the method we want to invoke. The first step to achieve this is to set the return parameter type.


request.set_return_type(getReturnParameter().
getCORBATypeCode( orb ) );

Note that this call uses polymorphism through the abstract Parameter class to get the CORBA type code for the particular type of the return parameter. For example, for a return parameter with a boolean type, the getCORBATypeCode() call is implemented in the BooleanParameter.get CORBATypeCode() method as:


return orb.get_primitive_tc (org.omg.CORBA.TCKind.tk_boolean );

Finally, the method arguments of the request may be configured.

int numberOfArgs = getNumberOfArguments();
for( int i = 0; i < numberofargs;="" ++i="" )="" {="" parameter="" argument="getArgumentParameter(" i="" );="" org.omg.corba.any="" argumentvalue="argument.addToRequestArguments(" request="" );="" argument.initcorbaany(="" argumentvalue="" );}="">

The Parameter.addToRequestArguments() makes use of polymorphism through the abstract Flag class to add a new argument to the request according to its direction flag. For example, for an "in" argument, the addToRequestArguments() call on the Parameter class calls the InFlag.add RequestArgument() method, which is implemented as:


	return request.add_named_in_arg
(argumentName);

Once the argument is added to the request, its value is set using the Parameter.initCORBAAny() method, which makes use of polymorphism through the abstract Parameter class to set the value according to the type of the parameter. For example, for a string parameter, this method is implemented in the StringParameter.init- CORBAAny() method as:

void initCORBAAny( org.omg.CORBA.Any any )
	{any.insert_string( (String) getValue() );
}

At this point, the dynamic request is completely configured and may be invoked. After invocation is complete, the results of the request are extracted for the return parameter and arguments with "inout" and "out" flags as shown in DynamicRequest.extractRequestResults().


	int numberOfArguments = getNumberOfArguments();
for( int i = 0; i < numberofarguments;="" ++i="" )="" {="" if(="" getargumentparameter(="" i="" ).hasreturnvalue()="" )="" {="" try="" {="" getargumentparameter(="" i="" ).setcorbavalue(="" request.arguments().item(="" i="" ).value()="" );="" }="" catch(="" org.omg.corba.bounds="" e="" )="" {="" e.printstacktrace();="" }="" }="" }="">

The Parameter.hasReturnValue() and Parameter.setCORBAValue() use polymorphism through the abstract Parameter class to determine if a given parameter has a return value and, if so, to set that value respectively. This allows other components to retrieve these values as properties on the DynamicRequest class. For example, the "totalPrice" argument in the server method we are invoking has a direction of "out" and is of type Double. The OutFlag.hasReturnValue() is therefore called and is implemented simply as:


boolean hasReturnValue() { return true; }
For a Parameter of type Double the DoubleParameter.setCORBAValue() is called and is implemented as:
void setCORBAValue( org.omg.CORBA.Any value ) {
	setValue( new Double( value.extract_double() ) );
}

Finally, after the request results are extracted, components listening to the DynamicRequest bean are notified that a new request has been completed via the DynamicRequest.fireDynamic-RequestEvent() method. These components can then get and process the results of the request as properties on the DynamicRequest bean without concerning themselves with any of the details of the JDK 1.2 CORBA DII implementation.

Future Work
The scope and implementation of the DynamicRequest bean and supporting classes was intentionally limited to clarify the points discussed in this article. A more complete implementation of these classes could be developed as a straightforward extension of the existing classes to support other base and user defined CORBA types, including structs, sequences, and arrays. In the accompanying implementation, only the string, double, long, and boolean base types are supported. Furthermore, these classes need to be enhanced with support for testing and diagnostics before they are suitable for implementation in mission-critical systems.

Defining the JavaBean support to facilitate visual configuration of the DynamicRequest bean would further enhance reuse of the bean and would facilitate RAD. Development of this support is a straightforward JavaBean development exercise. More complex visual configuration support could even go so far as to grab the server IDL from the CORBA interface repository and allow users to select the IDL method they want to invoke using a GUI drop-down list on the visual configuration GUI. This would further facilitate RAD by automatically configuring the return type and arguments of the server method selected.

A similar bean could also be written to encapsulate the complexity of the JDK 1.2 implementation of the CORBA Dynamic Skeleton Interface (DSI). This bean would provide the same benefits to CORBA Java servers that the DynamicRequest bean brings to the CORBA Java client.

Conclusion
The JDK 1.2 implementation of CORBA DII brings powerful new functionality to Java software developers building distributed enterprise systems. However, this new functionality comes at a price, namely increased complexity. In practice, increased complexity results in slower adoption of new technology and leads to increased training and implementation costs, and slows implementation schedules. To realize the maximum benefit of this new functionality while minimizing costs, it is desirable to encapsulate this complexity. Encapsulation allows the valuable functionality brought to the table by CORBA DII to be delivered at a higher level of abstraction and in more intuitive ways. JavaBeans are a very effective way of realizing this encapsulation and have the additional advantage of being suitable for visual configuration, in turn encouraging reuse and RAD, and enabling non-programmers to participate more in building and maintaining systems.

To view an interactive CORBA Beans demo go to the Corba Beans Website. David Houlding is a Senior Designer/Developer at The Technical Resource Connection in Tampa, FL.
He can be contacted at [email protected].