Next: hosts_access(5) Up: No Title Previous: The Dynamic Invocation

# The Dynamic Skeleton Interface

The Dynamic Skeleton Interface (or DSI) allows applications to provide implementations of the operations on CORBA objects without static knowledge of the object's interface. It is the server-side equivalent of the Dynamic Invocation Interface.

This chapter presents the Dynamic Skeleton Interface and explains how to use it. An toy example use of the DSI can be found in the omniORB2 distribution in the `<top>/src/examples/dsi` directory. For further information refer to the Dynamic Skeleton Interface and C++ Mapping sections of the CORBA 2 specification [OMG99a].

The DSI interface has changed in CORBA 2.3. The implementation described below conforms to CORBA 2.1 or 2.2.

# Overview

When an ORB receives an invocation request, the information includes the object reference and the name of the operation. Typically this information is used by the ORB to select an instance of an object and call into the implementation of the operation (which knows how to unmarshal the parameters etc.). The Dynamic Skeleton Interface however makes this information directly available to the application - so that it can implement the operation (or pass it on to another server) without static knowledge of the interface. In fact it is not even necessary for the server to always implement the same interface on any particular object!

To provide an implementation for one or more objects an application must sub-class `DynamicImplementation` and override the method `invoke()`. An instance of this class is registered with the BOA and is assigned an object reference (see below). When the ORB receives a request for that object the `invoke()` method is called and will be passed a `ServerRequest` object which provides:

- the operation name
- context strings
- access to the parameters
- a way to set the returned values
- a way to throw user-defined exceptions.

# DSI Types

## DynamicImplementation

This class must be sub-classed by the application to provide an implementation for DSI objects. The method `invoke()` will be called for each operation invocation.

    namespace CORBA {
      ...
      class BOA {
        ...
        class DynamicImplementation {
        public:
          DynamicImplementation();
          virtual ~DynamicImplementation();

          virtual void invoke(ServerRequest_ptr request,
                              Environment& env) throw() = 0;

        protected:
          Object_ptr _this();
          // Must only be called from within invoke(). Caller must release
          // the reference returned.

          BOA_ptr _boa();
          // Must only be called from within invoke(). Caller must NOT
          // release the reference returned.
        };
        ...
      };
      ...
    };

## ServerRequest

A `ServerRequest` object provides the interface between a dynamic implementation and the ORB.

    namespace CORBA {
      ...
      class ServerRequest {
      public:
        virtual const char*      op_name();
        virtual OperationDef_ptr op_def();
        virtual Context_ptr      ctx();
        virtual void             params(NVList_ptr parameters);
        virtual void             result(Any* value);
        virtual void             exception(Any* value);

        static ServerRequest_ptr _duplicate(ServerRequest_ptr);
        static ServerRequest_ptr _nil();
      };
      ...
    };

# Creating Dynamic Implementations

The application must override the `invoke()` method of `DynamicImplementation` to provide an implementation for DSI objects. This method must behave as follows:

- It may be called concurrently by multiple threads of execution, and so must be thread-safe.
- It may not throw any exceptions. User-defined exceptions are passed in a value of type Any and given to `ServerRequest::exception()`. In pre-omniORB 2.8.0 releases, system exceptions may be passed via the `env` parameter. From omniORB 2.8.0 onwards, system exceptions can be inserted into an Any and given to `ServerRequest::exception()` in the same way as user-defined exceptions. Since the methods provided by `ServerRequest` may throw system exceptions, the application must catch any such exception, passed it via `ServerRequest::exception()`.
- The operations on the `ServerRequest` object must be carried out in the correct order, as described below.

## Operations on the ServerRequest

`op_name()` will return the name of the operation, and may be called at any time. For attribute access the operation name is the IDL name of the attribute, prefixed by `_get_` or `_set_`. If the operation name is not recognised a `CORBA::BAD_OPERATION` exception should be passed back through `env`. This will allow the ORB to then see if it is one of the standard object operations.

Firstly `params()` must be called passing a `CORBA::NVList` which must be initialised to contain the type and mode of the parameters. The ORB consumes this value and will release it when the operation is complete. At this point any in/inout arguments will be unmarshalled, and when this operation returns their values will be in the `NVList`. The application may set the value of inout/out arguments by modifying this parameter list.

If the operation has user-context information, then `ctx()` must be called after `params()` to retrieve it.

`result()` must then be called exactly once if the operation has a non-void return value (unless an exception is thrown). The value passed should be an Any allocated with `new`, and will be freed by the ORB.

At any point in the above sequence `exception()` may be called to set a user-defined exception or a system exception. If this happens then no further operations should be invoked on the `ServerRequest` object, and the `invoke()` method should return.

Within the `invoke()` method `_this()` and `_boa()` may be called to obtain the object reference and BOA reference respectively. These methods may not be used at any other time.

# Registering Dynamic Objects

To use a `DynamicImplementation` a CORBA object must be created and associated with the implementation. The way in which this is done is not defined by the CORBA 2.0 specification, so the following method is omniORB2 specific:

    namespace CORBA {
      ...
      class BOA {
        ...
        Object_ptr create_dynamic_object(DynamicImplementation_ptr dir,
                                         const char* intfRepoId);
        ...
      };
      ...
    };

Ownership of the `DynamicImplementation` object is taken over by the ORB, and it will be deleted when associated the object is destroyed. The returned object may then be entered into the object table with a call to `BOA::obj_is_ready()` as usual, and will then start accepting operation invocations.

For some applications it will not be possible to register all DSI objects in advance of invocations arriving. In this case DSI objects can be created on demand in the same way as normal objects - see section 5.6.

# Example

This implementation of `DynamicImplementation::invoke()` is taken from an example which can be found in the omniORB2 distribution. The operation ``echoString'' is declared in IDL as:

    string echoString(in string mesg);

Here is the Dynamic Implementation Routine:

    void
    MyDynImpl::invoke(CORBA::ServerRequest_ptr request, CORBA::Environment& env)
      throw()
    {
      try {
        if( strcmp(request->op_name(), "echoString") )
          throw CORBA::BAD_OPERATION(0, CORBA::COMPLETED_NO);

        CORBA::NVList_ptr args;
        orb->create_list(0, args);
        CORBA::Any a;
        a.replace(CORBA::_tc_string, 0);
        args->add_value("", a, CORBA::ARG_IN);

        request->params(args);

        CORBA::Any& input_any = *(args->item(0)->value());
        CORBA::String_var input;
        input_any >>= input.out();

        CORBA::Any* result = new CORBA::Any();
        *result <<= CORBA::Any::from_string(input._retn(), 0);
        request->result(result);
      }
      catch(CORBA::Exception& ex) {
        CORBA::Any* v = new CORBA::Any;
        ::operator<<=(*v,ex);
        request->exception(v);
      }
      // In pre-omniORB 2.8.0, one has to do this:
      //  catch(CORBA::SystemException& ex){
      //  env.exception(CORBA::Exception::_duplicate(&ex));
      //  }
      catch(...){
        cout << "echo_dsiimpl: MyDynImpl::invoke - caught an"
            " unknown exception." << endl;
        env.exception(new CORBA::UNKNOWN(0, CORBA::COMPLETED_NO));
      }
    }

Next: hosts_access(5) Up: No Title Previous: The Dynamic Invocation