Netscape Internet Service Broker for Java: Programmer's Guide, Version 1.0

[Contents] [Previous] [Next]

Chapter 5
The Dynamic Invocation Interface

This chapter describes how clients can dynamically create requests for services at run time. It includes the following major sections:

Overview

The Dynamic Invocation Interface (DII) enables clients to invoke operations on any registered service without having to first compile the client stubs that were created for that service by the IDL compiler. By using DII, a client can dynamically build operation requests for any interface that has been stored in the Interface Repository. Service implementations do not require any special design to be able to receive and handle DII requests.

DII is not as efficient as static operation requests, but it offers some important advantages. Clients are not restricted to using the service that were defined at the time the client was compiled. In addition, clients that use DII do not need to be recompiled to access newly-activated service implementations.

Steps for Dynamic Invocation

These are the steps that a client follows when using DII.

Obtain an object reference to the service you wish to use.

  1. Create a Request object for the service.

  2. Initialize the request parameters and the result to be returned.

  3. Invoke the request and wait for the results.

  4. Retrieve the results.

Using the idl2java Compiler

The idl2java compiler has a flag (-portable) which, when switched on, generates stub code using DII. To understand how to do any type of DII, create an IDL file, generate with -portable, then look at the stub code.

Obtaining an Object Reference

Examples in this chapter obtain object references by using the register and resolve methods provided by ISB for Java's Web Naming Service. See also Operations on Object References.

Creating and Initializing a Request

When a client invokes a method on a service, a Request object is created to represent the method invocation. The Request object is written, or marshalled, to a buffer and sent to the service implementation. When a client uses client stubs, this processing occurs transparently. Clients that use DII must create and send the Request object themselves.

There is no constructor for Request objects. Use the Object._request method or one of the Object._create_request methods to create a Request object. The following code shows the methods offered by the Object interface. For information about all of the available methods, see the Netscape Internet Service Broker for Java Reference Guide.

The Object methods for creating a Request object.

package org.omg.CORBA;

    public interface Object {
        ...
        public org.omg.CORBA.Request _request(
            java.lang.String operation 
        );

        public org.omg.CORBA.Request _create_request(
            org.omg.CORBA.Context ctx,
            java.lang.String operation,
            org.omg.CORBA.NVList arg_list,
            org.omg.CORBA.NamedValue result
        );

        public org.omg.CORBA.Request _create_request(
            org.omg.CORBA.Context ctx,
            java.lang.String operation,
            org.omg.CORBA.NVList arg_list,
            org.omg.CORBA.NamedValue result,
            org.omg.CORBA.TypeCode[] exceptions,
            java.lang.String[] contexts
        );
        ...
}

The _create_request Methods

You can use the _create_request method to create a Request object, initialize the Context, the operation name, the argument list to be passed and the result. The request parameter points to the Request object that was created for this operation. The second form of this method allows you to specify a list of Context objects for the request; this supports type checking on context names.

The _request Method

The following code example shows the use of the _request method to create a Request object, specifying only the operation name. Once a Request object is created, the arguments, if any, must be set before the request can be sent to the server.

A portion of the Client.java file, showing the creation of a Request object.

// Using Enterprise Server's ORB
// Client.java
import org.omg.CORBA.*;
public class Client {
  public static void main(String[] args) {
    org.omg.CORBA.Object manager, account;
    try {
      orb = org.omg.CORBA.ORB.init();
      // Locate an account manager.
      _manager = Bank.AccountManagerHelper.narrow
                   (netscape.WAI.Naming.resolve("http://myHost/bank"));
      // Or, if using Communicator's ORB, the call would be:
      // netscape.WAI.Naming.resolve("http://myHost/NameService/bank");
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    String name = args.length > 0 ? args[0] : "Jack B. Quick";
    {
      Request openReq = manager._request("open");
      openReq.add_in_arg().insert_string(name);
      openReq.set_return_type(orb.get_primitive_tc(TCKind.tk_objref));
      openReq.invoke();
      account = openReq.result().value().extract_Object();
    }
    {
      Request balanceReq = account._request("balance");
      balanceReq.set_return_type
        (orb.get_primitive_tc(TCKind.tk_float));
      balanceReq.invoke();
      float balance = balanceReq.result().value().extract_float();
      System.out.println
        ("The balance in " + name + "'s account is $" + balance);
    }
  }
}

Setting the Arguments

The arguments for a Request are represented with a NVList object, which stores name-value pairs as NamedValue objects. You can use the Request.arguments method to obtain a reference to the argument list. This reference can then be used to set the names and values of each of the arguments.

Optionally, the arguments for a Request can be set using the various add_ methods. In the previous code example, the add_in_arg method is used to set the argument for the open method on the AccountManager interface.

NVList

NVList provides a list of NamedValue objects that represent the arguments for a method invocation. There is no constructor. Use the ORB.create_list method or the ORB.create_operation method to create an NVList object.

NVList provides methods for adding, removing, and querying the objects in the list. A complete description of NVList can be found in the Netscape Internet Service Broker for Java Reference Guide.

The NVList interface.

package org.omg.CORBA;
public interface NVList {
  public int count();
  public void add(int flags);
  public void add_item(java.lang.String name, int flags);
  public void add_value(java.lang.String name,
                        org.omg.CORBA.Any value,
                        int flags);
  public org.omg.CORBA.NamedValue item(int index);
  public void remove(int index);
}

NamedValue

NamedValue holds a name-value pair that can be used to represent both input and output arguments for a method invocation request. It is also used to represent the result of a request that is returned to the client application. There is no constructor for NamedValue. Use the ORB.create_named_value method to create a NamedValue object.

The name property is a character string and the value property is represented by an Any class. A complete description of NamedValue can be found in the Netscape Internet Service Broker for Java Reference Guide.

The NamedValue interface.

package org.omg.CORBA;

public interface NamedValue {
    public java.lang.String name();
    public org.omg.CORBA.Any value();
    public int flags();
}

Table 5.1 The NamedValue methods.
Method Description
name

Returns a reference to the name of the item that you can then use to initialize the name.

value

Returns a reference to an Any object representing the item's value that you can then use to initialize the value. For more information, see The Any Class.

flags

Indicates if this item is an input argument, an output argument or both an input and output argument. If the item is both an input and output argument, you can specify a flag indicating that the ORB should make a copy of the argument and leave the caller's memory intact. Flags are:
ARG_IN
ARG_OUT

ARG_INOUT

The Any Class

The Any class holds an IDL type so that it can be passed in a type-safe manner. Objects of this class have a reference to a TypeCode that defines the contained object's type and a reference to the contained object. There is no constructor for this class. The ORB.create_any method creates an Any object.

Methods are provided to create, read, write, and test the equality of Any objects as well as initialize and query the object's value and type. A complete description can be found in the Netscape Internet Service Broker for Java Reference Guide.

The Any class.

package org.omg.CORBA;

abstract public class Any {
    public static Any create();
    abstract public TypeCode type();
    abstract public void type(TypeCode type);
    abstract public void read_value(InputStream input, TypeCode type);
    abstract public void write_value(OutputStream output);
    abstract public boolean equal(Any rhs);
    ...
}

The TypeCode Class

This class is used by the Interface Repository and the IDL compiler to represent the type of arguments or attributes. TypeCode objects are also used in a Request to specify an argument's type, in conjunction with the Any class. There is no constructor for this class. Use the ORB.get_primitive_tc method or one of the ORB.create_*_tc methods to create a TypeCode object.

TypeCode objects have a kind property, represented by one of the values defined by the TCKind class. Complete descriptions of these classes can be found in the Netscape Internet Service Broker for Java Reference Guide.

The TypeCode Class.

abstract public class TypeCode {

  abstract public boolean equal(org.omg.CORBA.TypeCode tc);
  abstract public org.omg.CORBA.TCKind kind();
  abstract public java.lang.String id()
             throws org.omg.CORBA.TypeCodePackage.BadKind;
  abstract public java.lang.String name()
             throws org.omg.CORBA.TypeCodePackage.BadKind;
  abstract public int member_count()
             throws org.omg.CORBA.TypeCodePackage.BadKind;
  abstract public java.lang.String member_name(int index)
             throws org.omg.CORBA.TypeCodePackage.BadKind,
                    org.omg.CORBA.TypeCodePackage.Bounds;
  abstract public org.omg.CORBA.TypeCode member_type(int index)
             throws org.omg.CORBA.TypeCodePackage.BadKind,
                    org.omg.CORBA.TypeCodePackage.Bounds;
  abstract public org.omg.CORBA.Any member_label(int index)
             throws org.omg.CORBA.TypeCodePackage.BadKind,
                    org.omg.CORBA.TypeCodePackage.Bounds;
  abstract public org.omg.CORBA.TypeCode discriminator_type()
             throws org.omg.CORBA.TypeCodePackage.BadKind;
  abstract public int default_index()
             throws org.omg.CORBA.TypeCodePackage.BadKind;
  abstract public int length()
             throws org.omg.CORBA.TypeCodePackage.BadKind;
  abstract public org.omg.CORBA.TypeCode content_type()
             throws org.omg.CORBA.TypeCodePackage.BadKind;
}

Sending a DII Request

The Request interface provides several methods for sending a request, once it has been properly initialized. The simplest of these is the invoke method, which sends the request and waits for a response before returning to your client application.

Receiving the Result

The result method returns a reference to a NamedValue object that represents the return value.

A portion of the Client.java file, showing how a request is sent to the object implementation.

...
{
   Request openReq = manager._request("open");
   openReq.add_in_arg().insert_string(name);
   openReq.set_return_type(orb.get_primitive_tc(TCKind.tk_objref));
   openReq.invoke();
   account = openReq.result().value().extract_Object();
}
{
   Request balanceReq = account._request("balance");
   balanceReq.set_return_type(orb.get_primitive_tc(TCKind.tk_float));
   balanceReq.invoke();
   float balance = balanceReq.result().value().extract_float();
   System.out.println
        ("The balance in " + name + "'s account is $" + balance);
}
...

The send_deferred Method

A non-blocking method, send_deferred, is also provided for sending operation requests. It allows your client to send the request and then use the poll_response method to determine when the response is available. The get_response method blocks until a response is received. The following code example shows how these methods are used.

A portion of the account_clnt2.java file showing the use of the send_deferred and poll_response methods.

   ...
   // Send the request
   try {
       req.send_deferred();
       System.out.println("Send deferred call is made...");
   } catch(org.omg.CORBA.SystemException e) {
       System.out.println("Error while sending request");
       System.err.println(e);
   }

   // Poll for response
   try {
       while (!req.poll_response())
       {
           try{
               System.out.println("Waiting for response");
               Thread.sleep(1000);
           } catch (Exception e){
               System.err.println(e);
           }
       }
   } catch (org.omg.CORBA.SystemException e) {
       System.out.println("Failure while polling for response");
       System.err.println(e);
   }

   try {
       req.get_response();
       // Get the return value;
       balance = req.result().value().extract_float();
   } catch(org.omg.CORBA.SystemException e) {
       System.out.println("Error while receiving response");
       System.err.println(e);
   }
   ...

The send_oneway Method

The send_oneway method can be used to send an asynchronous request. Oneway requests do not involve a response being sent from the object implementation.

Sending Multiple Requests

If you create a sequence of DII Request objects, the entire sequence can be sent using the ORB methods send_multiple_requests_oneway or send_multiple_requests_deferred. If the sequence of requests is sent as oneway requests, no response is expected from the server to any of the requests.

Receiving Multiple Requests

When a sequence of requests is sent using send_multiple_requests_deferred, the poll_next_response and get_next_response methods are used to receive the response the server sends for each request.

The ORB method poll_next_response can be used to determine if a response has been received from the server. This method returns 1 if there is at least one response available. This method returns zero if there are no responses available.

The ORB method get_next_response can be used to receive a response. If no response is available, this method will block until a response is received. If you do not wish your client application to block, use the poll_next_response method to first determine when a response is available and then use the get_next_response method to receive the result.

ORB methods for sending multiple requests and receiving the results.

package org.omg.CORBA;

    abstract public class ORB {
        abstract public org.omg.CORBA.Environment create_environment();
        abstract public void send_multiple_requests_oneway
            (org.omg.CORBA.Request[] reqs);
        abstract public void send_multiple_requests_deferred
            (org.omg.CORBA.Request[] reqs);
        abstract public boolean poll_next_response();
        abstract public org.omg.CORBA.Request get_next_response();
        ...
}


[Contents] [Previous] [Next]

Last Updated: 02/04/98 13:46:55


Copyright © 1997 Netscape Communications Corporation

Any sample code included above is provided for your use on an "AS IS" basis, under the Netscape License Agreement - Terms of Use