What if I Don’t Have 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, or (more likely) not have that Java interface in the client JVM. We mentioned earlier that you can use an org.omg.CORBA.Object reference directly to make requests and exchange data with its remote object -- now we’ll briefly look at how the Dynamic Invocation Interface (DII) makes that possible.

The CORBA standard actually defines two complementary APIs for this purpose. The DII is used by a CORBA client to make remote method requests of a server object, while the Dynamic Skeleton Interface (DSI) can be used by a server-side skeleton to forward method invocations to its server implementation object in cases where it doesn’t have the actual servant interface available. 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 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 generated code 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.

On a more pragmatic note, there are cases where you might find yourself needing the DII and/or the DSI. In all the examples we’ve gone through in this chapter so far, we’ve assumed that both the server and client JVM’s had all of the relevant interfaces available locally. For clients, we assumed that somehow they had acquired the IDL-generated Java interface for our objects (Account, etc.). It is safe to assume you have access to the client machines directly, or can provide an easy way for users to download the required classes themselves as part of some installation process. Since the clients will obviously need to acquire your client code in the first place, it’s usually possible to provide the other CORBA client classes as well, and the DII isn’t needed. But if not (perhaps you want to minimize class downloads for some reason, for example), then it may be useful to use the DII to create a client that operates without the need for the object interfaces themselves.

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.

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. In general, the various create_XXX( ) methods on the ORB interface are used to construct all of these elements of a DII request, except for the Request itself. That is created by calling _create_request( ) on the Object that is the target of the remote method call.

Example 4-9 shows a version of our Account client that uses DII calls to invoke the deposit( ) or getBalance( ) methods on a remote Account object (the case for the withdraw( ) method is very similar to the deposit( ) case, so it’s omitted here for the sake of brevity.) The client is structured very much like the client in Example 4-8, except that the actual calls to the remote Account object are constructed as DII calls. For the deposit requests, the method has a single float argument and no return value, so the call to create the Request includes a null NamedValue for the result, and an NVList containing a single NamedValue holding the amount to be deposited. In the case of requests for the Account balance, the getBalance( ) method has no arguments and a single float return value, so the creation of the Request includes a null NVList for the arguments, and a NamedValue containing an Any object intended to hold a floating-point value.

Example 4-9. Account Client DII.java

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

public class AccountClientDII {
  public static void main(String args[]) {
    ORB myORB = ORB.init(args, null);
    try {
      // The object name passed in on the command line
      String name = args[0];
      org.omg.CORBA.Object acctRef = null;
      if (name.startsWith("corbaname") || name.startsWith("corbaloc") ||
          name.startsWith("IOR")) {
        System.out.println("Attempting to lookup " + args[0]);
        acctRef = myORB.string_to_object(args[0]);
      }
      else {
        System.out.println("Invalid object URL provided: " + args[0]);
        System.exit(1);
      }

      // Make a dynamic call to the doThis method
      if (acctRef != null) {
        // We managed to get a reference to the named account, now check the
        // requested transaction from the command-line
        String action = args[1];
        float amt = 0.0f;
        if (action.equals("deposit")) {
          amt = Float.parseFloat(args[2]);
        }
        System.out.println("Got account, performing transaction...");
        try {
          // Did user ask to do a deposit?
          if (action.equals("deposit")) {
            // The following DII code is equivalent to this:
            //   acct.deposit(amt);

            // First build the argument list.  In this case, there's a single
            // float argument to the method.
            NVList argList = myORB.create_list(1);
            Any arg1 = myORB.create_any(  );
            // Set the Any to hold a float value, and set the value to the
            // amount to be deposited.
            arg1.insert_float(amt);
            NamedValue nvArg = 
              argList.add_value("amt", arg1, org.omg.CORBA.ARG_IN.value);
            // Java IDL doesn't implement the get_default_context(  ) operation
            // on the ORB, so we just set the Context to null 
            Context ctx = null;
            // Create the request to call the deposit(  ) method
            Request depositReq = 
              acctRef._create_request(ctx, "deposit", argList, null);

            // Invoke the method...
            depositReq.invoke(  );
            System.out.println("Deposited " + amt + " to account.");
          }
          else {
            // The following DII code is equivalent to this:
            //   acct.balance(  );

            // No argument list is needed here, since the getBalance(  ) method
            // has no arguments.  But we do need a result value to hold the
            // returned balance
            Any result = myORB.create_any(  );
            // Set the Any to hold a float value
            result.insert_float(0.0f);
            NamedValue resultVal =
              myORB.create_named_value("result", result, 
                                        org.omg.CORBA.ARG_OUT.value);
            // Java IDL doesn't implement the get_default_context(  ) operation
            // on the ORB, so we just set the Context to null 
            Context ctx = null;
            // Create the request to call getBalance(  )
            Request balanceReq = 
              acctRef._create_request(ctx, "getBalance", null, resultVal);
 
           // Invoke the method...
            balanceReq.invoke(  );
            System.out.println("Current account balance: " +
                               result.extract_float(  ));
          }
        }
        catch (Exception e) {
          System.out.println("Error occurred while performing transaction:");
          e.printStackTrace(  );
        }
      }
      else {
        System.out.println("Null account returned.");
        System.exit(1);
      }
    }
    catch (Exception e) {
      e.printStackTrace(  );
    }
  }
}

Again, note that in most situations you will actually 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 and call its methods directly. 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.

Get Java Enterprise in a Nutshell, Second Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.