Previous Contents Next

Chapter 12   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. A toy example use of the DSI can be found in the omniORB distribution in the src/examples/dsi directory. For further information refer to the Dynamic Skeleton Interface and C++ Mapping sections of the CORBA 2.3 specification.

The DSI interface has changed in CORBA 2.3. omniORB 3 uses the new mapping, but since the mapping depends on PortableServer::Current, which is not yet implemented, not all facilities are available. This chapter describes an approach to building DSI servers which works with omniORB 3.

12.1   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 a servant 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 PortableServer::DynamicImplementation and override the method invoke(). An instance of this class is registered with a POA 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 CORBA::ServerRequest object which provides:

12.2   DSI Types

12.2.1   PortableServer::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 PortableServer {
  ...

  class DynamicImplementation : public virtual ServantBase {
  public:
    virtual ~DynamicImplementation();

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

    virtual void invoke(CORBA::ServerRequest_ptr request) = 0;
    virtual char* _primary_interface(const ObjectId& oid, POA_ptr poa) = 0;

    virtual CORBA::Boolean _is_a(const char* logical_type_id);
    // The default implementation uses _primary_interface(),
    // but may be overridden by subclasses.
  };
  ...
};

12.2.2   ServerRequest

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

namespace CORBA {
  ...

  class ServerRequest {
  public:
    virtual const char* operation() = 0;
    virtual void        arguments(NVList_ptr& parameters) = 0;
    virtual Context_ptr ctx() = 0;
    virtual void        set_result(const Any& value) = 0;
    virtual void        set_exception(const Any& value) = 0;

  protected:
    inline ServerRequest() {}
    virtual ~ServerRequest();
  };
  ...
};

12.3   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:

12.3.1   Operations on the ServerRequest

operation() 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 set_exception(). This will allow the ORB to then see if it is one of the standard object operations.

Firstly arguments() must be called passing a CORBA::NVList1 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 arguments() to retrieve it.

set_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 set_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() may be called to obtain the object reference. This method may not be used at any other time.

12.4   Registering Dynamic Objects

To use a DynamicImplementation servant, a CORBA object must be created and associated with it, just as for any other servant. Dynamic servants can also be created on demand by Servant Managers, just like static servants.

12.5   Example

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

string echoString(in string mesg);
Here is the Dynamic Implementation Routine:

void
MyDynImpl::invoke(CORBA::ServerRequest_ptr request)
{
  try {
    if( strcmp(request->operation(), "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->arguments(args);

    const char* mesg;
    *(args->item(0)->value()) >>= mesg;

    CORBA::Any* result = new CORBA::Any();
    *result <<= CORBA::Any::from_string(mesg, 0);
    request->set_result(*result);
  }
  catch(CORBA::SystemException& ex){
    CORBA::Any a;
    a <<= ex;
    request->set_exception(a);
  }
  catch(...){
    cout << "echo_dsiimpl: MyDynImpl::invoke - caught an unknown exception."
  << endl;
    CORBA::Any a;
    a <<= CORBA::UNKNOWN(0, CORBA::COMPLETED_NO);
    request->set_exception(a);
  }
}

1
obtained by calling CORBA::ORB::create_list()

Previous Contents Next