New York University

Computer Science Department

Courant Institute of Mathematical Sciences

 

Using the Dynamic Invovation Interface (DII)

 

 

Course Title: Application Servers                                           Course Number: g22.3033-011

Instructor: Jean-Claude Franchitti                                            Session: 4

 

Introducing the Dynamic Invocation Interface

Until now, the CORBA clients you've implemented have been static in some respect, aware of only the interfaces whose client stubs had been included with the rest of the client application at compile time. However, there are times when more dynamic client applications are called for, and this is where DII comes in.

 

It should be stressed that the Dynamic Invocation Interface could quite possibly be the least useful feature of CORBA. You'll see later in this handout that there are only a handful of types of applications which really benefit from using DII; in almost all other cases, chances are that you'll never have to use DII.

 

The Purpose of DII

As stated earlier, DII enables a CORBA client application to discover interfaces at runtime. This means that such a client application can be compiled with no client stubs at all, thus having no prior knowledge of any type of CORBA server object. (The client need not discover all server interfaces dynamically, though; it can be compiled with client stubs for some interfaces and find other interfaces dynamically.) In any case, DII is the enabling feature of CORBA that lets clients use services of objects that were unknown to the client at compile time. (Note that the use of DII only applies to a client; when a server method is invoked, that server has no knowledge of whether a method was invoked via the conventional static mechanism or through DII.)

 

So why is the Dynamic Invocation Interface useful? After all, shouldn't the designer of an application know what kind of objects the application will need to access? In most cases, this is true, but some types of applications, although uncommon, do benefit from the capability to discover new object types and use them. There are at least two practical examples: a CORBA design tool and a generic object browser application.

A Hypothetical CORBA Design Tool Using DII

One potential use for DII is in a design tool for creating CORBA applications. Such a tool would have access to the IDL interfaces used to create the CORBA objects, because developers don't generally deal with CORBA objects for which they have no source code or IDL. However, because you can never be sure what developers are going to do, it would be a nice touch for the tool to have the capability to discover existing CORBA interfaces and generate client code to use those objects. The tool could also enable the developer to plug in CORBA server objects based on either their IDL interfaces or the interfaces as determined through DII (much as controls can be plugged in to development tools such as Visual Basic and JavaBeans-aware Java development tools).

A Generic Object Browser Using DII

Another possible use for the Dynamic Invocation Interface is in an esoteric, but sometimes practical, application: one that browses objects on the network. There are many reasons why you might want to do this in some types of applications. For example, envision an automated test application that discovers objects, learns their interfaces, and invokes each method in the interface with a set of dummy parameters. The results could then be recorded and later analyzed to determine objects' compliance with a test plan. Because the test application would discover object interfaces dynamically using DII, it would not need to be recompiled to handle new types of objects, making it useful as a generic testing tool.

 

Yet another type of object browsing tool could look for objects that implement particular methods and then enable a user to access those objects. This would be helpful if a particular design called for a set of standard methods that should be implemented by all objects in the system, but for some reason it did not define a base class from which all interfaces would derive (this is not always possible when mixing together interfaces from various sources, such as different products or different projects). For example, if each object were to define a killObject() method, an object browser could use DII to look for objects that defined such a method, which would in turn enable users to kill objects at will. Although this is a trivial example, it sets the stage for a more complex set of methods that could, for example, provide remote system administration features.

 

Taking this idea one step further, it would be possible to design a Web object browser that could browse objects, instead of Web pages consisting of static HTML, Dynamic HTML, Java applications, and so on. Objects could support a basic interface and also, optionally, offer additional capabilities in the form of methods that the browser could discover through DII. Because such an application would most likely be interactive, the user could determine which methods were interesting through inspection. In fact, a clever browser application could determine which methods are interesting, based on their names and parameter lists.

 

As a final example, consider an interpreted scripting language such as Perl or Tcl (or some other fictitious scripting language). DII could be used to interface such a language with CORBA objects. When a script accessed an operation on a CORBA object, the interpreter could use DII to "assemble" a remote method invocation from the IDL interface definition, pass the proper arguments to the method, and return the result to the script. Here the language interpreter would essentially replace the IDL compiler, which as you should recall is usually responsible for interfacing CORBA objects with various languages. However, the language interpreter would also have to become an IDL compiler of sorts, since it would have to translate IDL definitions into DII method calls.

Comparison with Static Interfaces/IDL

By now it has been established that DII offers at least one advantage over the conventional static process of invoking methods on objects. You have also seen some potential applications in which DII would prove useful. Although this range of applications is admittedly limited, DII is instrumental in making them possible--without DII, such applications could not exist at all. To review the advantages of DII:

 

·        A client need not be aware of server interfaces at compile time; in fact, the interface definition for the server object does not need to even exist at the time that the client is compiled. This makes possible enormous flexibility in applications using DII (if you can find an application that requires such flexibility).



·        The DII offers several options for obtaining return parameters from a method. The client application can obtain the result normally, invoke the method using oneway semantics (even if the interface's IDL did not declare the method as oneway, although this may not be advisable), or poll for a result. These options enable even greater flexibility in DII applications than in their static invocation-making counterparts.

 

There are, however, some disadvantages associated with using the Dynamic Invocation Interface:

 

·        Applications using DII are more complex than their client stub-using counterparts. This is because a method call through DII must push each of the input arguments one at a time, invoke the method, and then pull each of the return arguments back. If this is done by hand, it can be a tedious and error-prone process.



·        While static type-checking capability is built into the static method invocation mechanism, there essentially is none for DII method calls. Consequently, subtle differences in interface definitions may cause an application to inadvertently invoke incorrect methods--even if the application code compiles correctly! Such errors can be difficult to track down, making them especially insidious.

 



·        Because each argument to a method must be pushed one at a time, additional overhead is incurred in each DII method call.



·        Of course, there is also the overhead associated with the actual discovery of interfaces. A DII client will typically need to "negotiate" with a server (or a number of servers) to locate the interface (or interfaces) in which that client is interested.

 

Using DII: An Overview

Now that you know what the DII is designed for, you need to see how it is used. The process of issuing a DII method invocation differs from issuing a static method invocation, as you might expect. There are three major concepts associated with using the DII: the Request object, the use of Anys and available options for sending requests and receiving replies.

Introducing the Request

The Request is a "pseudo-object" (that is, it does not represent a CORBA object, but is implemented as an object as far as the implementation language is concerned) that invokes a method on a CORBA object. To invoke a method using DII, you first obtain a reference to the object on which the method is to be invoked. Then, using the object's request() or create_request() method, you create a Request object. Depending on which method you choose, you populate the Request with arguments, return types, and exceptions, using the add_value() and result() methods of the Request object. Then you invoke the method (using one of the methods discussed later in this section) and finally retrieve the result of the method invocation (again using one of the methods discussed later).

 

The purpose of the Request is to encapsulate input parameters to method invocations and return result values from them. A Request can be created in one of two ways, depending on how you intend to use the Request. (Note that a Request object can be used for only one method invocation on one object; to call a method twice, call two separate methods on the same object, or to call methods on two different objects, you need to create two Request objects.) The two methods for creating a Request object are as follows:

 

·        Invoke the request() method on the CORBA object. The request() method takes the name of the method to be invoked as a parameter, for instance, request("getBanks"). You then call add_value() on the returned Request object to add input parameters. Finally, you call result() on the Request object to specify the type of the return parameter.

·        Invoke the create_request() method on the CORBA object. This method takes several parameters that populate the Request object before it is returned. The arguments used in the call to create_request() can be reused, possibly enhancing performance.

Anys and TypeCodes: A Review

An object of type Any can contain any type of object; a TypeCode is an object that describes an object's type. An Any consists of a TypeCode (describing the type of the Any) and the value itself. Most likely, when using the DII, you'll obtain TypeCodes through the ORB methods create_struct_tc() and create_exception_tc().

 

Another object you'll encounter when using DII is the NVList (NV stands for Named Value). An NVList is a list of corresponding names, values, and flags that specify whether its value is an in or out parameter. The values stored in the NVList are Anys. When using the request() method of an object to generate a Request, you simply add the arguments one at a time using add_value(); however, when using the create_request() method, you use an NVList to specify the input arguments to the method being called. In either case, the return value from the method invocation is always supplied in an NVList.

Request and Reply Options

A variety of options exist for sending a Request to a CORBA object. After the Request psuedo-object is created and the arguments for the method are specified, you invoke the method in one of the following ways:

 

·        Call the invoke() method on the Request. This method behaves in a way you're most likely accustomed to (with non-oneway calls), blocking until the reply is received.

·        Call the send_deferred() method on the Request. This method invokes the request but returns immediately; you can then retrieve the reply using one of the following methods:

·        Call the send_oneway()method on the Request. You should do this only if the method being invoked is declared as a oneway method in the IDL definition.

·        You can also use send_multiple_requests_deferred() and send_multiple_requests_oneway() on the ORB to invoke a number of methods on different objects in parallel.

 

Depending on how a method is invoked, there are several possible ways to obtain the results of the method invocation:

 

·        First, call the env() method on the Request to determine whether an exception was raised. If there was no exception, call the result() method on the Request object to obtain the NVList that contains the results of the method invocation. Use this method if you invoked the method using the invoke() method on the Request.

·        Call the poll_response()method on the Request to periodically check for a response from the method invocation. After poll_response() indicates that the result has been received or the client wants to block while waiting for the result, call the get_response() method on the Request object. Use this method if you invoked the method using the send_deferred() method.

·        Of course, if you used the send_oneway() method, there is no return result, and thus you don't call any method to get it.

 

Now that you're familiar with the process of invoking a method via DII, it's time for an example.

DII Example

Using DII in a simple example is more straightforward than it might sound. You can obtain an object reference in much the same way as you have in the past, using the ORB's bind() mechanism (keeping in mind that bind(), while being nonstandard, is useful for developing simple examples). However, the object reference you obtain will be a generic object reference, pointing to a generic CORBA::Object, rather than an instance of a specific object type. The following are some highlights from a CORBA client that uses DII:

 

CORBA::ORB_ptr orb;

CORBA::Object_ptr helloWorld;

 

Of course, first of all, you need a pointer to an ORB object. You also want a pointer to the object to which you'll be connecting. In this case, the object is a fictitious "Hello World" object, featuring a single method helloWorld() that takes a CORBA::String as a parameter and returns a CORBA::Long. The method does not raise any exceptions (but remember that a CORBA System Exception can be raised by any remote method). Note that the pointer to the HelloWorld object is a generic CORBA::Object pointer.

 

CORBA::NamedValue_ptr resultVal;

CORBA::Any_ptr resultValAny;

CORBA::Long returnValue = 0;

CORBA::Request_ptr request;

CORBA::Any string;

 

Next, you need a few other pointers. One holds the NamedValue returned by the DII method invocation. Another pointer holds the Any value contained in the NamedValue. A CORBA::Long variable is created to hold the actual return value. Also, a pointer is created to hold the Request object returned by the invoke() call. Finally, a pointer is created to hold the input parameter (which is the string "Hello World").

 

orb = CORBA::ORB_init(argc, argv);

 

You should be familiar with this call by now; it simply initializes the ORB. This much is the same in a DII application as in a static invocation application.

 

try {

    helloWorld = orb->bind("IDL:HelloWorld:1.0");

} catch (const CORBA::Exception& ex) {

    cout << "Could not bind to HelloWorld" << endl;

    cout << ex << endl;

    return 1;

}

 

Now the client application attempts to bind to the desired HelloWorld object. Note that, because the application does not have a client stub for the HelloWorld object, rather than use the HelloWorld::_bind() method, it uses the ORB::bind() method with a slightly revised syntax to obtain a reference to a HelloWorld object.

 

try {

    request = helloWorld->_request("helloWorld");

    string <<= "Hello World";

    CORBA::NVList_ptr arguments = request->arguments();

    arguments->add_value("string", string, CORBA::ARG_IN );

 

The client application asks the HelloWorld object to create a Request object by calling the request() method. The name of the method that the client wants to invoke on the HelloWorld object is the helloWorld() method, which is used as the parameter to the request() method. Then the client gets a parameter list (an NVList) from the Request object through its arguments() method and proceeds to populate the NVList with the single argument to the helloWorld() method: a CORBA::String with the value "Hello World". This argument is added as an input parameter using the add_value() method on the NVList.

 

    resultVal = request->result();

    resultValAny = result->value();

    resultAny->replace(CORBA::_tc_long, &resultVal);

} catch (const CORBA::Exception& ex) {

    cout << "Could not create request" << endl;

    cout << ex << endl;

    return 1;

}

 

Before submitting the Request, the client must do one more thing: Specify the expected return type for the method. As the method is expected to return a CORBA::Long, the TypeCode for this type is pushed into the result. To do this, the client calls result() on the Request object, gets the value() (which is an Any) from the result, and sets the type and value of the Any returned to be CORBA::Long. The client is now ready to invoke the method through DII.

 

try {

    request->invoke();

    CORBA::Environment_ptr env = request->env();

    if (env->exception()) {

        cout << "An exception occurred: " << *env->exception() <<

                endl;

    returnValue = 0;

    } else {

        returnValue = *(CORBA::Long*)resultValAny->value();

    }

} catch (const CORBA::Exception& ex) {

    cout << "Could not invoke request" << endl;

    cout << ex << endl;

    return 1;

}

cout << "The return value was " << returnValue << endl;

 

Finally, the client invokes the helloWorld() method on the HelloWorld object through the invoke() method on the Request. The client then checks for any exceptions that were raised by calling env() on the Request object and checking the returned environment by calling exception(). If this call returns a non-NULL result, then an exception was raised by the method call, and the exception is reported. If there is no exception, the client can call value() on the Any that was previously returned by the result() method, casting the value of the Any (obtained by calling value()) to a CORBA::Long, which is what the type of the Any should be.

 

Compared to the equivalent static invocation, you can see that the Dynamic Invocation Interface is much more involved. It is for this reason that most CORBA developers avoid the DII; the added flexibility often does not justify the added programming complexity. When the functionality offered by the DII is required, DII is necessary; otherwise, it is probably best left alone.

 

It is probably worth reiterating once more that most developers will never need to touch DII. Aside from the sort of examples provided earlier in this handout, DII is not useful for most applications, and would generally only add unnecessary complexity to most applications. If you're developing tools--such as development and system management tools--that need to work with unknown CORBA objects in a generic way, you might find DII useful; otherwise, you'll find that it provides little, if any, benefit.

Summary

This handout illustrates a way to invoke methods on remote CORBA objects--through the Dynamic Invocation Interface (DII). You also learned about the advantages and disadvantages of the DII mechanism compared to the traditional method of static invocation, as well as some potential practical applications of the DII mechanism. You then learned how to employ the DII features in an application, witnessing firsthand its extreme complexity compared to the static invocation to which you're accustomed.

Q&A

Q I think I need to use DII.



A
You don't. Actually, this answer is only partly tongue-in-cheek. DII invites many opportunities for confusion and difficult-to-trace errors in your application development efforts. Unless you're developing an application similar to those described in the examples in this handout and absolutely need to take advantage of a feature offered by DII, it is almost certain that you don't want to even think about DII.



Q If DII is so useless for most applications, why does the CORBA specification bother with it in the first place?



A
In the early days of CORBA, there were two camps with opposing views regarding how methods should be invoked. From one camp's view evolved the static invocation mechanism, and from the other came the DII.

Workshop

The following section will help you test your comprehension of the material presented in this handout and put what you've learned into practice.

 

Quiz

1.      Would you expect DII to be useful to most CORBA application developers? Why or why not?

2.      What are the advantages of DII over static method invocation?


3
. What are the disadvantages of DII compared to static method invocation?