Applied Informatics Open Service Platform

OSP Remoting Integration User Guide

Contents

Introduction

Applied Informatics Remoting is a framework for implementing distributed objects and web services in C++. It is fully integrated into the Open Service Platform. Different bundles provide the Remoting library, as well as the different transport implementations to OSP applications.

Integrating Remoting-based services into an OSP application is easy. The OSP code generator RemoteGen can be configured to create OSP-specific code. This can be done by either invoking the RemoteGen with the /osp (or --osp) command line option, or by adding a output/osp/enable element with content value true to the code generator configuration file. When configured for OSP code generation, the interface class generated by the code generator will be a subclass of Poco::OSP::Service (instead of Poco::RefCountedObject). This allows it to register interface objects (proxies and remote objects) as OSP services, with the OSP service registry.

The code generator can also be instructed to automatically generate a bundle activator class, by adding a output/osp/bundleActivator element to its configuration. For a server, the generated bundle activator will automatically register skeleton objects for all remote services defined in the configuration file with the ORB. For a client, the bundle activator will register the proxy factories, instead.

OSP Remoting Integration Tutorial

The following tutorial shows how to integrate a Remoting service into an OSP based application. We are going to build two bundles, a server bundle, which will set up the service object, and a client bundle, which will provide the interface object for accessing the service object, and register the interface object with the service registry. Finally, we will write some code that uses the service.

This tuturial assumes a basic understanding of Remoting technology. Reading at least the Remoting Overview and the first part of the Remoting Tutorial is highly recommended before proceeding.

In the following tutorial, we will build a remote service based on the Greeting Service sample from the OSP Tutorial.

The Server Bundle

Before building the server bundle, we first have to create the service class which will implement our service.

The Service Class

We simply take the GreetingService class from the OSP Tutorial, and turn it into a remote service, by annotating the class definition with the appropriate attributes.

//@ remote
//@ namespace="http://www.appinf.com/webservices/RemoteGreetingService/"
class RemoteGreetingService
{
public:
    typedef Poco::AutoPtr<RemoteGreetingService> Ptr;

    RemoteGreetingService(Poco::OSP::BundleContext::Ptr pContext);    
    ~RemoteGreetingService();

    std::string greeting();
        /// Return a greeting in the user's language, if the
        /// language is known, or in English otherwise.

private:
    Poco::OSP::BundleContext::Ptr _pContext;
};

Code Generator Configuration

The implementation of this class is left as an exercise for the reader. Next step is to create the code generator configuration file. The file is shown below:

<AppConfig>
  <RemoteGen>
    <files>
      <include>
        ../../../../Remoting/include/*/*/RemoteObject.h,
        ../../../../Remoting/include/*/*/Proxy.h,
        ../../../../Remoting/include/*/*/Skeleton.h,
        ./include/RemoteGreetingService.h,
      </include>
    </files>
    <output>
      <include>include</include>
      <src>src</src>
      <schema>bundle/wsdl</schema>
      <copyright>Copyright (c) 2009.</copyright>
      <mode>server</mode>
      <osp>
        <enable>true</enable>
        <bundleActivator>RGSSBundleActivator</bundleActivator>
      </osp>
    </output>
    <schema>
      <RemoteGreetingService>
        <serviceLocations>http://localhost:22080/soap/RemoteGreetingService/TheGreetingService</serviceLocations>
      </RemoteGreetingService>
    </schema>
    <compiler>
      <exec>cl</exec>
      <options>
        /I "..\..\..\..\Foundation\include",
        /I "..\..\..\..\Util\include",
        /I "..\..\..\..\OSP\include",
        /I "..\..\..\..\Remoting\include",
        /nologo,
        /C,
        /P,
        /TP
      </options>
    </compiler>
  </RemoteGen>
</AppConfig>

The only addition to an ordinary configuration file is the addition of the output/osp/enable and output/osp/bundleActivator elements, which direct the code generator to generate OSP-specific code.

After running the code generator, we can see that the generated interface class has been derived from Poco::OSP::Service:

class IRemoteGreetingService: public Poco::OSP::Service
{
public:
    typedef Poco::AutoPtr<IRemoteGreetingService> Ptr;

    IRemoteGreetingService();    
    virtual ~IRemoteGreetingService();

    virtual std::string greeting() = 0;
        /// Return a greeting in the user's language, if the
        /// language is known, or in English otherwise.

    bool isA(const std::type_info& otherType) const;    
    static const Poco::Remoting::Identifiable::TypeId& remoting__typeId();
    const std::type_info& type() const;    
};

We notice that the code generator has created the isA() and type() methods required for an OSP service as well.

The Bundle Activator

The code generator has generated a bundle activator class, which will register the skeleton for our service object with the ORB at startup. What is still left to do, though, is creating the service object and registering the service object with the ORB. Since construction of a service object might involve application specific steps, the generated bundle activator cannot simply create the service object. This must be implemented manually, and is done by implementing the startImpl() method of the generated bundle activator. In addition to the implementation file for the bundle activator (RGSSBundleActivator.cpp), the code generator has created an additional file, RGSSBundleActivatorImpl.cpp, which contains the implementation of the startImpl() (and stopImpl()) methods. It is safe to change the content of this file, as the code generator won't overwrite it when invoked again at a later time.

For our sample, the startImpl() method implementation should be this:

void RGSSBundleActivator::startImpl(Poco::OSP::BundleContext::Ptr pContext)
{
    Poco::SharedPtr<RemoteGreetingService> pObj = new RemoteGreetingService(pContext);
    registerRemoteObject(
        new RemoteGreetingServiceRemoteObject("TheRemoteGreetingService", pObj), 
        22080, 
        "soap");
}

The Client Bundle

The client bundle is easy to build. We don't need to write any code ourself, as everything needed will be generated for us by the code generator. All that remains to do is to write a code generator configuration and invoke the code generator.

Code Generator Configuration

The code generator configuration for the client is shown below:

<AppConfig>
  <RemoteGen>
    <files>
      <include>
        ../../../../Remoting/include/*/*/RemoteObject.h,
        ../../../../Remoting/include/*/*/Proxy.h,
        ../../../../Remoting/include/*/*/Skeleton.h,
        ./include/RemoteGreetingService.h,
      </include>
    </files>
    <output>
      <include>include</include>
      <src>src</src>
      <bundle>bundle</bundle>
      <copyright>Copyright (c) 2009.</copyright>
      <mode>client</mode>
      <osp>
        <enable>true</enable>
        <bundleActivator>RGSCBundleActivator</bundleActivator>
      </osp>
    </output>
    <compiler>
      <exec>cl</exec>
      <options>
        /I "..\..\..\..\Foundation\include",
        /I "..\..\..\..\Util\include",
        /I "..\..\..\..\OSP\include",
        /I "..\..\..\..\Remoting\include",
        /nologo,
        /C,
        /P,
        /TP
      </options>
    </compiler>
  </RemoteGen>
</AppConfig>

The configuration is very similar to the server configuration, with some minor differences. First, we have left out generation of the WSDL file. This is not needed on the client side. We have, however added an element to the configuration: the output/bundle element. This specifies the directory where the generated extensions.xml file will be placed.

Remote Objects And The Service Registry

The com.appinf.osp.remoting.service extension point allows for automatic registration of Remoting interface classes (proxies or remote objects) with the OSP service registry. For the client bundle, the code generator creates an extensions.xml file containing a template for the extension point. This file is only generated once, and won't be overwritten by successive invocations of the code generator, so it is safe to edit the file. For our client bundle to automatically register a service for the remote greeting service, the file must be changed as follows:

<extensions>
    <extension point="com.appinf.osp.remoting.service" 
               serviceName="com.appinf.osp.samples.TheRemoteGreetingService" 
               serviceLocation="http://localhost:22080/soap/RemoteGreetingService/TheRemoteGreetingService"/>
</extensions>

Invoking The Remote Service

With both the server and client bundle in place, we can now write code that uses the newly created remote greeting service. This is straightforward:

// Obtain the GreetingService object from the Service Registry.
ServiceRef::Ptr pServiceRef = pContext->registry().findByName("com.appinf.osp.samples.TheRemoteGreetingService");
if (pServiceRef)
{
    // Service is available - let's invoke it
    IRemoteGreetingService::Ptr pService = pServiceRef->castedInstance<IRemoteGreetingService>();
    std::string greeting = pService->greeting();
    std::cout << greeting << std::endl;
}

There is no Remoting-specific code necessary to invoke the service, except that we need the implementation of the interface class to invoke the service. We can either add the generated interface class from the server or client to our project, or we can use the code generator to generate only the interface class for us.

OSP Remoting Integration Reference

Remoting Bundle

The Remoting Bundle contains the Remoting shared library and ensures that the Remoting shared library can be found in the code repository. It also registers an extension point, com.appinf.osp.remoting.service, that allows for automatic registration of remote objects or proxies as OSP services with the Service Registry.

The com.appinf.osp.remoting.service has the following format:

<extension point="com.appinf.osp.remoting.service" 
           serviceName="<OSP service name>" 
           serviceLocation="<protocol>://<host>:<port>/[soap|binary]/<classname>/<objectid>">

The serviceName element specifies the name of the service, as registered with the service registry. The serviceLocation element specifies the Remoting URI of the service object. For each extension point specified in a bundle, the Remoting bundle will obtain an interface object (proxy or remote object) for the respective service object, and register the interface object with the service registry, using the given service name.

Binary Transport Bundle

The Binary Transport Bundle contains the Remoting binary transport implementation. It also contains a BundleActivator that registers the transport with the Remoting framework. To add binary listeners add a listeners.xml resource file to the bundle that contains listener entries:

<listeners>
    <listener port="10001"/>
    <listener port="8080"/>
</listeners>

The client side of the binary transport (i.e. when creating a connection to a binary server) does not require any configuration.

SOAP Transport Bundle

The SOAP Transport Bundle contains the Remoting SOAP transport implementation. It also contains a BundleActivator that registers the transport with the Remoting framework. Similar to the binary bundle, the listeners.xml file defines which listeners are initially started. A listener can have the following attributes:

The following example registers two SOAP listeners, one using the HTTPServer from the WebServer, the other creating a new HTTPListener:

<listeners>
    <listener ref="osp.web" port="22080" useSoap="true" keepAlive="true"/>
    <listener port="9999" useSoap="true" maxQueue="64" maxThreads="32" keepAlive="true" maxKeepAlive="0"/>
</listeners>

The client side of the SOAP package (i.e. when a connection is created to a SOAP service) is configured via the bundle.properties file:

# Enable/disable SOAP encoding
useSoap=true

# Enable/disable persistent HTTP connections
keepAlive=true