# Developing Servers

This section introduces Java IDL support for servers of transient CORBA objects. The Hello World example includes a transient object server.

Topics in this section include:

- Transient and Persistent Objects
- Servants and Servant Base Classes
- Using Servant Objects
- Dynamic Skeleton Interface
- Delegation-based Skeletons (Ties)

## Transient and Persistent Objects

A transient CORBA object has the same lifetime as the execution of the server process that creates it. When a server terminates, its transient objects disappear with it and any object references held by the client become invalid. Transient objects are often used to effect asynchronous, or callback communication between applications and objects. For example, suppose a timing service notifies a client application when an interval expires; it could do so as follows:

- The timing service defines an interface for a notifier object that includes an `interval_expired()` operation.

- The timing service requires that a client pass a notifier object to the timing service's `set_interval()` operation.

- The timing service client application implements a transient object that implements the notifier interface.

- The client application creates and passes a notifier object to the timing service.

- When the interval expires, the timing service invokes the notifier object's `interval_expired()` operation.

The arrangement, in other words, is much like a callback in procedural programming.

By contrast, a persistent object lives until it is explicitly destroyed. If a client has a reference to a persistent CORBA object, that reference can be used even if the object's server is not running -- an ORB daemon will start the server when the ORB receives an invocation on the object.

At present, Java IDL supports only transient object servers. Although persistent object servers can't yet be written using Java IDL, Java applets and applications can be clients of persistent CORBA objects whose servers are written in other languages, such as C++, or in other Java ORB implementations.

## Servants and Servant Base Classes

To implement a server for transient CORBA objects of some type, you write a Java class called a servant, which inherits from a class called the servant base; servant base classes are optionally generated by the `idlj` compiler. An instance of a transient CORBA object is implemented by an instance of its servant class.

The servant base class is the CORBA type-specific interface between the ORB and the servant code (skeleton) for the type. It unmarshals incoming parameters, invokes servant methods, marshals results, and directs the ORB to return results to the client ORB.

A servant class extends its servant base with a method for each operation in the IDL interface definition it implements. (OMG IDL attributes require one method if they are read only, two if they are writable.) For example, consider the following OMG IDL:

    module Notifiers {
       interface SimpleNotifier {
          void alert (in long alert_id);
       };
    };

A servant for this type might look as follows:

    import Notifiers.*

    class SimpleNotifierServant extends _SimpleNotifierImplBase {

       void alert (int alert_id) {
          // do something about the alert ...
          return;
       }
    }

The server class could create an instance of `SimpleNotifierServant` as follows:

      SimpleNotifierServant SimpleNotifier = new SimpleNotifierServant();
      orb.connect(SimpleNotifier);

The `orb.connect()` call registers the object and the servant with the ORB so that the ORB will invoke the servant when the CORBA object is invoked. When the server terminates, the ORB destroys its records for that server's CORBA objects so that subsequent invocations will result in an `OBJECT_NOT_EXIST` exception. A server can alternatively annul its CORBA objects before terminating by calling `orb.disconnect()`.

## Using Servant Objects

A transient CORBA object is implemented by a Java servant object. A servant object can be passed as a parameter to any method that needs a CORBA object reference of that type. For example, suppose a Java program wants to learn when the price of Sun Microsystems stock rises above 150. The program has obtained a reference to a CORBA stock-watcher object that provides the following operation (shown in IDL and Java):

    // IDL
    interface StockWatcher {
    void set_threshold(
       in string stock_symbol,
       in short stock_price,
       in Notifiers::SimpleNotifier notifier_obj);
    };

    // Java
    void set_threshold(
       String stock_symbol,
       short stock_price,
       Notifiers.SimpleNotifier notifier_obj)
      { // set the threshold ...
      }

To call `set_threshold()`, you need to create a `SimpleNotifier` CORBA object. Assuming you've imported a servant class called `SimpleNotifierImpl`, here's how to do it:

    SimpleNotifier SUNWnotifier = new SimpleNotifierImpl();
    int stockPrice = 150;
    orb.connect(SUNWnotifier);
    StockWatcher aStockWatcher = // code to get a stock-watcher reference;

    aStockWatcher.set_threshold ("SUNW", stockPrice, SUNWnotifier);

### Dynamic Skeleton Interface

DSI allows servers to serve a servant object without prior (compile time) knowledge of the object's interface. Instead of using skeleton code compiled from the IDL interface definition, the server constructs an operation invocation dynamically.

#### Why Use DSI?

Use DSI for servers that cannot have compile-time knowledge of the implementation interface. For example, you might need a bridging application to allow CORBA clients to invoke services residing in a COM environment while allowing COM clients the same access to services residing in the CORBA realm. Each environment has its own, very different way of building requests and responses.

This bridging application would use DSI to convert a CORBA client request to a format understood by a COM server. And it would use DII to convert a COM client request to a format understood by a CORBA server. The application programmer writes all the code to perform this work.

Contrast this with a typical static object invocation. The server has access to the compiled skeletons for the interfaces being invoked upon. These skeletons are generated by compiling the IDL interface definitions with the `idlj` compiler. When the ORB receives a request, it uses the skeleton code to build the operation arguments on the server side and to send back any result.

#### Steps to Using DSI

To use DSI, implement and register a dynamic servant by doing the following:

1. Declare your class to extend `org.omg.CORBA.DynamicImplementation`.

2. Implement the `invoke()` method.
   Write the `invoke()` method code to work with a `ServerRequest` object to:
   1. Extract the operation name via a call on `op_name()`.
   2. Build an `NVList` of the operation parameters (this requires type information on the parameters, possibly from an interface repository).
   3. Extract the parameter values via a call on `params()`, passing the `NVList`.
   4. Perform the operation, assigning new values to out and inout parameters in the `NVList` as appropriate.
   5. Call either `result()` or `except()`, as appropriate.
   Note: The calls to `params()` and then to `result()` or `except()` must be made in the proper order. You must call `params()` before calling either of the other two methods, and you must call only one of `result()` or `except()` once only. Failure to observe any of these limitations results in a `BAD_INV_ORDER` exception.

3. Implement the `_ids()` method.
   This method is inherited from `org.omg.CORBA.portable.ObjectImpl`, the superclass of `DynamicImplementation`. It returns the repository IDs of the interfaces implemented by this dynamic server.

4. Create an instance of the DSI object and register it with the ORB via a call to `org.omg.CORBA.ORB.connect()`.

#### DSI Example

Here is DSI.idl, which defines a very simple interface to be implemented dynamically.

    //IDL
    module JavaIDL {
      interface DSIExample {
        void print_args(in string arg1, in short arg2);
      };
    };

Here is the corresponding Java code, from the file DSIServer.java. This portion shows the implementation of `invoke()` and the dynamic handling of the `print_args()` operation defined in DSI.idl.

    //Java
    import java.util.*;
    import org.omg.CORBA.*;

    // Dynamic servant class implementation
    class DSIExampleServantImpl extends DynamicImplementation {

      // Store the repository ID for the interface implemented
      static String[] myIds = {"IDL:JavaIDL/DSIExample:1.0"};

      // Create a reference to the ORB
      ORB orb;
      DSIExampleServantImpl(ORB orb) {
        this.orb = orb;
      }

      // Implementation of invoke() for handling dynamic requests
      public void invoke(ServerRequest request) {
        try {
          System.out.println("DSI: invoke called, op = "+ request.op_name());

          // Create an NVList to hold the parameters
          NVList nvlist = orb.create_list(0);

          // Check if the request is for the operation
          // "print_args"
          if (request.op_name().equals("print_args") == true) {

            // Add first argument to NVList
            Any any1 = orb.create_any();
            any1.insert_string("");
            nvlist.add_value("arg1", any1, ARG_IN.value);

            // Add second argument to NVList
            Any any2 = orb.create_any();
            any2.insert_short((short)0);
            nvlist.add_value("arg2", any2, ARG_IN.value);

            //Pass the NVList to the request, to get values
            request.params(nvlist);

            // Extract values and print arguments
            System.err.println("Argument 1: In value: "
    			    + nvlist.item(0).value().extract_string());
            System.err.println("Argument 2: In value: "
    			    + nvlist.item(1).value().extract_short());
            TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_void);
            Any result_any = orb.create_any();
            result_any.type(result_tc);

    	// Set the void result
            request.result(result_any);
          }
        }
        catch ( Exception ex ) {
          ex.printStackTrace();
          System.out.println("DSIExample: Exception thrown: " + ex);
        }
      }

      // Implement the _ids() method to return repository ID of interface
      public String[] _ids() {
        return myIds;
      }

    }
    // File DSIServer.java continues

Here is the remainder of DSIServer.java, showing a standard server implementation. Note that you register a dynamic servant with the ORB by using the same operation you would for a static servant.

    // Java

    // DSIServer implementation
    public class DSIServer {

      // Main
      public static void main(String[] args) {
        try {
          // Access and initialize the ORB
          org.omg.CORBA.ORB orb = ORB.init(args, null);

          // Create an instance of the dynamic implementation
          DSIExampleServantImpl servant = new DSIExampleServantImpl(orb);

          // Register the dynamic servant with the ORB
          orb.connect(servant);

          // Write IOR into file.
          // Alternatively, the naming service could be used.
          OutputStream f = new FileOutputStream(
                System.getProperty("user.home") +
    	    System.getProperty("file.separator") + "DSI.ior") ;
          DataOutputStream out = new DataOutputStream(f) ;
          String ior = orb.object_to_string(servant) ;
          out.writeBytes(ior) ;
          out.close();

          System.out.println("IOR is " + ior) ;

          // Wait for requests from client
          java.lang.Object sync = new java.lang.Object();
          synchronized(sync){
            sync.wait();
          }

        }
        catch (Exception ex) {
          ex.printStackTrace();
          System.err.println("DSIServer: Exception thrown: " + ex);
        }
      }
    }

## Delegation-based Skeletons (Ties)

Because Java allows a class to inherit implementation from only a single superclass, it is sometimes awkward to provide CORBA object implementations for objects that rightfully belong in a class hierarchy--the servant base class occupies the single available superclass position. These objects can become CORBA servants most easily by use of delegation-based skeletons.

Delegation-based skeletons move the required CORBA operations from a servant base class (from which your object must inherit) to the generated `Tie` class. The `Tie` class acts as the skeleton for this object, receiving invocations from the ORB and delegating them to the servant that actually does the work.

The `idlj` compiler is installed to the J2SDK's `bin` directory when you installed the Java 2 Platform, Standard Edition, v1.3. These steps are based on this version of the J2SDK.

### Using Ties

To use ties, first compile the IDL interface using the `-ftie` flag. In addition to the usual Java files, this command also produces an `Operations` interface and a `Tie` class. Then write your class, implementing the generated `Operations` interface.

### Ties Example

Consider the following simple IDL interface:

    // IDL
    interface Frog{
      void croak();
    };

Compiling Frog.idl with `idlj` generates the standard client and server files (servant classes, etc.) and the special files for delegation-based skeletons: _FrogTie and _FrogOperations. The standard implementation of this IDL looks like this:

    // FrogImpl.java--without using ties, inherits required
    // CORBA functionality from _FrogImplBase

    public class FrogImpl extends _FrogImplBase {
      public void croak() {
        getAudioClip(getCodeBase(), "frog.au").play();
      }

      public static void main(String[] args) {
        ORB orb = ORB.init();
        Frog frogRef = new FrogImpl();
        orb.connect(frogRef);
        // remainder of code deleted
      }
    }

Note that, because FrogImpl.java inherits its CORBA functionality (such as the dispatch upcall from the ORB) from _FrogImplBase, it must contain the implementation code for the rest of its methods; it cannot inherit them even if they are identical to those in another class.

The same class, using a delegation-based skeleton, would look like this:

    // Amphibian.java--provides general behavior

    public class Amphibian extends Applet {
      public void breathWater(){
        // implementation deleted
      }
    }

    // FrogImpl.java--using ties

    public class FrogImpl extends Amphibian implements _FrogOperations {
      public void croak() {
        // croak method must still be here; it is in the Operations interface
        getAudioClip(getCodeBase(), "frog.au").play();
      }

      public static void main(String[] args) {
        ORB orb = ORB.init();
        FrogImpl servant = new FrogImpl();
        Frog frogRef = new _FrogTie(servant);
        orb.connect(frogRef);
        // remainder of code deleted
      }
    }

Using ties, FrogImpl reserves its superclass slot for inheritance of amphibian behavior while implementing the CORBA operations defined in the IDL interface (and in _FrogOperations).

Note the difference in the `orb.connect()` call. With a delegation-based skeleton, you pass a new tie class instance to the ORB, rather than passing the actual object implementation.

Clients | Servers | Exceptions | Initialization | Naming

Home | Fundamentals | Programming | References | Tutorial

Copyright © 1996, 1997 Sun Microsystems, Inc., 2550 Garcia Ave., Mtn. View, CA. 94043-1100 USA., All rights reserved.