Creating CORBA Client Applications

     Previous  Next    Open TOC in new window  Open Index in new window  View as PDF - New Window  Get Adobe Reader - New Window
Content starts here

Using the Dynamic Invocation Interface

This topic includes the following sections:

The information in this topic applies to CORBA C++client applications.

For an overview of the invocation types and DII, see Static and Dynamic Invocation.

For a complete description of the CORBA member functions mentioned in this topic, see the CORBA Programming Reference.

Notes: The BEA Tuxedo CORBA Java client and BEA Tuxedo CORBA Java client ORB were deprecated in Tuxedo 8.1 and are no longer supported. All BEA Tuxedo CORBA Java client and BEA Tuxedo CORBA Java client ORB text references, associated code samples, should only be used to help implement/run third party Java ORB libraries, and for programmer reference only.
Note: Technical support for third party CORBA Java ORBs should be provided by their respective vendors. BEA Tuxedo does not provide any technical support or documentation for third party CORBA Java ORBs.

 


When to Use DII

There are good reasons to use either static or dynamic invocation to send requests from the CORBA client application. You may find you want to use both invocation types in the same CORBA client application. To choose an invocation type, you need to understand the advantages and disadvantages of DII.

One of the major differences between static invocation and dynamic invocation is that, while both support synchronous and one-way communication, only dynamic invocation supports deferred synchronous communication.

In synchronous communication, the CORBA client application sends a request and waits until a response is retrieved; the CORBA client application cannot do any other work while it is waiting for the response. In deferred synchronous communication, the CORBA client application sends the request and is free to do other work. Periodically, the CORBA client application checks to see if the request has completed; when the request has completed, the CORBA client application makes use of the result of that request.

In addition, DII enables a CORBA client application to invoke a method on a CORBA object whose type was unknown at the time the CORBA client application was written. This contrasts with static invocation, which requires that the CORBA client application include a client stub for each type of CORBA object the CORBA client application intends to invoke. However, DII is more difficult to program (your code has to do the work of a client stub).

A CORBA client application can use DII to obtain better performance. For example, the CORBA client application can send multiple deferred synchronous requests at the same time and can handle the completions as they occur. If the requests go to different server applications, this work can be done in parallel. You cannot do this when you are using synchronous client stubs.

Note: The client stubs have optimizations, that allow the client stubs to achieve quicker response time than is achieved with DII when sending a single request and immediately blocking to get the response for that request.

DII is purely an interface to the CORBA client application; static and dynamic invocations are identical from a CORBA server application's point of view.

 


DII Concepts

DII frequently offers more than one way to accomplish a task, the trade-off being programming simplicity versus performance. This section describes the high-level concepts you need to understand to use DII. Details, including code examples, are provided later in this topic.

The concepts presented in this section are as follows:

Request Objects

A request object represents one invocation on one method of a CORBA object. If you want to make two invocations on the same method, you need to create two request objects.

To invoke a method, you need an object reference to the CORBA object that contains the method. You use the object reference to create a request object, populate the request object with arguments, send the request, wait for the reply, and obtain the result from the request.

You can create a request object in the following ways:

For a complete description of the CORBA member functions, see the CORBA Programming Reference.

Options for Sending Requests

Once you have created and populated a request object with arguments, a result type, and exception types, you send the request to the CORBA object. There are several ways to send a request:

Note: When using the CORBA::Request::send_deferred member function, the invocation on the request object acts synchronously when the target object is in the same address space as the CORBA client application issuing the invocation. As a result of this behavior, calling the CosTransaction::Current::suspend operation does not raise the CORBA::BAD_IN_ORDER exception, because the transaction has completed.

For a complete description of the CORBA member functions, see the CORBA Programming Reference.

Options for Receiving the Results of Requests

If you send a request using the invoke method, there is only one way to get the result: use the request object's CORBA::Request::env member function to test for an exception; and if there is not exception, extract the NVList from the request object using the CORBA::Request::result member function.

If you send a request using the deferred synchronous method, you can use any of the following member functions to get the result:

If you used the CORBA::Request::send_oneway member function, there is no result.

For a complete description of the CORBA member functions, see the CORBA Programming Reference.

 


Summary of the Development Process for DII

The steps for using DII in client applications are as follows:

Step
Description
1
Load the CORBA interfaces into the Interface Repository.
2
Obtain an object reference for the CORBA object on which you want to invoke methods.
3
Create a request object for the CORBA object.
4
Send the DII request and retrieve the results.
5
Delete the request.
6
Use the Interface Repository with DII.

The following sections describe these steps in detail and provide C++ code examples.

 


Step 1: Loading the CORBA Interfaces into the Interface Repository

Before you can create CORBA client applications that use DII, the interfaces of the CORBA object need to be loaded into the Interface Repository. If the interfaces of a CORBA object are not loaded in the Interface Repository, they do not appear in the BEA Application Builder. If a desired CORBA interface does not appear in the Services window, use the idl2ir command to load the OMG IDL that defines the CORBA object into the Interface Repository. The syntax for the idl2ir command is as follows:

idl2ir [-f repositoryfile.idl] file.idl

Option
Description
-f repositoryfile
Directs the command to load the OMG IDL files for the CORBA interface into the specified Interface Repository. Specify the name of the Interface Repository in the BEA Tuxedo domain that the CORBA client application will access.
file.idl
Specifies the OMG IDL file containing definitions for the CORBA interface.

For a complete description of the idl2ir command, see the BEA Tuxedo Command Reference.

 


Step 2: Obtaining the Object Reference for the CORBA Object

Use the Bootstrap object to get a FactoryFinder object. Then use the FactoryFinder object to get a factory for the CORBA object you want to access from the DII request. For an example of using the Boostrap and FactoryFinder objects to get a factory, see Step 4: Writing the CORBA Client Application.

 


Step 3: Creating a Request Object

When your CORBA client application invokes a method on a CORBA object, you create a request for the method invocation. The request is written to a buffer and sent to the CORBA server application. When your CORBA client application uses client stubs, this processing occurs transparently. Client applications that want to use DII must create a request object and must send the request.

Using the CORBA::Object::_request Member Function

The following C++ code example illustrates how to use the CORBA::Object::_request member function:

Boolean          aResult;
CORBA::ULong long1 = 42;
CORBA::Any in_arg1;
CORBA::Any &in_arg1_ref = in_arg1;

in_arg1 <<= long1;
// Create the request using the short form
Request_ptr reqp = anObj->_request("anOp");
// Use the argument manipulation helper functions
reqp->add_in_arg() <<= in_arg1_ref;
// We want a boolean result
reqp->set_return_type(_tc_boolean);
// Provide some place for the result
CORBA::Any::from_boolean boolean_return_in(aResult);
reqp->return_value() <<= boolean_return_in;
// Do the invoke
reqp->invoke();
// No error, so get the return value
CORBA::Any::to_boolean boolean_return_out(aResult);
reqp->return_value() >>= boolean_return_out;

Using the CORBA::Object::create_request Member Function

When you use the CORBA::Object::create_request member function to create a request object, you create an empty NVList and you add arguments to the NVList one at a time. You create the request object, passing the completed NVList as an argument to the request.

Setting Arguments for the Request Object

The arguments for a request object are represented with an NVList object that stores named/value objects. Methods are provided for adding, removing, and querying the objects in the list. For a complete description of CORBA::NVList, see the CORBA Programming Reference.

Setting Input and Output Arguments with the CORBA::NamedValue Member Function

The CORBA::NamedValue member function specifies a named/value object that can be used to represent both input and output arguments for a request. The named/value objects are used as arguments to the request object. The CORBA::NamedValue pair is also used to represent the result of a request that is returned to the CORBA client application. The name property of a named/value object is a character string, and the value property of a named/value object is represented by a CORBA Any.

For a complete description of the CORBA::NamedValue member function, see the CORBA Programming Reference.

Example of Using CORBA::Object::create_request Member Function

The following C++ code example illustrates how to use the CORBA::Object::create_request member function:

CORBA::Request_ptr         reqp;
CORBA::Context_ptr ctx;
CORBA::NamedValue_ptr boolean_resultp = 0;
Boolean boolean_result;
CORBA::Any boolean_result_any(CORBA::_tc_boolean, & boolean_result);
CORBA::NVList_ptr arg_list = 0;
CORBA::Any arg;
// Get the default context
orbp->get_default_context(ctx);
// Create the named value pair for the result
(void) orbp->create_named_value(boolean_resultp);
CORBA::Any *tmpany = boolean_resultp->value();
*tmpany = boolean_result_any;

arg.replace(CORBA::_tc_long, &long_arg, CORBA_FALSE)
// Create the NVList
orbp->create_list(1, arg_list);

// Add an IN argument to the list
arg_list->add_value("arg1", arg, CORBA::ARG_IN);

// Create the request using the long form
anObj->_create_request (ctx,
"anOp",
arg_list,
boolean_resultp,
reqp,
CORBA::VALIDATE_REQUEST );
// Do the invoke
reqp->invoke();

CORBA::NamedValue_ptr result_namedvalue;
Boolean aResult;
CORBA::Any *result_any;
// Get the result
result_namedvalue = reqp->result();
result_any = result_namedvalue->value();
// Extract the Boolean from the any
*result_any >>= aResult;

 


Step 4: Sending a DII Request and Retrieving the Results

You can invoke a request in several ways, depending on what kind of communication type you want to use. This section describes how the CORBA member functions are used to send requests and retrieve the results.

Synchronous Requests

If you want synchronous communication, the CORBA::Request::invoke member function sends the request and waits for a response before it returns to the CORBA client application. Use the CORBA::Request::result member function to return a reference to a named/value object that represents the return value. Once the results are retrieved, you read the values from the NVList stored in the request.

Deferred Synchronous Requests

The nonblocking member function, CORBA::Request::send_deferred, is also provided for sending requests. It allows the CORBA client application to send a request and then use the CORBA::Request::poll_response member function to determine when the response is available. The CORBA::Request::get_response member function blocks until a response is available.

The following code example illustrates how to use the CORBA::Request::send_deferred, CORBA::Request::poll_response, and CORBA::Request::get_response member functions:

request->send_deferred ();

if (poll)
{
for ( int k = 0 ; k < 10 ; k++ )
{
CORBA::Boolean done = request->poll_response();
if ( done )
break;
     }
}
request->get_response();

Oneway Requests

Use the CORBA::Request::send_oneway member function to send a oneway request. Oneway requests do not involve a response from the CORBA server application. For a complete description of the CORBA::Request::send_oneway member function, see the CORBA Programming Reference.

The following code example illustrates how to use the CORBA::Request::send_oneway member function:

request->send_oneway();

Multiple Requests

When a sequence of request objects is sent using the CORBA::Request::send_multiple_requests_deferred member function, the CORBA::ORB::poll_response, CORBA::ORB::poll_next_response, CORBA::ORB::get_response, and CORBA::ORB::get_next_response member functions can be used to retrieve the response the CORBA server application sends for each request.

The CORBA::ORB::poll_response and CORBA::ORB::poll_next_response member functions can be used to determine if a response has been retrieved from the CORBA server application. These member functions return a 1 if there is at least one response available, and a zero if there are no responses available.

The CORBA::ORB::get_response and CORBA::ORB::get_next_response member functions can be used to retrieve a response. If no response is available, these member functions block until a response is retrieved. If you do not want your CORBA client application to block, use the CORBA::ORB::poll_next_response member function to first determine when a response is available, and then use the CORBA::ORB::get_next_response method to retrieve the result.

You can also send multiple oneway requests by using the CORBA::Request::send_multiple_requests_oneway member function.

The following code example illustrates how to use the CORBA::Request::send_multiple_requests_deferred, CORBA::Request::poll_next_response, and CORBA::Request::get_next_response member functions:

CORBA::Context_ptr           ctx;
CORBA::Request_ptr requests[2];
CORBA::Request_ptr request;
CORBA::NVList_ptr arg_list1, arg_list2;
CORBA::ULong i, nreq;
CORBA::Long arg1 = 1;
Boolean aResult1 = CORBA_FALSE;
Boolean expected_aResult1 = CORBA_TRUE;
CORBA::Long arg2 = 3;
Boolean aResult2 = CORBA_FALSE;
Boolean expected_aResult2 = CORBA_TRUE

try
{
orbp->get_default_context(ctx);

populate_arg_list ( &arg_list1, &arg1, &aResult1 );

nreq = 0;

anObj->_create_request ( ctx,
"Multiply",
arg_list1,
0,
requests[nreq++],
0);

populate_arg_list ( &arg_list2, &arg2, &aResult2 );

anObj->_create_request ( ctx,
"Multiply",
arg_list2,
0,
requests[nreq++],
0 );

// Declare a request sequence variable...
CORBA::ORB::RequestSeq rseq ( nreq, nreq, requests, CORBA_FALSE );

orbp->send_multiple_requests_deferred ( rseq );
for ( i = 0 ; i < nreq ; i++ )
{
requests[i]->get_response();
}
// Now check the results
if ( aResult1 != expected_aResult1 )
{
cout << "aResult1=" << aResult1 << " different than expected: " <<
expected_aResult1;
}
if ( aResult2 != expected_aResult2 )
{
cout << "aResult2=" << aResult2 << " different than expected: " <<
expected_aResult2;
}
aResult1 = CORBA_FALSE;
aResult2 = CORBA_FALSE;
// Using the same argument lists, multiply the numbers again.
// This time we intend to poll for response...

orbp->send_multiple_requests_deferred ( rseq );

// Now poll for response...
for ( i = 0 ; i < nreq ; i++ )
{
// We will randomly poll maximum 10 times...
for ( int j = 0 ; j < 10 ; j++ )
{
CORBA::Boolean done = requests[i]->poll_response();

if ( done ) break;
}
}
// Now actually get the response...
for ( i = 0 ; i < nreq ; i++ )
{
requests[i]->get_response();
}
// Now check the results
if ( aResult1 != expected_aResult1 )
{
cout << "aResult1=" << aResult1 << " different than expected: " <<
expected_aResult1
}
if ( aResult2 != expected_aResult2 )
{
cout << "aResult2=" << aResult2 << " different than expected: " <<
expected_aResult2;
}
aResult1 = CORBA_FALSE;
aResult2 = CORBA_FALSE;
// Using the same argument lists, multiply the numbers again.
// Call get_next_response, and WAIT for a response.
orbp->send_multiple_requests_deferred ( rseq );

// Poll until we get a response and then use get_next_response get it...
for ( i = 0 ; i < nreq ; i++ )
{
CORBA::Boolean res = 0;

while ( ! res )
{
res = orbp->poll_next_response();
}
orbp->get_next_response(request);
CORBA::release(request);
}
// Now check the results
if ( aResult1 != expected_aResult1 )
{
cout << "aResult1=" << aResult1 << " different than expected: " <<
expected_aResult1;
}
if ( aResult2 != expected_aResult2 )
{
cout << "aResult2=" << aResult2 << " different than expected: " <<
expected_aResult2;
}
static void populate_arg_list (
CORBA::NVList_ptr ArgList,
CORBA::Long * Arg1,
CORBA::Long * Result )
{
CORBA::Any any_arg1;
CORBA::Any any_result;

(* ArgList) = 0;
orbp->create_list(3, *ArgList);

any_arg1 <<= *Arg1;
any_result.replace(CORBA::_tc_boolean, Result, CORBA_FALSE);
(*ArgList)->add_value("arg1", any_arg1, CORBA::ARG_IN);
(*ArgList)->add_value("result", any_result, CORBA::ARG_OUT);

return;
}

 


Step 5: Deleting the Request

Once you have been notified that the request has successfully completed, you need to decide if you want to delete the existing request, or reuse portions of the request in the next invocation.

To delete the entire request, use the CORBA::Release(request) member function on the request to be deleted. This operation releases all memory associated with the request. Deleting a request that was issued using the deferred synchronous communication type causes that request to be canceled if it has not completed.

 


Step 6: Using the Interface Repository with DII

A CORBA client application can create, populate, and send requests for objects that were not known to the CORBA client application when it was built. To do this, the CORBA client application uses the Interface Repository to retrieve information needed to create and populate the requests. The CORBA client application uses DII to send the requests, since it does not have client stubs for the interfaces.

Although this technique is useful for invoking operations on a CORBA object whose type is unknown, performance becomes an issue because of the overhead interaction with the Interface Repository. You might consider using this type of DII request when creating a CORBA client application that browses for objects, or when creating a CORBA client application that is an administration tool.

The steps for using the Interface Repository in a DII request are as follows:

  1. Set ORB_INCLUDE_REPOSITORY in CORBA.h to the location of the Interface Repository file in your BEA Tuxedo system.
  2. Use the Bootstrap object to obtain the InterfaceRepository object, which contains a reference to the Interface Repository in a particular BEA Tuxedo domain. Once the reference to the Interface Repository is obtained, you can navigate the Interface Repository from the root.
  3. Use the CORBA::Object::_get_interface member function to communicate with the CORBA server application that implements the desired CORBA object.
  4. Use CORBA::InterfaceDef_ptr to get the definition of the CORBA interface that is stored in the Interface Repository.
  5. Locate the OperationDescription for the desired operation in the FullInterfaceDescription operations.
  6. Retrieve the repository ID from the OperationDescription.
  7. Call CORBA::Repository::lookup_id using the repository ID returned in the OperationDescription to look up the OperationDef in the Interface Repository. This call returns the contained object.
  8. Narrow the contained object to an OperationDef.
  9. Use the CORBA::ORB::create_operation_list member function, using the OperationDef argument, to build an argument list for the operation.
  10. Set the argument value within the operation list.
  11. Send the request and retrieve the results as you would any other request. You can use any of the options described in this topic to send a request and to retrieve the results.

  Back to Top       Previous  Next