SampleApp: Developing an asynchronous Symphony Java client

Goal

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

At a glance

  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

Build the sample client and service

On Windows

Compile with the .bat file

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

Change to the %SOAM_HOME%\4.1\samples\Java\SampleApp directory and run the .bat file:
build.bat

Compile with the Ant build file

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

Change to the %SOAM_HOME%\4.1\samples\Java\SampleApp directory and run the command:
ant

Compile in Eclipse

To compile in Eclipse, see "Symphony plug-in for Eclipse" in the Application Development Guide.

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.
  2. Set the environment:
    • For csh, enter

      source cshrc.soam
    • For bash, enter

      . profile.soam
  3. Compile with the Makefile or with the Ant build file.
    • Compile with the Makefile:

      Change to the $SOAM_HOME/4.1/samples/Java/SampleApp directory and run the make command:
      make
    • Compile with the Ant build file:

      Change to the $SOAM_HOME/4.1/samples/Java/SampleApp directory and run the build command:
      ant

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 following directory:
%SOAM_HOME%\4.1\samples\Java\SampleApp

Add the application

When you add an application through the DE PMC, 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 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:

    • Java

      • Windows—%SOAM_HOME%\4.1\samples\Java\SampleApp\SampleAppJava.xml

      • Linux—$SOAM_HOME/4.1/samples/Java/SampleApp/SampleAppJava.xml

    The Service Package location window displays.

  6. Browse to the created service package and select it, then, select Continue.
    • Java

      • Windows—%SOAM_HOME%\4.1\samples\Java\SampleApp\SampleServiceJavaPackage.jar

      • Linux—$SOAM_HOME/4.1/samples/Java/SampleApp/SampleServiceJavaPackage.zip

    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.
  • From the command line:

%SOAM_HOME%\4.1\samples\Java\SampleaApp\RunAsyncClient.bat

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.

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/4.1/samples/Java/SampleApp/RunAsyncClient.sh

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.

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.

Locate the code samples


Operating System

Files

Location of Code Sample

Windows

Client

%SOAM_HOME%\4.1\samples\Java\SampleApp\src\com\platform\symphony\samples\SampleApp\client\AsyncClient.java

Input and output objects

%SOAM_HOME%\4.1\samples\Java\SampleApp\src\com\platform\symphony\samples\SampleApp\common\MyInput.java

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

Service code

%SOAM_HOME%\4.1\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%\4.1\samples\Java\SampleApp\SampleAppJava.xml

Output directory

%SOAM_HOME%\4.1\samples\Java\SampleApp\

Linux

Client

$SOAM_HOME/4.1/samples/Java/SampleApp/src/com/platform/symphony/samples/SampleApp/client/AsyncClient.java

Input and output objects

$SOAM_HOME/4.1/samples/Java/SampleApp/src/com/platform/symphony/samples/SampleApp/common/MyInput.java

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

Service code

$SOAM_HOME/4.1/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/4.1/samples/Java/SampleApp/SampleAppJava.xml

Output directory

$SOAM_HOME/4.1/samples/Java/SampleApp/


What the sample does

The client application sample sends 10 input messages through 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 Symphony

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.

Code differences between synchronous and asynchronous clients

An asynchronous client is very similar to a synchronous client. The only differences are:

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

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

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.

Note that:
  • 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.

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

  • isSuccessful() checks whether there is output to retrieve.

  • 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();
        }

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());
...

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();
                        }
                    } 
...