'; zhtm += ''; zhtm += '

' + pPage + ''; zhtm += '
'; window.popUpWin.document.write(zhtm); window.popUpWin.document.close(); // Johnny Jackson 4/28/98 } //--> Teach Yourself CORBA In 14 Days -- Ch 11 -- Using the Dynamic Invocation Interface (DII)


Teach Yourself CORBA In 14 Days

Previous chapterNext chapterContents


Day 11
Using the Dynamic Invocation Interface (DII)


On Day 10, "Learning About CORBA Design Issues," you took a short break from developing the sample Bank application to study some design issues raised by the CORBA architecture. As you saw, using CORBA sometimes requires you to rethink parts (or all!) of the design of some applications because CORBA introduces some restrictions of its own.

Today you'll continue your hiatus from the sample Bank application--this time to study a simple client that accesses a server object through the Dynamic Invocation Interface (DII). DII enables a client to access services without having been compiled with a client stub for those services. (Recall in the past that with your applications you had to compile and link client stubs that used CORBA object services.) How does this work? The DII enables CORBA clients to discover interfaces dynamically (in other words, at runtime rather than compile time) and invoke methods on objects that implement those interfaces. Today you'll learn about DII and why it is useful, and then you'll see how a client application is implemented to use DII services.

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. Thus, the BankClient and ATMClient applications only knew about the Bank interface, the ATM interface, the Account interface, and so on. For the purposes of the Bank application, static knowledge of interfaces works well; there is no reason for a client to access other types of objects unknown to it at compile time. However, there are times when more dynamic client applications are called for, and this is where DII comes in. (You'll see very soon the situations which call for the capability provided by DII.)

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 chapter 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. However, for the sake of completeness--and just in case, by some freak chance, you might ever find yourself needing to use it--a discussion of DII is included here.

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:

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

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 TypeCodes (which you will recall from Day 3), 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:

Anys and TypeCodes: A Review

You recall from Day 3 the discussion about the Any and TypeCode types. 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:

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

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 chapter, 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

Today you learned a new 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.

On Day 12, "Exploring CORBAservices and CORBAfacilities," you'll explore the next in the series of advanced CORBA topics--the use of CORBAservices and CORBAfacilities. Because a great number of features are offered by these services, there is space in this book for only a short description of each. However, you will also return to the sample Bank application and get the opportunity to integrate the use of a CORBAservice--namely, the CORBA Naming Service--with the Bank application.

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 chapter 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 today and put what you've learned into practice. You'll find the answers to the quiz in Appendix A. On most days, a few exercises will accompany the quiz; today, because no real "working knowledge" material was presented, there are no exercises.

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?


Previous chapterNext chapterContents


© Copyright, Macmillan Computer Publishing. All rights reserved.