What If I Don't Know the Interface? (Java Enterprise in a Nutshell) Book Home Java Enterprise in a Nutshell Search this book

4.5. What If I Don't Know the Interface?

In the examples we've seen so far, we've always assumed that the Java interfaces for the remote objects are available at compile time. But what happens if they aren't? You might get a reference to a CORBA Object from a Naming Service, for example, and not know what interface that object implements. I mentioned earlier that you can use an org.omg.CORBA.Object reference directly to make requests and exchange data with its remote object.

The CORBA standard defines two complementary APIs for this purpose: the Dynamic Invocation Interface (DII) that a client can use to make remote method requests of a server object, and the Dynamic Skeleton Interface (DSI) that a server-side skeleton can use to forward method invocations to its server implementation object. Both of these APIs provide the same essential function: a dynamic interface to an object whose interface is not known at compile time. The DII offers this functionality to clients of CORBA objects, and the DSI provides it to the server-side skeletons that bridge the object implementation with the ORB.

The DII and DSI may seem like sidebar topics in the CORBA world, but in reality they are at the heart of CORBA and how it works. When we generate Java stubs and skeletons from IDL interfaces, the code that is generated uses the DII and DSI to execute remote method calls. The details of how this is done are shielded from you, the developer, by the Java interface you use to interact with the remote object. But it's still worthwhile to understand how CORBA objects implement their distributed nature, especially in situations where the Java interface for the remote object is not there, and you need to deal directly with these details.

In this section, we take a look at how the DII works and how you might use it in a client. We won't cover the DSI in this book, since its practical uses are even more limited for the average developer. Note, however, that the API of the DSI is analogous to that of the DII, so you shouldn't have much trouble mapping the following explanation to the DSI as well.

4.5.1. Dynamic Invocation Interface

The Dynamic Invocation Interface provides abstract representations of remote method requests and their arguments. In simple terms, this means it includes objects that represent remote method requests and parameters that are passed with these method requests. Methods on these objects allow you to set the parameters to the request, make the request, and get the results. DII's central classes are:

Request

A request to invoke a method on a remote object. Created by the client and issued through the ORB to the server object.

NamedValue

A named parameter to a method request. Conceptually, this is a name tied to an Any value. The name of the value must match the name of the parameter as specified in the IDL interface the remote object satisfies.

NVList

A list of NamedValue parameters used to represent an argument list passed into a remote method request.

Any

A general argument value. An Any object can contain the Java equivalent of any basic IDL type or an Object that can be described in IDL.

Context

A list of NamedValue objects used to specify any details of the client environment that shouldn't be passed as method arguments.

Once you get an org.omg.CORBA.Object reference to a remote object (using any of the approaches we've already covered), you can create and issue a method request to the object by building a parameter list for the method call, making a NamedValue object to hold the result, making a Context object and putting any useful environment values in it, and then using all of these items to create a Request object that corresponds to a particular method on the object. Example 4-11 shows a sample DII client that gets a reference to a remote object through a Naming Service and then makes a dynamic call to its doThis() method.

Example 4-11. Client Using DII to Make Remote Method Call

import org.omg.CORBA.*;
import org.omg.CosNaming.*;

public class DIISimpleClient {
  public static void main(String argv[]) {
    ORB myORB = ORB.init(argv, null);
    ORB singleORB = ORB.init();
    try {
      // Get a reference to the object
      org.omg.CORBA.Object ncRef = 
        myORB.resolve_initial_references("NameService");
      NamingContext nc = NamingContextHelper.narrow(ncRef);
      NameComponent nComp = new NameComponent("ThisOrThatServer", "");
      NameComponent[] path = {nComp};
      org.omg.CORBA.Object objRef = nc.resolve(path);

      // Now make a dynamic call to the doThis method.  The first step is
      // to build the argument list. In this case, there's a single String
      // argument to the method, so create an NVList of length 1.  Next
      // create an Any object to hold the value of the argument and insert
      // the desired value.  Finally, wrap the Any object with a NamedValue
      // and insert it into the NVList, specifying that it is an input
      // parameter.
      NVList argList = myORB.create_list(1);
      Any arg1 = myORB.create_any();
      arg1.insert_string("something");
      NamedValue nvArg = 
        argList.add_value("what", arg1, org.omg.CORBA.ARG_IN.value);

      // Create an Any object to hold the return value of the method and
      // wrap it in a NamedValue
      Any result = myORB.create_any();
      result.insert_string("dummy");
      NamedValue resultVal = myORB.create_named_value("result", result, 
          org.omg.CORBA.ARG_OUT.value);

      // Get the local context from the ORB.  
      // NOTE: This call does not work in Java 1.2, and returns a
      //   NOT_IMPLEMENTED exception.  To make this work in Java 1.2, simply
      //   remove this call to get_default_context(), and pass a null pointer
      //   into the _create_request() call below.  This example should work 
      //   as is with any compliant Java CORBA environment, however.
      Context ctx = myORB.get_default_context();

      // Create the method request using the default context, the name of
      // the method, the NVList argument list, and the NamedValue for the 
      // result.  Then invoke the method by calling invoke() on the Request.
      Request thisReq = 
        objRef._create_request(ctx, "doThis", argList, resultVal);
      thisReq.invoke();

      // Get the return value from the Request object and output results.
      result = thisReq.result().value();
      System.out.println("doThis() returned: " + result.extract_string());
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Note that in most situations you will have the Java interface for the remote object available in your client along with its helper class, so you'll be able to narrow the Object reference to a specific type. One exception might be if you're building some kind of software development tool, and you want to provide a dynamic execution utility for the CORBA code being developed. The previous example demonstrates how a CORBA method call can be carried out at this lower level, in case you ever find it necessary to do so. And when you're trying to fix a problem with your CORBA application, it's always better to understand what's going on under the hood, so to speak.



Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.