SampleApp: Your first IBM Spectrum Symphony C++ service

This tutorial guides you through the process of building and running a service, then walks you through the sample service code. You learn the minimum amount of code that you need to create a service.

Before you begin

Before you begin, ensure you have installed and started IBM® Spectrum Symphony Developer Edition.

About this task

You will complete the following tasks:
  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

Procedure

  1. Build the sample client and service:
    1. Build the sample client and service on Windows. You can build client application and service samples at the same time.
      1. In %SOAM_HOME%\version\samples\CPP\SampleApp, locate workspace file sampleCPP_vc6.dsw, or one of the Visual Studio solution files.
      2. Load the file into Visual Studio and build it.
    2. Build the sample client and service on Linux®.
      1. Change to the conf directory under the directory in which you installed IBM Spectrum Symphony Developer Edition.

        For example, if you installed IBM Spectrum Symphony Developer Edition in /opt/ibm/platformsymphonyde/de732, go to /opt/ibm/platformsymphonyde/de732/conf.

      2. Source the environment:
        • (csh) source cshrc.soam
        • (bash) . profile.soam
      3. Compile using the Makefile located in $SOAM_HOME/version/samples/CPP/SampleApp:
        make
  2. Package the sample service.

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

    1. Package the sample service on Windows:
      1. Go to the directory in which the compiled samples are located:
        cd %SOAM_HOME%\version\samples\CPP\SampleApp\Output\
      2. Create the service package by compressing the service executable. Here is an example, using gzip:
        gzip SampleServiceCPP.exe
        

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

    2. Package the same service on Linux:
      1. Change to the directory in which the compiled samples are located:
        cd $SOAM_HOME/version/samples/CPP/SampleApp/Output/
      2. Create the service package by compressing the service executable into a tar file:
        tar -cvf SampleServiceCPP.tar SampleServiceCPP
        gzip SampleServiceCPP.tar

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

  3. Add the application.

    When you add an application through the cluster management console, 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 cluster management console, click WorkloadSymphonyApplication Profiles.

      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:

      • Windows: %SOAM_HOME%\version\samples\CPP\SampleApp\SampleApp.xml
      • Linux: $SOAM_HOME/version/samples/CPP/SampleApp/SampleApp.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 cluster management console. Your new application is displayed as enabled.

  4. Run the sample client and service:
    1. 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:
      %SOAM_HOME%\version\samples\CPP\SampleApp\Output\SyncClient.exe

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

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

    2. Run the sample client and service on Linux by running the client application:
      $SOAM_HOME/version/samples/CPP/SampleApp/Output/SyncClient

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

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

  5. Walk through the code. You review the sample service code to learn how you can create a service:
    1. Locate the code samples:
      Table 1. Code samples
      Operating system Files Location of code sample
      Windows Client %SOAM_HOME%\version\samples\CPP\SampleApp\SyncClient
      Message object %SOAM_HOME%\version\samples\CPP\SampleApp\Common
      Service code %SOAM_HOME%\version\samples\CPP\SampleApp\Service
      Application profile The service required to compute the input data along with additional application parameters are defined in the application profile: %SOAM_HOME%\version\samples\CPP\SampleApp\SampleApp.xml
      Output directory %SOAM_HOME%\version\samples\CPP\SampleApp\Output
      Linux Client $SOAM_HOME/version/samples/CPP/SampleApp/SyncClient
      Message object $SOAM_HOME/version/samples/CPP/SampleApp/Common
      Service code $SOAM_HOME/version/samples/CPP/SampleApp/Service
      Application profile The service required to compute the input data along with additional application parameters are defined in the application profile: $SOAM_HOME/version/samples/CPP/SampleApp/SampleApp.xml
      Output directory $SOAM_HOME/version/samples/CPP/SampleApp/Output/
    2. Understand what the sample does: the service takes input data sent by client applications, returns the input data you have sent and replies Hello Client !!.
    3. Input and output: declare and implement the Message object. Your service needs to handle data that it receives as input, and generate output data that can be sent back to the client application.
      Note: Client applications and services share the same message class. You do not need to create a different message class. In our example, we have created a common directory for code that is shared by client and service. Use the Message object declared and implemented by the client application.
      If you have not done so already, take a look at the synchronous client application tutorial for details on the Message object.
      • Input and output: declare the message object.
      • Implement the MyMessage object.
    4. Define a service container:

      For a service to be managed by IBM Spectrum Symphony, it needs to be in a container object. This is the service container.

      Image of sample service, MyServiceContainer, in a container object, ServiceContainer
      In SampleService.cpp, we inherited from the ServiceContainer class:
      #include "stdafx.h"
      #include <stdio.h>
      #include "soam.h"
      #include "MyMessage.h"
      
      using namespace soam;
      using namespace std;
      
      class MyServiceContainer : public ServiceContainer
      
    5. Process the input:
      {
      public:
      
          virtual void onInvoke (TaskContextPtr& taskContext)
          {
              // get the input that was sent from the client
              MyMessage inMsg;
              taskContext->populateTaskInput(inMsg);
      
              // We simply echo the data back to the client
              MyMessage outMsg;
              outMsg.setInt(inMsg.getInt());
      
              std::string str="you sent : ";
              str += inMsg.getString();
              str += "\nwe replied : Hello Client !!\n>>> ";
      
              if (inMsg.getIsSync())
              {
                  str += "Synchronously.\n";
              }
              else
              {
                  str += "Asynchronously.\n";
              }
              outMsg.setString(str.c_str());
      
              // set our output message
              taskContext->setTaskOutput(outMsg);
          }
      };
      

      IBM Spectrum Symphony calls onInvoke() on the service container once per task. Once you inherit from the ServiceContainer class, implement handlers so that the service can function properly. This is where the calculation is performed.

      To gain access to the data set for the client, you must present an instance of the message object to the populateTaskInput() method on the task context.

      The task context contains all information and functionality that is available to the service during an onInvoke() call in relation to the task that is being processed.

      Important: Services are virtualized. As a result, a service should not read from stdin or write to stdout. Services can, however, read from and write to files that are accessible to all compute hosts.

      You present to populateTaskInput() the message object that comes from the client application. During this call, the data sent from the client is used to populate the message object.

    6. Run the container:
      int main(int argc, char* argv[])
      {
          // return value of our service program
          int retVal = 0;
      
          try
          {
              // Create the container and run it
              MyServiceContainer myContainer;
              myContainer.run();
          } 
      

      The service is implemented within an executable. At a minimum, we need to create within our main function an instance of the service container and run it.

      Note that your service is started by parameters.

    7. Catch exceptions in case the container fails to start running:
      catch(SoamException& exp)
      {
          // report exception to stdout
          cout << "exception caught ... " << exp.what() << endl;
          retVal = -1;
      }
      
      // NOTE: Although our service program will return an overall 
      // failure or success code it will always be ignored in the 
      // current revision of the middleware. 
      // The value being returned here is for consistency.
      return retVal;