[Previous] [Contents] [Next] [IONA Technologies]


Chapter 19
Dynamic Invocation Interface


Contents

19.1 Example
19.2 Using the DII
19.2.1 Obtaining an Object Reference
19.3 Using the DII: CORBA Based Approach
19.3.1 Creating a Request
19.3.2 Setting up a Request using _request()
19.3.3 Invoking a Request
19.3.4 Setting up a Request using _create_request()
19.3.5 Using the DII with the Interface Repository
19.3.6 Adding a Context Parameter
19.3.7 Setting up a Request to Read or Write an IDL Attribute
19.3.8 Operation Results
19.3.9 Interrogating a Request
19.4 Alternative Ways of Using the DII
19.4.1 Using Insertion Methods to Add Parameters to a Request
19.4.2 Using Extraction Methods to Extract Results from a Request
19.4.3 Inserting and Extracting Array Types
19.4.4 Resetting a Request Object for Reuse
19.5 Deferred Synchronous Invocations
19.6 Using Filters with the DII



As we have seen, IDL is used to describe interfaces, and the IDL compiler is used to generate the necessary support to allow clients to invoke remote objects. Specifically, the IDL compiler automatically builds the appropriate code to manage proxies, to route operation invocations to objects in servers, and to manage the underlying OrbixWeb services.

However, the use of the IDL compiler in this way is a limiting approach for an important subset of applications. The IDL interfaces which a client program can use are determined when the client program is compiled. Hence the client code is limited to using those servers which contain objects that provide the IDL interfaces selected by the client programmer when building an application. Some application programs and tools require that they can use an indeterminate range of interfaces: interfaces which perhaps were not even conceived at the time the applications were developed. Examples include browsers, management support tools and distributed debuggers. It certainly is not desirable to limit a browsing tool to a fixed set of pre-defined interfaces.

OrbixWeb therefore supports a Dynamic Invocation Interface (DII) which allows an application to issue requests for any interface, even if that interface was unknown at the time the application was compiled. OrbixWeb DII support allows invocations to be constructed by specifying at runtime the target object reference, the operation name and the parameters. Such calls are termed "dynamic" because the IDL interfaces used by a program do not have to be "statically" determined at the time the program is designed and implemented.

Note that an OrbixWeb server receiving an incoming invocation request does not know–or care–whether the client which sent the request used the static (that is, use of proxies) or dynamic approach to compose the request.

19.1 Example

To demonstrate the use of the DII, we will use the familiar bank example making use of the following IDL definitions:

To better illustrate the use of the DII, we have extended the newAccount() operation to take an inout parameter denoting the initial balance.

A programmer can make dynamic invocations by constructing a Request object and then invoking an operation on the Request object to make the request. Class Request is defined in the OrbixWeb IE.Iona.Orbix2.CORBA package.

In the examples that follow, we create a request for the operation newAccount() with the aim of dynamically invoking an operation whose static equivalent is:

19.2 Using the DII

This chapter explains how a client can make dynamic invocations. To do so, the following steps are required:

    1. Obtain an object reference.
    2. Create a Request object.
    3. Populate the Request object with the object reference, details of the name of the operation and the parameters to the operation.
    4. Invoke the request.
    5. Obtain the result, if necessary.
The following code illustrates some of these steps using the set of parameter insertion methods supplied by the OrbixWeb class Request:

To improve clarity, exception handling code (as described in Chapter 12) is not included in this example or most of the remaining examples in this chapter. However, developers should note that this sample code will not compile without the inclusion of OrbixWeb exception handling.

This example is unrealistic since it assumes we know the name of the operation (newAccount). In practice, this information would be obtained in some other way, for example from the Interface Repository as explained in Chapter 20, "Interface Repository".

In the remainder of this chapter, we will describe in detail the DII programming steps outlined above. In particular, we will illustrate two alternative approaches to setting up a Request: the first is based on the CORBA standard specification of the DII; the second uses a set of Request parameter insertion and extraction methods (as shown in the above sample code) and is specific to OrbixWeb.

19.2.1 Obtaining an Object Reference

Assume that there is already some server which contains a number of objects that implement the interfaces in section 19.1. The first step in using the DII is to obtain an object reference of interface type _ObjectRef (defined in package IE.Iona.Orbix2.CORBA) which references the target object.

If the full object reference of the target object is known in character string format, then an object reference, of a type which implements _ObjectRef, can be constructed to facilitate making a dynamic invocation on it. For example, this can be achieved by invoking the method string_to_object() on the IE.Iona.Orbix2._CORBA.Orbix object as follows:

In this example, the variable refStr is a stringified object reference for the target object, perhaps retrieved from a file, a mail message, or an IDL operation call.

19.3 Using the DII: CORBA Based Approach

This section demonstrates how to use the DII using the OrbixWeb implementation of the classes and operations defined in the CORBA specification.

19.3.1 Creating a Request

CORBA specifies two ways to construct a Request object. These are implemented in OrbixWeb as follows:

    1. The method _request() is defined in interface _ObjectRef. It is declared as:
       // Java
       // in package IE.Iona.Orbix2.CORBA,
       // in interface _ObjectRef
       
       public IE.Iona.Orbix2.CORBA.Request 
       		_request(String operation);
      
    This method takes a single parameter which specifies the operation to be invoked on the target object.
    2. The method _create_request() is also defined in interface _ObjectRef. It is declared as:
       // Java
       // in package IE.Iona.Orbix2.CORBA,
       // in interface _ObjectRef
       public int _create_request(
       	IE.Iona.Orbix2.CORBA.Context ctx,
       	String operation, 
       	IE.Iona.Orbix2.CORBA.NVList arg_list,
       	IE.Iona.Orbix2.CORBA.NamedValue result, 
       	IE.Iona.Orbix2.CORBA.RequestHolder hrequest,
       	IE.Iona.Orbix2.CORBA.Flags req_flags)
       	throws IE.Iona.Orbix2.CORBA.SystemException;
      
The use of these methods is described in turn in section 19.3.2 and section 19.3.4. (An alternative approach to request construction is explained in section 19.4.)

19.3.2 Setting up a Request using _request()

A request is set up by invoking _request() on the target object and specifying the name of the operation which is to be dynamically invoked. In our first attempt at constructing the request, we will write the code in a verbose fashion so that the individual steps can be explained easily. We will then show a simpler more compact version of the same code.

The following steps are required in setting up a Request using the _request() method:

    1. Obtain an object reference to the target object. We use the stringified object reference obtained earlier (section 19.2.1):
       // Java
       IE.Iona.Orbix2.CORBA._ObjectRef oRef =
       	IE.Iona.Orbix2._CORBA.Orbix.string_to_object 
       	(refStr);
      
    2. Construct a Request object by calling _request() on the target object.
       IE.Iona.Orbix2.CORBA.Request request = 
       	oRef._request("newAccount"); 
      
    3. Populate the Request. First obtain an empty NVList which will contain the parameters to the operation request. The method create_list() can be invoked on the _CORBA.Orbix object to create an operation list whose length is specified in the first parameter.
    An NVList is a list of NamedValue elements. A NamedValue contains a name and a value, where the value is of type Any and is used in the DII to describe the arguments to a request. The Any can be obtained using the value() method defined on class NamedValue.
    The code to create the NVList and add the NamedValues is:
       import IE.Iona.Orbix2._CORBA;
       import IE.Iona.Orbix2.CORBA.Flags;
       import IE.Iona.Orbix2.CORBA.NamedValue;
       import IE.Iona.Orbix2.CORBA.NVList;
       import IE.Iona.Orbix2.CORBA.NVListHolder;
       
       ...
       
       NVList argList = request.arguments ();
       NVListHolder argListHld = 
       	new NVListHolder (argList);
       
       NamedValue ownerArg, balanceArg;
       
       if (_CORBA.Orbix.create_list (2, argListHld)) {
       	ownerArg = argListHld.value.add 
       		(new Flags (_CORBA.ARG_IN));
       	balanceArg = argListHld.value.add
       		(new Flags (_CORBA.ARG_INOUT));
       
       	// Fill in name of operation and values of 
       	// parameters as shown below ...
       }
      
    The method NVList.add()1 creates a NamedValue and adds it to the NVList. It returns a NamedValue pseudo object reference for the newly created NamedValue.
    The parameter to NVList.add() can be a Flags object initialised with one of the following:

    _CORBA.ARG_IN

    Input parameters (IDL's in).

    _CORBA.ARG_OUT Output parameters (IDL's out).

    _CORBA.ARG_INOUT Input/output parameters (IDL's inout).


    The parameter must be correctly chosen to match the corresponding formal argument.
    The NamedValues added to the NVList correspond, in order, to the parameters of the operation. They must be inserted in the correct order. The parameters to a request will be (dynamically) type checked by OrbixWeb on the server's node when the request arrives at the remote object.
    To fully populate the request, the final task is to update the Any contained in each NamedValue element of the argument list with the value that is to be passed in the operation request.
    To update the first parameter to the operation newAccount():
       // Insert the value of the parameter 
       // into the Any
       ownerArg.value().insertString ("Chris");
      
    To update the second parameter:
       Any balanceValue = balanceArg.value();
       // Insert the value of the parameter 
       // into the Any
       balanceArg.value().insertFloat ((float)1000.00);
      

Compact Syntax

The code above can be written more compactly by making use of the return values and the method Request.arguments() which returns the argument list (of type NVList):

19.3.3 Invoking a Request

Once the parameters are inserted, the request can be invoked as follows:

Note that a Request invocation can raise both OrbixWeb system exceptions and user-defined exceptions. The OrbixWeb classes SystemException and UserException both inherit from class CORBAException, so this class is specified in the Java catch clause in order to handle all possible invocation errors.

If the invocation throws a user exception of unknown type, then the application will catch a system exception of type UNKNOWN.

19.3.4 Setting up a Request using _create_request()

This section shows how to use the CORBA defined method Request._create_request() to create a request:

The parameters of this method are as follows:

The return value is of type int: the method _create_request() returns zero to indicate failure and one to indicate success.

The example shown below constructs a Request for operation newAccount(), passing the parameters "Chris" and 1000.00 as before. The argument list is created as in section 19.3.2 using ORB.create_list(). We use the compact syntax described in that section to add the arguments to argList (of type NVList):

19.3.5 Using the DII with the Interface Repository

If the programmer has obtained a description of the operation (of type IE.Iona.Orbix2.OperationDef) from the Interface Repository, then an alternative way to create an NVList is to call the operation create_operation_list() on the _CORBA.Orbix object:

This method returns an NVList, stored in the value of the parameter hnew_list, initialised with the argument descriptions for the operation specified in operation. The returned NVList is of the correct length (with one element per argument), and each NamedValue element of the list has a valid name and valid flags (denoting the argument passing mode). The value (of type Any) of the NamedValue has a valid type (denoting the type of the argument). The value of the argument is not filled in.

The use of the Interface Repository is described in Chapter 20, "Interface Repository".

19.3.6 Adding a Context Parameter

If the IDL operation has a context clause then a Context object can be added to the request using the method ctx() on class Request:

19.3.7 Setting up a Request to Read or Write an IDL Attribute

The DII can also be used to read and write attributes. To read the attribute balance, for example, the operation name should be set to "_get_balance". For example:

In general, for attribute A, the operation name should be set to one of the following:

     _get_A
    
to read the attribute.

     _set_A
    
to write the attribute.

19.3.8 Operation Results

A request can be invoked as described in section 19.3.3. Once the invocation has been made, the return value and output parameters can be examined. If there are any out or inout parameters, then these parameters would be modified by the call, and no special action is required to access their values. Their values are contained in the NVList argument list which can be accessed using the method Request.arguments().

The operation's return value (if it is not void) can be accessed using the method Request.result() which returns a NamedValue.

19.3.9 Interrogating a Request

The operation name and the target object's object reference of a Request can be determined using the methods operation() and target(), respectively.

19.4 Alternative Ways of Using the DII

The OrbixWeb implementation of class Request contains a set of insertion and extraction methods which can be used to add parameters values to a Request object before operation invocations and remove results afterwards. We will illustrate the functionality of these methods in this section.

As in the previous sections, exception handling code is omitted from examples in order to improve clarity, but must be added before compilation.

19.4.1 Using Insertion Methods to Add Parameters to a Request

Class Request includes an insertion method for each of the standard IDL types, such as long, unsigned long, float, Object, any, and string. These insertion methods are named insertLong, insertULong, insertFloat, and so on.

A single-element insertion method simply takes the element value as a parameter. For example, the signature of Request.insertLong() is as follows:

Class Request also provides an insert() method, which supports the insertion of parameters of all user-defined types. Java classes generated for user-defined types inherit from the OrbixWeb class Marshalable, so the signature for insert() can be defined as:

The first step in using any of these insertion methods is to obtain an object reference, as described in section 19.2.1. Assume we have an object reference:

The next step is to create a Request object, and to use it to define the target object, the operation name, and the parameters of the call. OrbixWeb provides Request class constructors which simplify the creation of a Request object. For example:

In this case, the Request object is built for a specific target object reference. Alternatively, both the target and the operation name can be specified to the constructor:

All of the parameters (in, out, and inout) to the request should now be given. The insertion methods do not allow the parameter passing mode to be specified implicitly, so the Request object stores a flag value which indicates the current insertion mode. This value can be read using the argFlags() method and set using the setArgFlags() method.

The default parameter attribute mode is in. If another parameter passing mode is set using setArgFlags(), then this changes the parameter attribute mode for all subsequent parameters for this Request object or until another call to setArgFlags() is used.

To insert the parameters to operation newAccount(), the programmer could do the following:

The parameters must be inserted in the correct order.

Once the parameters are inserted, the request can be made as follows:

19.4.2 Using Extraction Methods to Extract Results from a Request

Once the invocation has been made, the first task is to force the values of inout and out parameters to be updated. This can be done by calling the Request method extractOutParams() as follows:

The values of the variables passed as inout and out parameters will now be updated.

The operation's return value can be extracted from the Request object using the appropriate extraction method for the return type. Class Request provides an extraction method for each of the standard IDL types, called extractLong(), extractULong(), extractFloat(), and so on. The method extractAny() illustrates the signature format of these methods:

Class Request also provides an extract() method, which supports the retrieval of return values of all user-defined types. Java classes generated for user-defined types inherit from the OrbixWeb class Marshalable, so the signature for extract() can be defined as:

In our example, the Account object returned from operation newAccount() can be extracted from the Request as follows:

Note that this method extracts the Account object to type _ObjectRef. If the IDL generated Account class is available to the client, this object reference could be narrowed to type _AccountRef (using method Account._narrow()).

19.4.3 Inserting and Extracting Array Types

To support the insertion of array parameters of each IDL type into an Request object, a set of array insertion methods are supplied. The name of each array insertion method is similar to that of the equivalent single-element insert method, with the word Array appended. For example, the array insertion method for type long is named insertLongArray(), while the generic method for the insertion of arrays of user-defined types is insertArray().

An array insertion method takes the array value and array length as parameters. For example, the signature of insertLongArray() is as follows:

The extraction of array return types from a Request is also supported. For this purpose, class Request includes a set of array extraction methods. These methods include extractLongArray(), whose signature can be described as:

Note that each of the array extraction methods takes two parameters: an array of the appropriate type, and the length of the incoming array. The array parameter must be a pre-allocated array of sufficient length to hold the return value. If the length parameter is less than the length of the array value, OrbixWeb will throw a system exception of type BAD_PARAM. The extraction method returns the actual length of the array extracted.

19.4.4 Resetting a Request Object for Reuse

In an OrbixWeb client which uses the DII, it is often necessary to make several operation invocations. This can be done by declaring and instantiating individual Request objects for each invocation. However, OrbixWeb provides the method reset(), which allows a Request variable to be reused.

The method reset() is called on the Request object and clears all of the Request fields, including its target object and operation name. For example, the Request variable r in our example could be reused for an invocation of operation makeDeposit() as follows:

or as follows:

19.5 Deferred Synchronous Invocations

In addition to using the invoke() operation on a Request, OrbixWeb supports a deferred synchronous invocation mode. This allows clients to invoke on a target object and to continue processing in parallel with the invoked operation. At a later point, the client can check to see if a response is available, and if so can obtain the response. This may be useful to improve the throughput of a client, particularly in the case of long-running invocations.

To use this invocation mode, a request should be invoked in one of the following two ways:

1. Method send_deferred() can be called on the Request.
The caller will continue in parallel with the processing of the call by the target object. The caller can use the method poll_response() on the Request to determine whether the operation has completed and get_response() to determine the result.
2. Method send_oneway() can be called on the Request. This method must be used when the operation is a oneway operation.
The caller will continue in parallel with the processing of the call by the target object.
Multi-cast requests are also allowed. Two methods are provided which may be called on the _CORBA.Orbix object. These are: ORB.send_multiple_requests_oneway() and ORB.send_multiple_requests_deferred().

19.6 Using Filters with the DII

OrbixWeb allows a programmer to implement methods which will be invoked at specified filter points in the invocation of a request, as described in Chapter 21, "Filters". In general, use of the DII does not by-pass this filter mechanism, and all filter points implemented by a programmer will be called during the invocation of a dynamic request.

However, there is one filter point which does not conform to this rule. The filter point inReplyPostMarshal() will not be invoked on a DII request, unless the programmer makes an explicit method call after retrieving all operation results from a Request object. In particular, the programmer should call the following method:

It is important that this method is called on the Request object after all parameter values and the return value have been extracted.



1 Class NVList, also provides a method add_value() which takes three parameters: the name of the NamedValue (that is, the name of the formal parameter in the IDL operation); the value, of type Any of the NamedValue; and a flag indicating the mode of the parameter. For example:



[Roadmap] [Introduction] [GS: Applications] [GS: Applets]
[IDL] [Mapping] [Programming OrbixWeb] [Publishing Objects] [Retrieving Objects] [IIOP]
[Running Clients] [Running Servers] [Exceptions] [Inheritance] [Callbacks] [Contexts]
[API Configuration] [TypeCode] [Any] [DII] [IR] [Filters] [Smart Proxies] [Loaders] [Locators]
[Index]