SharingData: Developing a C++ client and service to share data among tasks

Goal

This tutorial walks you through the sample common data object code, then describes how to use different data objects for input, output, and common data. How to develop a client application and service to share data among all tasks in a session. The data is shared by all invocations of tasks within the same session.

At a glance

Before you begin, ensure you have installed and started Platform Symphony Developer Edition. You should also have completed the tutorial Your First Synchronous Symphony C++ Client. When you are ready, do the following:
  1. Build the sample client and service

  2. Package the sample service

  3. Add the application

  4. Run the sample client and service

  5. Walk through the code

When to use common data

Common data is data that can be made available to service instances for the duration of a session.

Use common data when you need to set up the initial state of a service, and you only want to do it once, not on every task. Common data is useful for passing data from a client to a service. The service loads the data when the session is created.

You can use common data, for example, to set the environment in the service that is common to all tasks in a session. This way you only need to set the environment once, when the session is created.

Symphony attempts to use the same service instance for all tasks in a session. A service instance is made available to other sessions only when session workload completes, a session is closed or aborted, or when another session of higher priority is assigned the service instance.

Build the sample client and service

On Windows

You can build client application and service samples at the same time.

Load the workspace file sharing_data_vc6.dsw, or one of the Visual Studio solution files into Visual Studio and build it.

On Linux

You can build client application and service samples at the same time.

  1. Change to the conf directory under the directory in which you installed Symphony DE.

    For example, if you installed Symphony Developer Edition in /opt/symphonyDE/DE51, go to /opt/symphonyDE/DE51/conf.

  2. Source the environment:
    • For csh, enter

      source cshrc.soam
    • For bash, enter

      . profile.soam
  3. Compile using the Makefile located in $SOAM_HOME/5.1/samples/CPP/SharingData:

    make

Package and deploy the sample service

On Windows

To deploy the service, you first need to package it.

  1. Go to the directory in which the compiled samples are located:

    cd %SOAM_HOME%\5.1\samples\CPP\SharingData\Output\

  2. Create the service package by compressing the service executable into a zip file:
    gzip DataService.exe 

    You have now created your service package DataService.exe.gz.

On Linux

To deploy the service, you first need to package it.

  1. Change to the directory in which the compiled samples are located:
    cd $SOAM_HOME/5.1/samples/CPP/SharingData/Output/
  2. Create the service package by compressing the service executable into a tar file:

    tar -cvf DataService.tar DataService

    gzip DataService.tar

    You have now created your service package DataService.tar.gz.

Add the application

When you add an application through the DE PMC, you must use the Add Application wizard. This wizard defines a consumer location to associate with your application, deploys your service package, and registers your application. After completing the steps with the wizard, your application should be ready to use.

  1. In the DE PMC, click Symphony Workload > Configure Applications.

    The Applications page displays.

  2. Select Global Actions > Add/Remove Applications.

    The Add/Remove Application page displays.

  3. Select Add an application, then click Continue.

    The Adding an Application page displays.

  4. Select Use existing profile and add application wizard. Click Browse and navigate to your application profile.
  5. Select your application profile xml file, then click Continue

    For SampleApp, you can find your profile in the following location:

    • C++:

      • Windows—%SOAM_HOME%\5.1\samples\CPP\SharingData\SharingData.xml

      • Linux—$SOAM_HOME/5.1/samples/CPP/SharingData/SharingData.xml

    The Service Package location window displays.

  6. Browse to the service package you created in .gz or tar.gz format and select it, then, click Continue.

    The Confirmation window displays.

  7. Review your selections, then click Confirm.

    The window displays indicating progress. Your application is ready to use.

  8. Click Close.

    The window closes and you are now back in the Platform Management Console. Your new application is displayed as enabled.

Run the sample client and service

On Windows

To run the service, you run the client application. The service a client application uses is specified in the application profile.

Run the client application:
%SOAM_HOME%\5.1\samples\CPP\SharingData\Output\DataClient.exe

You should see output on the command line as workload is submitted to the system.

The client starts and the system starts the corresponding service. The client displays messages indicating that it is running.

On Linux

To run the service, you run the client application. The service a client application uses is specified in the application profile.

Run the client application:

$SOAM_HOME/5.1/samples/CPP/SharingData/Output/DataClient

You should see output on the command line as workload is submitted to the system.

The client starts and the system starts the corresponding service. The client displays messages indicating that it is running.

Walk through the code

Locate the code samples


Operating System

Files

Location of Code Sample

Windows

Client

%SOAM_HOME%\5.1\samples\CPP\SharingData\Client

Input, output and data object declaration and implementation

%SOAM_HOME%\5.1\samples\CPP\SharingData\Common

Service code

%SOAM_HOME%\5.1\samples\CPP\SharingData\Service

Application profile

The service required to compute the input data along with additional application parameters are defined in the application profile:

%SOAM_HOME%\5.1\samples\CPP\SharingData\SharingData.xml

Output directory

%SOAM_HOME%\5.1\samples\CPP\SharingData\Output\

Linux

Client

$SOAM_HOME/5.1/samples/CPP/SharingData/Client

Input, output and data object declaration and implementation

$SOAM_HOME/5.1/samples/CPP/SharingData/Common

Service code

$SOAM_HOME/5.1/samples/CPP/SharingData/Service

Application profile

The service required to compute the input data along with additional application parameters are defined in the application profile:

$SOAM_HOME/5.1/samples/CPP/SharingData/SharingData.xml

Output directory

$SOAM_HOME/5.1/samples/CPP/SharingData/Output/


What the client sample does

In the samples, the output message is different from the input message object.

The client creates a session with common data. It sends 10 input messages, and retrieves the output. The client then outputs Hello Grid!!

What the service sample does

The service takes input data sent by client applications, returns the input data you have sent and replies "Hello Client !!". The service uses onSessionEnter() to define attributes global to the session.

Prepare common data in your client

  1. Declare and implement the Message object.

    In the synchronous client tutorial, input and output message objects were the same object. In this tutorial, different objects represent input and output. In addition, we are creating an additional object to represent common data.

  2. Once your message and data objects are declared, implement handlers for serialization and deserialization.

    In MyDataObjects.cpp, we implement methods to handle the data.

  3. Use the common data object when creating a session:
    1. As in the synchronous client tutorial, initialize the client and connect to the application. Then, create your session to group tasks.
    2. When creating a session, use the common data object to pass data from the client application to the service.

      In Client.cpp, we create a session and pass the common data object.

      ...
      // Set up session creation attributes
              SessionCreationAttributes attributes;
              attributes.setSessionName("mySession");
              attributes.setSessionType("ShortRunningTasks");
              attributes.setSessionFlags(Session::ReceiveSync);
              attributes.setCommonData(&commonData);
              // Create a synchronous session
                          SessionPtr sesPtr = conPtr->createSession(attributes);
      ...
  4. Now proceed the same way as in the synchronous client tutorial:
    • Send input data to be processed

    • Retrieve output

    • Catch exceptions

    • Uninitialize

Access common data in your service

  1. Define a service container and get data from the session:
    1. As in the basic service tutorial, first define a service container.
    2. Retrieve the common data from the session sent by the client by implementing onSessionEnter() before your invoke call.

      onSessionEnter() is called once for the duration of the sessions corresponding pair is onSessionLeave().

      In SampleService.cpp, we inherited from the ServiceContainer class, and implemented onSessionEnter() to get common data and store it for later with the session context.

      ...
      class MyServiceContainer : public ServiceContainer
      {
      public:
          void onSessionEnter (SessionContextPtr& sessionContext)
          {
              // get the current session ID (if needed)
              m_currentSID = const_cast<char*>(sessionContext->getSessionId());
              
              // populate our common data object
              m_commonData = new MyCommonData();
              sessionContext->populateCommonData(*m_commonData);
          }
          void onInvoke (TaskContextPtr& taskContext)
      {
      ....
          void onSessionLeave()
          { 
              // We get a chance to free the common data here
              if (SOAM_NULL_PTR != m_commonData)
              {
                  delete m_commonData;
                  m_commonData =  SOAM_NULL_PTR;
              }
          }
      ...
  2. Process the input.

    In this example, we use the common data in our invoke call by formatting the output string. We then set our output message as usual to send common data back with each of the replies.

    ...
    void onInvoke (TaskContextPtr& taskContext)
        {
     ... 
    // setup a reply to the client
            std::string str="Client sent : ";
            str += inMsg.getString();
            str += "\nSymphony replied : Hello Client !! with common data (\"";
            str += m_commonData->getString();
            str += "\") for session(";
            str += m_currentSID;
            str += ")";
            outMsg.setString(str.c_str());
            // set our output message
            taskContext->setTaskOutput(outMsg);
        }
    ...
  3. Perform any data cleanup: after processing the input, use the onSessionLeave() call to free the data for the session.

    The call onSessionLeave() is called once for every session that is created.

    ...
    void onSessionLeave()
        { 
            // We get a chance to free the common data here
            if (SOAM_NULL_PTR != m_commonData)
            {
                delete m_commonData;
                m_commonData =  SOAM_NULL_PTR;
            }
        }
    ...
  4. As with the basic service, run the container in the service main and catch exceptions.