SampleApp: Developing an asynchronous IBM Spectrum Symphony Java client

In this tutorial, you will learn how to convert a synchronous client into an asynchronous one.

About this task

In this tutorial, you will complete these 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:

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

    1. Build the sample client and service on Windows:
      1. Compile with the .bat file by changing to the %SOAM_HOME%\version\samples\Java\SampleApp directory under IBM® Spectrum Symphony Developer Edition and running the .bat file:
        build.bat
      2. Compile with the Ant build file.
        Note: IBM Spectrum Symphony supports Ant 1.6.0 or higher for building Java™ samples in the IBM Spectrum Symphony Developer Edition package.
        Change to the %SOAM_HOME%\version\samples\Java\SampleApp directory and run the command:
        ant
        
      3. Compile in Eclipse.

        To compile in Eclipse, see Using Eclipse as your development environment.

    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.
      2. Set the environment:
        • (csh) source cshrc.soam
        • (bash) . profile.soam
      3. Compile with the makefile or with the Ant build file:
        • To compile with the Makefile, change to the $SOAM_HOME/version/samples/Java/SampleApp directory and run the make command:
          make
        • To compile with the Ant build file, change to the $SOAM_HOME/version/samples/Java/SampleApp directory and run the build command:
          ant
          Note: IBM Spectrum Symphony supports Ant 1.6.0 or higher for building Java samples in the IBM Spectrum Symphony Developer Edition package.
  2. Package the sample service.

    You must package the files required by your service to create a service package. When you built the sample, the service package was automatically created for you.

    Your service package SampleServiceJavaPackage.jar is in the %SOAM_HOME%\7.3.2\samples\Java\SampleApp directory.

  3. Add the application.

    When you add an application through the cluster management console, you must use the Add Application wizard. This wizard creates 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 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 your application profile XML file, then click Continue
      For SampleApp, you can find your profile in the following location:
      • Windows: %SOAM_HOME%\version\samples\Java\SampleApp\SampleAppJava.xml
      • Linux: $SOAM_HOME/version/samples/Java/SampleApp/SampleAppJava.xml

      The Service Package location window displays.

    5. Browse to the created service package and select it, then, select Continue.
      • Windows: %SOAM_HOME%\version\samples\Java\SampleApp\SampleServiceJavaPackage.jar
      • Linux: $SOAM_HOME/version/samples/Java/SampleApp/SampleServiceJavaPackage.zip

      The Confirmation window displays.

    6. Review your selections, then click Confirm.

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

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

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

    1. Run the sample client and service on Windows, run the client application from the command line:
      %SOAM_HOME%\version\samples\Java\SampleaApp\RunAsyncClient.bat
    2. Run the sample client and service on Linux by running the client application:
      $SOAM_HOME/version/samples/Java/SampleApp/RunAsyncClient.sh

    You should see output 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.

    Review the sample client application code to learn how you can understand the differences between a synchronous client and an asynchronous client.

    1. Locate the code samples:
      Table 1. Code samples
      Operating system Files Location of code sample
      Windows Client %SOAM_HOME%\version\samples\Java\SampleApp\src\com\platform\symphony\samples\SampleApp\client\AsyncClient.java
      Input and output objects %SOAM_HOME%\version\samples\Java\SampleApp\src\com\platform\symphony\samples\SampleApp\common\MyInput.java

      %SOAM_HOME%\version\samples\Java\SampleApp\src\com\platform\symphony\samples\SampleApp\common\MyOutput.java

      Service code %SOAM_HOME%\version\samples\Java\SampleApp\src\com\platform\symphony\samples\SampleApp\service\MyService.java
      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\Java\SampleApp\SampleAppJava.xml

        Output directory %SOAM_HOME%\version\samples\Java\SampleApp\
      Linux Client $SOAM_HOME/version/samples/Java/SampleApp/src/com/platform/symphony/samples/SampleApp/client/AsyncClient.java
      Input and output objects $SOAM_HOME/version/samples/Java/SampleApp/src/com/platform/symphony/samples/SampleApp/common/MyInput.java

      $SOAM_HOME/version/samples/Java/SampleApp/src/com/platform/symphony/samples/SampleApp/common/MyOutput.java

      Service code $SOAM_HOME/version/samples/Java/SampleApp/src/com/platform/symphony/samples/SampleApp/service/MyService.java
      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/Java/SampleApp/SampleAppJava.xml

        Output directory $SOAM_HOME/version/samples/Java/SampleApp/
    2. Understand what the sample does

      The client application sample sends 10 input messages through IBM Spectrum Symphony to the service with the data Hello Grid !!.

      The service takes the input data sent by the client and returns it with the additional data Hello Client !!.

      Results are returned asynchronously with a callback interface provided by the client to the API. Methods in this interface are called from threads within the API when certain events occur. In the sample, the events are:
      • When there is an error at the session level.
      • When results return from IBM Spectrum Symphony.
    3. Understand considerations for asynchronous clients.
      The purpose of an asynchronous client is to get the output as soon as it is available. The client thread does not need to be blocked once the input data is sent and can perform other actions.
      Synchronization
      Because results can come back at any time, it is probable that your callback code needs synchronization between the callback thread and the controlling thread. The controlling thread needs to know when work is complete.
      Order of results
      Results are not sent back in order. If order of results is important, the client application must sort the results.
    4. Understand code differences between synchronous and asynchronous clients.
      An asynchronous client is very similar to a synchronous client. The only differences are as follows:
      • You need to specify a callback when creating a session
      • You specify a different flag to indicate asynchronous when you create a session
      • Handling of replies
      The following figure highlights in bold the differences between synchronous and asynchronous clients. Everything else is the same as the synchronous client.
      Differences between synchronous and asynchronous clients.
    5. Implement input and output objects and initialize the client.

      As in the synchronous client tutorial, implement your own input and output objects and initialize the client.

      For more details, look at the synchronous client tutorial, specifically:
      • Implement input and output objects
      • Initialize the client
    6. Declare and implement your callback object.

      Perform this step after implementing your own input and output objects.

      In MySessionCallback.java, we create our own callback class that extends the SessionCallback class, and we implemented onResponse() to retrieve the output for each input message that we send.
      Notes:
      1. We handle when an exception occurs on the callback method for the session. If you do not handle the exception, you do not have any exceptions if an error occurs on the callback.
      2. onResponse() is called every time a task completes and output is returned to the client. The task output handle allows the client code to manipulate the output.
      3. isSuccessful() checks whether there is output to retrieve.
      4. If there is output to retrieve, getTaskOutput() gets the output. Once results return, we print them to standard output and return.
      public class MySessionCallback extends SessionCallback
      {
          //=========================================================================
          //  Constructor
          //=========================================================================
      
          public MySessionCallback(int tasksToReceive) 
          {
              m_tasksReceived = 0;
              m_exception = false;
              m_tasksToReceive = tasksToReceive;
      }
      
       //=========================================================================
          //  SessionCallback Interface Methods
          //=========================================================================
          
      /**
           * Invoked when an exception occurs within the scope of the given session.
           * Must be implemented by the application developer. 
           */
          public void onException(SoamException exception) throws SoamException
          {
              System.out.println("An exception occured on the callback :");
              System.out.println(exception.getMessage());
              setException(true);
          }
      
      /**
           * Invoked when a task response is ready.
           * Must be implemented by the application developer. 
           */
          public void onResponse(TaskOutputHandle output) throws SoamException
          {
              try
              {
                  // check for success of task
                  if (output.isSuccessful())
                  {
                      // get the message returned from the service
                      MyOutput myOutput = (MyOutput)output.getTaskOutput();
      
                      // display content of reply
                      System.out.println("\nTask Succeeded [" +  output.getId() + "]");
                      System.out.println("Your Internal ID was : " + myOutput.getId());
                      System.out.println("Estimated runtime was recorded as : " + myOutput.getRunTime());
                      System.out.println(myOutput.getString());
                  }
                  else
                  {
                      // get the exception associated with this task
                      SoamException ex = output.getException();
                      System.out.println("Task Failed :");
                      System.out.println(ex.getMessage());
                  }
              }
              catch (Exception exception)
              {
                  System.out.println("Exception occured in onResponse() : ");
                  System.out.println(exception.getMessage());
              }
              
      // Update counter used to synchronize the controlling thread 
              // with this callback object
              incrementTaskCount();
      }
      
    7. Create a session to group tasks.

      In AsyncClient.java, perform this step after you have connected to the application.

      When creating an asynchronous session:
      • Specify the flag PARTIAL_ASYNC. This indicates that results are collected asynchronously.
      • Provide a callback object.
      ...
      // Create session callback
                      int tasksToSend = 10;
                      MySessionCallback myCallback = new MySessionCallback(tasksToSend);
                      Session session = null;
      
                      // Set up session attributes
                      SessionCreationAttributes attributes = new SessionCreationAttributes();
                      attributes.setSessionName("mySession");
                      attributes.setSessionType("ShortRunningTasks");
                      attributes.setSessionFlags(Session.PARTIAL_ASYNC);
                      attributes.setSessionCallback(myCallback);
      
                      // Create an asynchronous session
                      try
                      {
                          session = connection.createSession(attributes);
      
                          // Retrieve and print session ID
                          System.out.println("Session ID:" + session.getId());
      ...
      
    8. Synchronize the controlling and callback threads.

      Perform this step after sending the input data to be processed.

      Since our client is asynchronous, we need to synchronize the controlling thread and the callback thread. In this example, the controlling thread blocks until all replies have come back.

      The callback signals when all results are received:
      ...
      synchronized(myCallback)
                          {
                              while (!myCallback.isDone())
                              {
                                  myCallback.wait();
                              }
                          } 
      ...