CrossLanguage: Developing cross-language clients and services

Goal

This tutorial walks you through using Symphony serialization when developing client applications and services. Symphony serialization allows clients and services written in different programming languages to communicate with each other. For example, you can use a C++ client with a Java service.

You should also use Symphony serialization if you are concerned with performance and memory usage.

In this tutorial, you build samples in C++, Java, and .NET, package and deploy the service in either language, and use the C++, Java, COM, and .NET clients to submit work to the service.

At a glance

  1. Build the samples

  2. Package the service

  3. Add the application

  4. Run the sample clients

  5. Walk through the code

Prerequisites

  • Ensure that you have installed and started Symphony DE.

  • You should also have completed the following tutorials in either C++, Java, or .NET:

    • Your First Synchronous Symphony Client

    • Your First Symphony Service

Build the samples

The following section provides instructions for building the samples in C++, Java, COM, and .NET.

You need to build all samples to have cross-language clients and services.

Build the C++ sample client and service

On Windows

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

  1. In %SOAM_HOME%\5.1\samples\CrossLanguage\CPP, locate workspace file CrossLanguageSampleCPP_vc6.dsw, or one of the solution files supported by your version of Visual Studio.
  2. Load the file into Visual Studio and build it.

On Linux

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

  1. Change to the $SOAM_HOME/conf directory.
  2. Set 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/CrossLanguage/CPP:
    make

Build the Java 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%\5.1\samples\CrossLanguage\Java\ 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%\5.1\samples\CrossLanguage\Java\ directory and run the build command:
ant
Compile in Eclipse

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

On Linux

Compile with the Makefile

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

  1. Change to the $SOAM_HOME/conf directory.
  2. Set the environment:
    • For csh, enter

      source cshrc.soam
    • For bash, enter

      . profile.soam
  3. Change to the $SOAM_HOME/5.1/samples/CrossLanguage/Java directory and run the command:
    make
Compile with the Ant build file

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

  1. Change to the $SOAM_HOME/conf directory.
  2. Set the environment:
    • For csh, enter

      source cshrc.soam
    • For bash, enter

      . profile.soam
  3. Change to the $SOAM_HOME/5.1/samples/CrossLanguage/Java directory and run the command:
    ant
Compile in Eclipse

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

Build the .NET sample client and service

  1. Double-click the appropriate Visual C#.NET solution file located in the $SOAM_HOME/5.1/samples/CrossLanguage/DotNet.
  2. Build the solution.

Build the COM client

  1. Double-click to open VB_Clients.vbp located in the %SOAM_HOME%\4.0\samples\CrossLanguage\COM\Client directory.
  2. In the Microsoft Visual Basic, open the SyncClient.frm code and uncomment api.Uninitialize, which is under Form_Unload. Close the form.
  3. In the Microsoft Visual Basic, build the COM client by clicking File>Make ComApiClients.exe and create a project in the %SOAM_HOME%\4.0\samples\CrossLanguage\COM\output directory.

Package the service

Select the service in the language of your preference to deploy.

Important:

Deploy the service from only one language. This is because all services are registered under the same application, so only one service can be deployed at any one time.

Instructions are provided for all programming languages.

Package the C++ sample service

On Windows

To run the service, you first need to create a service package.

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

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

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

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

On Linux

To run the service, you first need to create a service package, then deploy it.

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

    cd $SOAM_HOME/5.1/samples/CrossLanguage/CPP/Output

  2. Create the service package:

    tar -cvf CrossLanguageServiceCPP.tar CrossLanguageServiceCPP

    gzip CrossLanguageServiceCPP.tar

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

Package the Java 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.

Go to the directory in which the service package is located.
  • On Windows, you have CrossLanguageServiceJavaPackage.jar

cd %SOAM_HOME%\5.1\samples\CrossLanguage\Java
  • On Linux, you have CrossLanguageServiceJavaPackage.zip

cd $SOAM_HOME/5.1/samples/CrossLanguage/Java

Package the .NET sample service

You must package the files required by your service to create a service package.

  1. Go to the directory that contains the files for the service package:
    cd %SOAM_HOME%\5.1\samples\CrossLanguage\DotNet\CS\output
  2. Locate the CrossLanguageServiceDotNetCS.exe and Common.dll files and add them to an archive using a compression program such as WinZip®.
  3. Save the archive as CrossLanguageServiceDotNetCS.zip in the current directory.

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

    Select the profile that matches the programming language and operating system for your service. For example, if you want to use a C++ service with a .NET and Java client, use the C++ application profile.

    • C++:

      • Windows—%SOAM_HOME%\5.1\samples\CrossLanguage\CrossLanguageCpp.xml

      • Linux—$SOAM_HOME/5.1/samples/CrossLanguage/CrossLanguageCpp.xml

    • Java

      • Windows—%SOAM_HOME%\5.1\samples\CrossLanguage\crossLanguageJava.xml

      • Linux—$SOAM_HOME/5.1/samples/CrossLanguage/CrossLanguageJava.xml

    • .NET:

      • %SOAM_HOME%\5.1\samples\CrossLanguage\CrossLanguageDotNetCS.xml

    The Service Package location window displays.

  6. Browse to the service package you created in .zip, tar.gz, or .jar format and select it, then, select 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 clients

On Windows

To demonstrate that your cross-language clients and services work, use clients developed in different languages, and submit workload to a service developed in a different language.

We are going to use C++, Java, COM, and .NET clients to submit work to the service.

  1. Run the C++ client on the command-line.
    %SOAM_HOME%\5.1\samples\CrossLanguage\CPP\Output\CrossLanguageClient

    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 Java client on the command-line
    %SOAM_HOME%\5.1\samples\CrossLanguage\Java\RunCrossLanguageClient.bat

    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.

  3. Run the .NET client on the command-line.
    %SOAM_HOME%\5.1\samples\CrossLanguage\DotNet\CS\output\CrossLanguageClient

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

  4. Run the COM client on the Synchronous Symphony Client window.
    Note:

    Make sure you have local administrator privileges to register the COM API assembly. Register Platform.Symphony.Soam.COM.dll, which is at the location %SOAM_HOME%\4.0\win32-vc7\lib\COM or %SOAM_HOME%\4.0\w2k3_x64-vc7-psdk\lib\COM with regsvr32. For example, regsvr32 Platform.Symphony.Soam.COM.dll.

    %SOAM_HOME%\5.1\samples\CrossLanguage\COM\output\ComApiClients.exe

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

On Linux

To demonstrate that your cross-language clients and services work, use clients developed in a different programming language from the service to submit workload.

For this example we are going to use C++ and Java clients to submit work to the service.

  1. Run the C++ client application.
    $SOAM_HOME/5.1/samples/CrossLanguage/CPP/output/CrossLanguageClient

    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.

  2. Run the Java client application.
    • From the command-line:

    $SOAM_HOME/5.1/samples/CrossLanguage/Java/RunCrossLanguageClient.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.

Walk through the code

Review the sample code to learn how you can create cross-language clients and services.

Locate the code samples


Operating System

Language

File

Location of Code Sample

Windows

Java

Client

%SOAM_HOME%\5.1\samples\CrossLanguage\Java\src\com\platform\symphony\samples\CrossLanguage\client\CrossLanguageClient.java

Input, output objects

%SOAM_HOME%\5.1\samples\CrossLanguage\Java\src\com\platform\symphony\samples\CrossLanguage\common\MyMessage.java

Service

%SOAM_HOME%\5.1\samples\CrossLanguage\Java\src\com\platform\symphony\samples\CrossLanguage\service\CrossLanguageService.java

Application profiles

The Java service and additional application parameters are specified in the application profile:

%SOAM_HOME%\5.1\samples\CrossLanguage\crossLanguageJava.xml

Output directory

%SOAM_HOME%\5.1\samples\CrossLanguage\Java

C++

Client

%SOAM_HOME%\5.1\samples\CrossLanguage\CPP\Client\CrossLanguageClient.cpp

Input, output objects

%SOAM_HOME%\5.1\samples\CrossLanguage\CPP\Common\MyMessage.cpp

Service

%SOAM_HOME%\5.1\samples\CrossLanguage\CPP\Service\CrossLanguageService.cpp

Application profiles

The C++ service and additional application parameters are specified in the application profile:

%SOAM_HOME%\5.1\samples\CrossLanguage\CrossLanguageCpp.xml

Output directory

%SOAM_HOME%\5.1\samples\CrossLanguage\CPP\Output

.NET

Client

%SOAM_HOME%\5.1\samples\CrossLanguage\DotNet\CS\Client\CrossLanguageClient.cs

Input, output objects

%SOAM_HOME%\5.1\samples\CrossLanguage\DotNet\CS\Common\MyMessage.cs

Service

%SOAM_HOME%\5.1\samples\CrossLanguage\DotNet\CS\Service\CrossLanguageService.cs

Application profiles

The .NET service and additional application parameters are specified in the application profile:

%SOAM_HOME%\5.1\samples\CrossLanguage\CrossLanguageDotNetCS.xml

Output directory

%SOAM_HOME%\5.1\samples\CrossLanguage\DotNet\CS\output

COM

Client

%SOAM_HOME%\5.1\samples\CrossLanguage\COM\Client\VB_Clients.vbp

Input, output objects

MyMessage.cls is under Class Modules in VB.

Output directory

%SOAM_HOME%\5.1\samples\CrossLanguage\COM\output

Linux

Java

Client

$SOAM_HOME/5.1/samples/CrossLanguage/Java/src/com/platform/symphony/samples/CrossLanguage/client/CrossLanguageClient.java

Input, output objects

$SOAM_HOME/5.1/samples/CrossLanguage/Java/src/com/platform/symphony/samples/CrossLanguage/common/MyMessage.java

Service

$SOAM_HOME/5.1/samples/CrossLanguage/Java/src/com/platform/symphony/samples/CrossLanguage/service/CrossLanguageService.java

Application profiles

The Java service and additional application parameters are specified in the application profile:

$SOAM_HOME/5.1/samples/CrossLanguage/CrossLanguageJava.xml

Output directory

$SOAM_HOME/5.1/samples/CrossLanguage/Java

C++

Client

$SOAM_HOME/5.1/samples/CrossLanguage/CPP/Client/CrossLanguageClient.cpp

Input, output objects

$SOAM_HOME/5.1/samples/CrossLanguage/CPP/Common/MyMessage.cpp

Service

$SOAM_HOME/5.1/samples/CrossLanguage/CPP/Service/CrossLanguageService.cpp

Application profiles

The C++ service and additional application parameters are specified in the application profile:

$SOAM_HOME/5.1/samples/CrossLanguage/CrossLanguageCpp.xml

Output directory

$SOAM_HOME/5.1/samples/CrossLanguage/CPP/Output


What the samples do

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

The service takes input data sent by the client application and returns the input and the reply "Hello Client !!". The client blocks to receive messages synchronously.

Differences between cross-language and same-language clients and services

Client and service structures are the same in cross-language clients and services as those of same-language clients and services, except for serialization.

The Java and .NET APIs support two modes of serialization: native serialization and Symphony serialization. The same-language samples for both of these APIs demonstrate the use of native serialization. On the other hand, the C++ and cross-language samples implement Symphony serialization.

Symphony serialization

Symphony serialization allows communication between clients and services written in different languages. For example, Symphony serialization allows you to use a C++ client with a Java service.

Symphony serialization is achieved in all languages by deriving from the SOAM Message object and implementing the appropriate serialization handlers.

You also use Symphony serialization if you are concerned with performance and memory usage.

Compatibility matrix

The following compatibility matrix for cross-language support shows which data types are compatible across languages.

C++

Java

.NET

VB

bits

short

short

Int16

Short

16

int

int

Int32

Integer

32

long long

long

Int64

Long

64

unsigned short

UInt16

UShort

16

unsigned int

UInt32

UInteger

32

unsigned long long

UInt64

ULong

64

float

float

Single

Single

32

double

double

Double

Double

64

char

char

Char

Char

-

bool

boolean

Boolean

Boolean

8

const char*

java.lang.String

String

String

N/A


Note:

  • In Java and .NET, a character may consume 1-2 bytes of memory while in C++ a character consumes 1 byte of memory.

  • Since byte arrays are represented differently across the supported languages, you need to use a special method when serializing this data. To write a byte array in C++ and Java, use the writeByteArray() method on the OutputStream. To write a byte array in .NET, use the WriteByteArray() method on the OutputStream.

  • Note that the C++ “long” type and "unsigned long type" has been removed from the Compatibility Matrix for Symphony releases 3.1 and later due to portability issues across platforms and languages. While the C++ long type can still be serialized/de-serialized in the API, developers should consider using “int” for 32-bit values and “long long” for 64-bit values to maintain platform independence. Refer to the section on 64-bit Application Support for more information.

Use Symphony serialization in C++ to serialize input and output

There is no native serialization in C++. All C++ tutorials already use Symphony serialization. The client and service have the same structure as samples in all C++ tutorials.

Use Symphony serialization in Java to serialize input and output

Send input to the service

In the client, in CrossLanguageClient.java, when sending input to the service, session.sendTaskInput() takes in the message object instead of java.io.Serializable.

 ...
// Now we will send some messages to our service
                    int tasksToSend = 10;
                    for (int taskCount = 0; taskCount < tasksToSend; taskCount++)
                    {
                        // Create a message
                        MyMessage inMsg = new MyMessage(taskCount, true, "Hello Grid !!");
                        // send it
                        TaskInputHandle input = session.sendTaskInput(inMsg);
 ...

Serialize input

In MyMessage.java, implement the onSerialize() handler to write data to the provided OutputStream. Symphony calls this method when you send data.

In native serialization, the Java serialization mechanisms automatically serialize your data. For Symphony serialization, you need to specify the data you want to serialize.

Note:

Anything that you write to the stream you need to read back in the same order that you wrote it.

...
 public void onSerialize(OutputStream stream) throws SoamException
    {
        stream.writeInt(m_int);
        stream.writeBoolean(m_isSync);
        stream.writeString(m_string);
    }
...

Retrieve input on the service

In CrossLanguageService.java, create an instance of the message object and pass your own instance to populate the inMsg message object. The populateTaskInput() method fills in the object.

...
public void onInvoke (TaskContext taskContext) throws SoamException
    {
        // Get the input that was sent from the client
        MyMessage inMsg = new MyMessage();
        taskContext.populateTaskInput(inMsg);
...

In MyMessage.java, implement the onDeSerialize() handler to read data from the provided InputStream. Symphony calls this method when you retrieve data.In native serialization, the Java serialization mechanisms automatically deserialize your data. For Symphony serialization, you need to specify the data to read from the stream.

Note:

Anything that you write to the stream you need to read back in the same order that you wrote it.

...
public void onDeserialize(InputStream stream) throws SoamException
    {
        m_int = stream.readInt();
        m_isSync = stream.readBoolean();
        m_string = stream.readString();
    }
...

Send output back to the client

In CrossLanguageService.java, pass the output message object to send output back to the client. Symphony invokes your onSerialize() handler to send the output back to the client.

...
// Set our output message
        taskContext.setTaskOutput(outMsg);
...

Retrieve output on the client

In your client, in CrossLanguageClient.java, create an instance of the message object and pass your own instance to populate the outMsg object. The populateTaskOutput() method fills in the object.

Symphony invokes your onDeserialize() handler to retrieve the output.

...
// get the message returned from the service
                            MyMessage outMsg = new MyMessage();
                            output.populateTaskOutput(outMsg);
...

Use Symphony serialization in .NET to serialize input and output

Send input to the service

In your client, in CrossLanguageClient.cs, when sending input to the service, session.SendTaskInput() takes a message object instead of a [serializable] object.

 ...
// Now we will send some messages to our service
                    int numTasksToSend = 10;
                    for (int taskCount = 0; taskCount < numTasksToSend; taskCount++)
                    {
                        // Create a message
                        MyMessage inputMessage = new MyMessage(taskCount, true, "Hello Grid !!");
                        // send it
                        TaskInputHandle input = session.SendTaskInput(inputMessage);
 ...

Serialize input

In MyMessage.cs, implement the OnSerialize() handler to write data to the provided OutputStream. Symphony calls this method when you send data.

In native serialization, .NET serialization mechanisms automatically serialize your data. For Symphony serialization, you need to specify the data you want to serialize.

Note:

Anything that you write to the stream you need to read back in the same order that you wrote it.

...
public override void OnSerialize(OutputStream ostream)
        {
            ostream.WriteInt32(m_id);
            ostream.WriteBoolean(m_isSync);
            ostream.WriteString(m_string);
        }
...

Retrieve input on the service

In CrossLanguageService.cs, create an instance of the message object and pass your own instance to populate the inputMsg object. The PopulateTaskInput() method fills in the object.

...
public override void OnInvoke(TaskContext taskContext)
{
// get the input that was sent from the client
MyMessage inputMsg = new MyMessage();
taskContext.PopulateTaskInput(inputMsg);
...

In MyMessage.cs, implement the OnDeserialize() handler to read data from the provided InputStream. Symphony calls this method when you retrieve data.

In native serialization, .NET serialization mechanisms automatically deserialize your data. For Symphony serialization, you need to specify the data to read from the stream.

Note:

Anything that you write to the stream you need to read back in the same order that you wrote it.

...
public override void OnDeserialize(InputStream istream)
        {
            m_id     = istream.ReadInt32();
            m_isSync = istream.ReadBoolean();
            m_string = istream.ReadString();
        }
...

Send output back to the client

In CrossLanguageService.cs, pass the output message object to send output back to the client. Symphony invokes your OnSerialize() handler to send the output back to the client.

...
// set our output message
taskContext.SetTaskOutput(outputMsg);
...

Retrieve output on the client

In your client, in CrossLanguageClient.cs, create an instance of the message object and pass your own instance to populate the outputMessage object. The PopulateTaskOutput() method fills in the object. Symphony invokes your OnDeSerialize() handler to retrieve the output.

...
 // get the message returned from the service
                            MyMessage outputMessage = new MyMessage();
                            output.PopulateTaskOutput(outputMessage);
...