![]() |
![]() |
|
|
Using the Dynamic Invocation Interface
This topic includes the following sections:
The information in this topic applies to CORBA C++ and CORBA Java client applications. DII is not supported in ActiveX 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.
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:
Use the CORBA::Object::_request member function to create an empty request object specifying only the interface name you intend to invoke in the request (for example, get_course_details). Once the request object is created, the arguments, if there are any, must be added before the request can be sent to the CORBA server application. You invoke the CORBA::NVList::add_value member function for each argument required by the method you intend to invoke.
You must also specify the type of the request's result using the CORBA::Request::result member function. For performance reasons, the messages exchanged between Object Request Brokers (ORBs) do not contain type information. By specifying a place holder for the result type, you give the ORB the information it needs to properly extract the result from the reply. Similarly, if the method you are invoking can raise user exceptions, you must add a place holder for exceptions before sending the request object.
When you use the CORBA::Object:: _create_request member function to create a request object, you pass all the arguments required to make the request and to specify the types of the result and user exceptions, if there are any, that the request may return. Using this member function, you create an empty NVList, add arguments to the NVList one at a time, and create the request object, passing the completed NVList as an argument to the request. The potential advantage of the CORBA::Object::_create_request member function is performance. You can reuse the arguments in multiple CORBA::ORB::_create_request calls if you invoke the same method on multiple target objects.
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:
This member function determines whether a request has completed and is ready to be processed. This member function does not block. If the request is ready, the CORBA client application has to use the get_response() or get_next_response() member functions to process the response. Use this member function when you don't care about the order in which responses are processed, you want the CORBA client application to process other requests while waiting for a specific response, or you want to impose a timeout.
This member function indicates whether a response for any outstanding request is ready to be processed. If the request is ready, the CORBA client application has to use the get_response() or get_next_response() member functions to process the response. Use this member function when the order in which requests are processed is not important and you want the CORBA client application to process other requests while waiting for a specific response.
This member function blocks until the response for the specific request is completed and processed. Use this member function when you want to process the requests for outstanding requests in a particular order.
This member function blocks until a response for any outstanding requests are completed and processed. Use this member function when the order in which requests are processed is not important.
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:
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
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:
![]() |
![]() |
![]() |
|
Copyright © 2001 BEA Systems, Inc. All rights reserved.
|