Tuscany SCA Native - C++ Extension

The Tuscany C++ extension allows C++ classes to be used as components in SCA composites and as clients that can invoke SCA services.

This document describes how to build and install the C++ extension and create and run SCA components in Tuscany SCA Native milestone release 3.

See the SCA C++ Client and Implementation specification for more details about the SCA C++ programming model.

See CppCalculator or CppBigBank for samples that demonstrate the use of C++ components

System Requirements

In order to install and use the Tuscany SCA C++ Extension there are some extra requirements in addition to the Tuscany SCA requirements:

Software Download Link
Java SDK 1.4 or later http://java.sun.com/javase/downloads
For building and running the SCAGEN code generation tool, which is used when developing Tuscany SCA C++ components. Please download and follow the installation instructions
Apache Ant 1.6 or later http://ant.apache.org
For building the SCAGEN code generation tool. This is only required when building the C++ extension from a source distribution of Tuscany SCA Native. Please download and follow the installation instructions

Installing the Tuscany SCA C++ Extension

Getting the Tuscany SCA C++ Extension working with the binary release on Linux and Mac OS X

  1. Add the <tuscany_sca_install_dir>/extensions/cpp/lib directory to the PATH environment variable

Getting the Tuscany SCA C++ Extension working with the source release on Linux and Mac OS X

  1. You will need the Tuscany SCA kernel and SDO libraries - follow the instructions here to build the SCA libraries and default extensions
  2. The following environment variables are required:
    • TUSCANY_SCACPP=<path to built Tuscany SCA>
    • TUSCANY_SDOCPP=<path to installed Tuscany SDO>
  3. Build the C++ source only with the following command sequence:
    • cd <tuscany_sca_install_dir>
    • ./configure --prefix=$TUSCANY_SCACPP --enable-cpp --enable-wsbinding=no
    • make
    • make install
    NOTE: If you don't provide a --prefix configure option, it will by default install into /usr/local/tuscany/sca

Getting the Tuscany SCA C++ Extension working with the binary release on Windows

  1. Add the <tuscany_sca_install_dir>/extensions/cpp/lib directory to the PATH environment variable

Getting the Tuscany SCA C++ Extension working with the source release on Windows

  1. Unzip the supplied source zip file
  2. The following environment variables are required:
    • TUSCANY_SCACPP=<path to built Tuscany SCA>
    • TUSCANY_SDOCPP=<path to installed Tuscany SDO>
  3. You must have set up the environment for Microsoft Visual C++ tools. The build command will call vcvars32 to set the environment. Ensure the directory containing this is on your path. This will be where you installed the compiler.
  4. Build the source:
    • cd <to where you unzipped the source>
    • build
    This will build all the projects and put the required output into the 'deploy' directory

    Alternatively, open the workspace at <tuscany_sca_install_dir>/projects/tuscany_sca/tuscany_sca.dsw in Visual Studio 6 or at at <tuscany_sca_install_dir>/projectsvc7/tuscany_sca/tuscany_sca.sln in Visual Studio 7.1 - you can build projects individually
  5. Set the TUSCANY_SCACPP environment variable to point to the 'deploy' directory that was just created

Creating and deploying an SCA C++ Component

Each SCA C++ component needs:

  • A service header file that defines the operations that can be invoked on the component
  • An implementation header file that defines the implementation and extends the service header file
  • A C++ implementation of the service that implements the operations defined in the service header file
  • Proxy and wrapper header and implementation files generated by the Tuscany C++ SCAGEN tool
  • A service definition in a .componentType file
  • An SCDL component definition within an SCDL composite file. Usually this composite file will contain multiple components configured and assembled together.

Once these items are in place for each component in your composite, you will need to deploy this composite to your SCA system. In this release we are using the SCA recursive composition model to do this. You simply create another SCDL component definition in a separate composite file that will represent the composite you created above in the SCA system. Follow the steps below to see each of these items being created and used.

In this section we will use the Calculator sample as a worked example. The Calculator code and files can be found at samples/CppCalculator and has been developed further than the details specified below. In the interests of readability, the example used below takes the simplest path.

  1. Create the service header file that defines the operations your component will implement. E.g. Calculator.h contains the following:
    #ifndef CALCULATOR_H
    #define CALCULATOR_H
    class Calculator  
    {
    public:
        virtual float add(float arg1, float arg2) = 0;
        virtual float sub(float arg1, float arg2) = 0;
        virtual float mul(float arg1, float arg2) = 0;
        virtual float div(float arg1, float arg2) = 0;
    };
    
    #endif
  2. Create the implementation header file that extends the service header file. E.g. CalculatorImpl.h contains the following:
    #ifndef CALCULATORIMPL_H
    #define CALCULATORIMPL_H
    
    #include "Calculator.h"
    
    class CalculatorImpl : public Calculator
    {
    public:
        CalculatorImpl();
        virtual ~CalculatorImpl();
    
        // Calculator interface
        virtual float add(float arg1, float arg2);
        virtual float sub(float arg1, float arg2);
        virtual float mul(float arg1, float arg2);
        virtual float div(float arg1, float arg2);
    };
    
    #endif
  3. Create the implementation for the component based on the implementation header file. E.g. CalculatorImpl.cpp contains the following code:
    #include "CalculatorImpl.h"
    #include 
    
    CalculatorImpl::CalculatorImpl()
    {
    }
        
    CalculatorImpl::~CalculatorImpl()
    {
    }
    
    // Calculator interface
    float CalculatorImpl::add(float arg1, float arg2)
    {
        float result = arg1 + arg2;
    
        printf("CalculatorImpl::add %f + %f = %f\n", arg1, arg2, result);
        return result;
    }
    
    float CalculatorImpl::sub(float arg1, float arg2)
    {
        float result = arg1 - arg2;
        printf("CalculatorImpl::sub %f - %f = %f\n", arg1, arg2, result);
        return result;
    }
    
    float CalculatorImpl::div(float arg1, float arg2)
    {
        float result = arg1 / arg2;
        printf("CalculatorImpl::div %f / %f = %f\n", arg1, arg2, result);
        return result;
    }
    	
    float CalculatorImpl::mul(float arg1, float arg2)
    {
        float result = arg1 * arg2;
        printf("CalculatorImpl::mul %f * %f = %f\n", arg1, arg2, result);
        return result;
    }
  4. Create the componentType file for your component to define the service that your component provides. The file must be named after your implementation class and specifies the name of the service and the service header file (which describes the service operations). E.g. CalculatorImpl.componentType contains the following XML:
    <componentType xmlns="http://www.osoa.org/xmlns/sca/1.0">
    
    	<service name="CalculatorService">
    		<interface.cpp header="Calculator.h"/>
    	</service>
    
    </componentType>
  5. Create a sample.calculator.composite file for your composite and define your component within it. The component definition specifies the implementation library to use (a .dll file on Windows, a .so file on Linux and a .dylib file on Mac OS X) and the implementation header file (which describes the implementation class). Component properties and references to other services can also be specified here. E.g. the Calculator sample.calculator.composite file contains the following XML:
    <composite xmlns="http://www.osoa.org/xmlns/sca/1.0" 
    	name="sample.calculator">
    
    	<component name="CalculatorComponent">
    		<implementation.cpp library="Calculator" header="CalculatorImpl.h"/>
    	</component>
    
    </composite>
  6. Generate the proxy and wrapper classes and header files using the SCAGEN tool. These classes are used by the Tuscany SCA C++ runtime to enable service implementations to be invoked from a client or another component. Run the SCAGEN tool, specifying the directory where your header files, sca.composite and componentType file are and the directory where you want the generated files to be placed. E.g. on Windows, the following command is run from the directory where Tuscany SCA is deployed:
    ./extensions/cpp/bin/scagen.bat -dir ./samples/CppCalculator/sample.calculator -output ./samples/CppCalculator/sample.calculator
    which produces the following files:
    • CalculatorImpl_CalculatorService_Proxy.h
    • CalculatorImpl_CalculatorService_Proxy.cpp
    • CalculatorImpl_CalculatorService_Wrapper.h
    • CalculatorImpl_CalculatorService_Wrapper.cpp
  7. Compile and link the code that has been written and generated. This will produce a .dll or .so library file. The name should match the library name specified in the sample.calculator.composite file.
  8. Create the sample.calculator.solution.composite file and define the Calculator composite as a component within it. This is used to include the Calculator composite in the SCA system and should specify the composite name used in the sample.calculator.composite file. E.g. the Calculator sample.calculator.solution.composite file contains the following XML:
    <composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
    	name="sample.calculator.solution">
    	
            <component name="sample.calculator.CalculatorComponent">
            	<implementation.composite name="sample.calculator" />
           	</component>
    
    </composite>
  9. Deploy the various files into the SCA directory structure, as follows:
    • <deploy_root>/CompositeName/CompositeName.composite
    • <deploy_root>/CompositeName/Implementation.componentType
    • <deploy_root>/CompositeName/Implementation.dll (or .so on Linux and .dylib on Mac OS X)
    • <deploy_root>/SolutionName.composite
    E.g. for the Calculator sample the structure is:
    • samples/CppCalculator/deploy/sample.calculator/Calculator.h
    • samples/CppCalculator/deploy/sample.calculator/CalculatorImpl.h
    • samples/CppCalculator/deploy/sample.calculator/sample.calculator.composite
    • samples/CppCalculator/deploy/sample.calculator/CalculatorImpl.componentType
    • samples/CppCalculator/deploy/sample.calculator/Calculator.dll
    • samples/CppCalculator/deploy/sample.calculator.solution.composite
  10. Your component, composite and subsystem are now ready to be invoked. Create a client that will call the service. E.g. the Calculator client (in the CalculatorClient.cpp file) contains code similar to the following:
    try
    {
        // Locate the service
        CompositeContext myContext = CompositeContext::getCurrent();
        Calculator *calcService = (Calculator*) myContext.locateService("CalculatorComponent/CalculatorService");
        if (calcService == 0)
        {
            cout << "calculator_client: Unable to find Calculator service" << endl;
        }
        else
        {
            float result = calcService->add(arg1, arg2);
            cout << "calculator_client add(" << arg1 << "," << arg2 << ") = " << result << endl; 
        }
    }
    catch (ServiceRuntimeException& ex)
    {
        cout << "calculator_client: Error whilst invoking Tuscany: " << 
                ex.getMessageText() << endl; 
    }
    
  11. Compile, link and run the client that has been created. You should (hopefully!) see your component invoked. Remember you will need to have the TUSCANY_SCACPP and TUSCANY_SDOCPP environment variables set, as well as the SCA and SDO bin directories on your PATH on Windows or the SCA and SDO lib directories on your LD_LIBRARY_PATH on Linux and your DYLD_LIBRARY_PATH on Mac OS X. You will also need to set the TUSCANY_SCACPP_SYSTEM_ROOT and TUSCANY_SCACPP_DEFAULT_COMPONENT environment variables to the path to your SCA component directory structure and the default component respectively. TUSCANY_SCACPP_SYSTEM_ROOT is the directory where the SCA runtime will look for any .composite files and TUSCANY_SCACPP_DEFAULT_COMPONENT is the name of the base component to be used by SCA clients or containers when finding services - this component must be an instance of a composite (i.e. contain an <implementation.composite> element).
    E.g. on Windows run the following commands:
    • set TUSCANY_SCACPP=C:/tuscany_sca
    • set TUSCANY_SDOCPP=C:/tuscany_sdo
    • set PATH=%PATH%;C:/tuscany_sca/bin;C:/tuscany_sdo/bin
    • set TUSCANY_SCACPP_SYSTEM_ROOT=C:/tuscany_sca/samples/CppCalculator/deploy
    • set TUSCANY_SCACPP_DEFAULT_COMPONENT=sample.calculator.CalculatorComponent
    • ./calculator_client.exe
  12. Optionally, enable Tuscany logging by setting the TUSCANY_SCACPP_LOGGING environment variable with the level you wish to log at (0 for minimal logging, up to 9 for more detailed logging) and the TUSCANY_SCACPP_LOG environment variable to define the file to log to (if this is not set, logging will go to the console). E.g. on Windows run the following commands:
    • set TUSCANY_SCACPP_LOGGING=5
    • set TUSCANY_SCACPP_LOG=C:/tuscany/mylogfile.txt

Getting Help

First place to look is at the Tuscany FAQ at http://incubator.apache.org/tuscany/faq.html

Any problem with this release can be reported to the Tuscany mailing lists or create a JIRA issue at http://issues.apache.org/jira/browse/Tuscany.