Building a simple C + + service component, part 1th: Introduction to the Service component Architecture C + + API

Source: Internet
Author: User
Tags naming convention sca sdo sprintf wrappers

Building a simple C + + service component, part 1th: Introduction to the Service component Architecture C + + API

Familiarize yourself with the APIs that will be used with Apache Tuscany SCA for C + +. You'll learn about the main components of the API in order to get started quickly.

See more in this series | 0 Reviews:

Ed Slattery ([email protected]), software engineer, IBM UK

Pete Robbins ([email protected]), software engineer, IBM UK

Andrew Borley ([email protected]), software engineer, IBM UK

December 12, 2006

    • Content
Building and connecting simple C + + service components about Tuscany

Apache Tuscany is an Apache software Foundation project that is in the incubation period. One of the goals of this project is to obtain the C + + runtime (For more information, see Resources) that implements the following serviced component Architecture (Service Component ARCHITECTURE,SCA) Specification:

    1. SCA Assembly Models (SCA Assembly model)
    2. SCA C + + client and implementation (SCA C + + client and implementation)

In this article, we will detail the steps to develop and deploy a service component for the Apache Tuscany C + + runtime using C + +.

Introduced

The Tuscany C + + Service Component Architecture (SCA) runtime allows you to build SCA components using standard C + + code and deploy them to locations that the SCA runtime can find and load. To enable this component to load dynamically, the runtime requires a series of profiles, together with your own header files, to generate proxies and wrappers that allow you to invoke your components from other components or client code in a manner similar to handling local C + + objects.

We'll start by creating a simple SCA component, then creating a second component and connecting the two together.

We use Microsoft Visual Studio as the development environment, but you can also use the command-line compiler and a text editor. You'll learn how to set up Studio projects and develop applications.

Note: Tuscany SCA relies on the Tuscany SDO project and the Apache AXIS2/C project. Before you begin, you must ensure that the Tuscany sca/sdo Library and Apache Axis Library are set up in your PATH environment variable. For more information, see the project download instructions.

The Tuscany SCA C + + runtime will need to know where modules and components are deployed. The deployment root is identified using the environment variable tuscany_scacpp_system_root. We'll set this variable right away so we can run our test program from within Visual Studio. If you are using a command line, you do not need to set the content before you run it.

TUSCANY_SCACPP_SYSTEM_ROOT specifies the path that the runtime will use to find the deployed modules and subsystems, which we will explain later. The root directory must have two subdirectories, named "Modules" and "subsystems", respectively.

Use Control Panel settings: Tuscany_scacpp_system_root=c:\mybasicsample.

Go to Control Panel, System, select the Advanced tab, and then click the Environment Variables button. Click the New button, set variable name to Tuscany_scacpp_system_root, and set variable value to C:\mybasicsample. Then click OK to set this environment variable.

Create a directory named Mybasicsample that contains two subdirectories, named modules and subsystems, respectively.

Now you're ready to deploy. We might want to write something that we can deploy.

Briefly review the SCA specification (you've read this specification-right?). ), you will remember that the SCA system contains one or more subsystems. Each subsystem contains a list of module components. Each module component is actually implemented by the module. In C + +, there is a set of descriptive XML files that are used to generate service proxies and wrappers at compile time and to find the services provided at run time. Before you begin development, it is necessary to understand these files. The file that describes the subsystem must be named Sca.subsystem and must be stored in its own subdirectory, which is located in the subsystems directory in the root directory. The Sca.subsystem file describes which module components are involved in the subsystem. A module component can be considered a simple part of a subsystem, the module component has a name, and also indicates the module that implements the module's component behavior:

Listing 1. Module components
<subsystem xmlns= "http://www.osoa.org/xmlns/sca/0.9" name= "Myservicesubsystem" >        <modulecomponent Name= "Mymodulecomponent" module= "Floatconverter"/></subsystem>

Listing 1 tells the SCA runtime that the module component "Mymodulecomponent" is implemented by a module called "Floatconverter", so we must build this module.

Sca.subsystem files are actually run-time artifacts and are not useful at compile time. Other files (component type files and Sca.module files) describe the "Floatconverter" module so that it can be found at run time. These files also help the code generator build wrappers and proxies for the service. We will discuss these files in more detail during the development process below.

Now let's go back to the beginning of this process. We want to deploy the C + + class as a service and put the service into a module named "Floatconverter". The following steps explain how to accomplish this task.

First, while there may be a risk of redundancy (a lot of people certainly have done this before), we'll create a sample C + + application.

Note: Before you begin the development process, you must download the SCA/SDO code and build it, or download a binary version to tell the project where to find the SCA runtime later. Set up two environment variables, named Tuscany_scacpp and Tuscany_sdocpp, to the deployment directory for SCA and SDO projects, where the corresponding bin, LIB, and include directories exist.

First, I'm going to create an abstract base class that represents the service we want to expose. This is equivalent to defining a Java interface. The header file we create here will be used by the client application to interpret the available service interfaces.

Here is the class, located in a header file named "Example.h":

Listing 2. class Example
Class Example  {public:    //We'll get a float from a string    virtual float tofloat (const char* input) = 0;    We'll convert a float to a string    virtual char* toString (float value) = 0;};

We need to tell the code generator which component will expose this abstract behavior, so we've created a component type file. The component type file links the name of the implementation class to the abstract behavior through a naming convention. This file is named according to the implementation class and contains a reference to the abstract class, so in this case, the file is called "Exampleimpl.componenttype":

Listing 3. Component Type File
<?xml version= "1.0" encoding= "ASCII"? ><componenttype xmlns= "http://www.osoa.org/xmlns/sca/0.9"               xmlns : xs= "Http://www.w3.org/2001/XMLSchema" ><service name= "Exampleservice" ><interface.cpp header= " Example.h "></interface.cpp></service></componentType>

Listing 3 tells the code generator that a component named "Exampleservice" exposes the behavior in the header file "Example.h". It also informs the runtime that the service implemented by the header file "ExampleImpl.h" is exampleservice.

Therefore, in Visual Studio, we created a Win32 DLL project and inserted the above header file in it. We named this project "Theexampleproject", so we expect it to generate a DLL named "TheExampleProject.dll" by default. Now to create the implementation for the service, the corresponding files will naturally be named ExampleImpl.cpp and ExampleImpl.h:

Listing 4. Service implementation
#include "Example.h" class Exampleimpl:public Example{public:    Exampleimpl ();    Virtual ~exampleimpl ();    Example interface    Virtual float tofloat (const char* input);    Virtual char* toString (float value);}; #include "ExampleImpl.h" #include <stdio.h> #include <string.h> #include <math.h> #include < Stdlib.h>exampleimpl::exampleimpl () {}    Exampleimpl::~exampleimpl () {}//Example interfacefloat ExampleImpl:: Tofloat (const char* input) {    if (input! = 0)    {        float f = (float) atof (input);        return f;    }    return (float) 0;} char* exampleimpl::tostring (float value) {    char * r = new char[100];    sprintf (R, "The Float is:%5.5f", value);    return r;}

The DLL is compiled and linked, so you can write a test program to use the Example API and test it. Please skip this step, as this is actually a standard content.

Now we're going to cover the rest of Jigsaw to link the "Floatconverter" module to the code we wrote.

The SCA runtime needs to know where the service is located. Use the runtime to find the module context in the client code and call "Locateservice". There are two ways in which the runtime can determine the default module context:

    1. Tuscany_scacpp_default_module=<subsystemname>/<modulecomponentname> through the environment variable, so in this case, this variable will be: TUSCANY_ Scacpp_default_module=myservicesubsystem/mymodulecomponent.
    2. The client code can use the Tuscanyruntime class to specify the default module. This is the method that we used in this example.

Now the runtime only needs to find the service in the module and find the name of the associated DLL. This is done by reading the "Sca.module" file, as shown in Listing 5.

Listing 5. Read Sca.module file
<?xml version= "1.0" encoding= "ASCII"? ><module xmlns= "http://www.osoa.org/xmlns/sca/0.9" xmlns:v= "/HTTP/ www.osoa.org/xmlns/sca/values/0.9 "Name=" Floatconverter "><component name=" Exampleservice ">< Implementation.cpp dll= "TheExampleProject.dll" header= "ExampleImpl.h" ></implementation.cpp>        < Properties> </properties><references></references></component></module>

We now know that the Floatconverter module contains a component named "Exampleservice". Exampleservice is implemented in TheExampleProject.dll, and its methods are described in the header file "ExampleImpl.h".

We should now add these sca.module and Sca.subsystem files to our Studio project in order to keep track of them.

Our SCA runtime now has all the information it needs to find the service and invoke the method. However, you cannot write a client that invokes the service directly, or it will generate a dependency on the DLL at compile time, so a callable proxy is required, and the library needs a wrapper class to wrap the service. These will be generated by our Scagen utility. Scagen will get the header file defined in the Sca.module file, and then build the required code. You only need to run it to tell where to find the appropriate file and where to write the output to. Let's assume that the source files for Sca.module files and projects are located in C:\mybasicsample\Example. In directory c:\mybasicsample, type Scagen-dir example-output Example.

Note: first of all, of course you will need to get scagen and need to know that Scagen is a Java application. If you download the binary code, the Scagen is already in the bin directory, otherwise it needs to be built. To build the Scagen, just install the Java JDK (1.4.2 or later) and install Apache Ant. Go to the Tools/scagen directory in the SCA project and type "ant". The Scagen utility will be built in the bin directory.

Four files are generated according to the naming convention shown in listing 6.

Listing 6. Scagen Practical Tools

Add these new files to your Visual Studio project.

Your project now relies on SCA and will not be built until you tell you where to find the SCA header files and libraries. Add $ (tuscany_scacpp)/include and $ (TUSCANY_SDO)/include to the path of the included header files (project, settings, C + +, preprocessor, and other include directories). Also add tuscany_sdo.lib and tuscany_sca.lib to libraries (link/input/object/library modules). Also add $ (tuscany_scacpp) \lib,$ (tuscany_sdocpp) \lib as an additional library path.

Now to compile your project again, you are ready to start writing the client.

The client program will be in the new console executable project, so you can create one of these projects directly. The environment relies on the SCA runtime, but obviously it must not depend on the DLL project. However, the client does not need to know which methods and services are provided, so ultimately we will use the abstract base class defined at the beginning. The Example.h header file should be added to the client project. The client project relies on the SCA runtime, so we must also add all the libraries and header files as if we were working with the DLL project.

Now create the client CPP file:

Listing 7. Client CPP Files
#include ". \myserviceproject\example.h "#include" osoa/sca/sca.h "#include <iostream> #include <stdlib.h> #include <tuscany/sca/core/tuscanyruntime.h>using namespace Osoa::sca;using namespace std;int main (int argc, char* argv[]    {if (argc! = 2) {cout << "MyClient.exe:Would you cast me adrift without my float?" << Endl;    return 0;    }//Set The default modulecomponent tuscanyruntime runtime ("Myservicesubsystem/mymodulecomponent"); try{Runtime.start ();//bootstrap the Tuscany Runtime//Get the current module context-(which is the Def        Ault) Modulecontext mycontext = Modulecontext::getcurrent (); Get An example Serviceexample *theservice = (example*) mycontext.locateservice ("Exampleservice"); if (Theservice = = 0) { cout << "MyClient.exe:Unable to find Myfloatservice" << Endl;}                 else {try {float result = Theservice->tofloat (argv[1]); cout &Lt;< "The float returned is" << result << Endl;                 Char *str = theservice->tostring (result + 1);       cout << "The string came back as" << str << Endl;     } catch (char* x) {cout << "MyClient.exe:exception caught:" << x << Endl; }}} catch (serviceruntimeexception& ex) {cout << "MyClient.exe:runtime exception caught:" <& Lt    ex << Endl; } runtime.stop (); Stop the Tuscany Runtime return 0;}

This completes the creation process. Your first SCA application invokes a single service from a client. To deploy it, you must put the runtime artifacts into the deployment directory, as follows:

For the Tuscany_scacpp_system_root/modules/example directory:

    • * Example.h Header file
    • * ExampleImpl.h Header file
    • * TheExampleProject.dll
    • * Exampleimpl.componenttype
    • * Sca.module

For the Tuscany_scacpp_system_root/subsystems/example directory:

    • * Sca.subsystem

Now that the Tuscany_sca.dll, Tuscany_sdo.dll, and Axis2 DLLs are already located somewhere on the path, and the TUSCANY_SCACPP_SYSTEM_ROOT environment variable has been set, your application will be able to run.

You have built a component, but a single component is not of much use. You won't buy a resistor, and then say, "Oh, look, the current is reduced." You want to be a radio, so let's talk about how to connect.

Services may invoke other services that can be connected together to allow the runtime to solve the problem of service usage in the same way as a client invocation. The main concept is the component context. We have learned that the runtime has a module context through which the service can be found. In the service, however, there is a component context where the runtime can find the services on which the current service depends.

In subsequent articles in this series, you will learn that these services can be exposed as Web services, and our SCA services can also rely on incoming Web services, but for now we are simply connecting two of services running within the same application space.

First, we need to create a second service. There is no need to elaborate on how to complete this work. We just need to create a simple service that returns a string:

Listing 8. Simple Service Example
Class stringthing  {public:    //We'll get a string    virtual char* getString () = 0;}; #include "StringThing.h" class Stringthingimpl:public Stringthing{public:    Stringthingimpl ();    Virtual ~stringthingimpl ();    Interface    Virtual char* getString ();}; #include "StringThingImpl.h" #include <stdio.h> #include <string.h> #include <math.h> #include < Stdlib.h>stringthingimpl::stringthingimpl () {}    Stringthingimpl::~stringthingimpl () {}//interfacechar* Stringthingimpl::getstring () {    char * r = new char[100];    sprintf (R, "the string from Stringthing");    return r;}

Now, before using Scagen again, we need to create a new component type file for the new component and add the new component to the Sca.module file. Finally, we need to inform the system that our first component type will reference the second component type. This is done by changing the Exampleimpl.componenttype file.

The following is the new component type (Stringthingimpl.componenttype):

Listing 9. Stringthingimpl.componenttype
<?xml version= "1.0" encoding= "ASCII"? ><componenttype xmlns= "http://www.osoa.org/xmlns/sca/0.9"               xmlns : xs= "Http://www.w3.org/2001/XMLSchema" ><service name= "Stringservice" ><interface.cpp header= " StringThing.h "></interface.cpp></service></componentType>

The following is the changed Sca.module file:

Listing 10. Sca.module file after change
><?xml version= "1.0" encoding= "ASCII"? ><module xmlns= "http://www.osoa.org/xmlns/sca/0.9" xmlns:v= "http ://www.osoa.org/xmlns/sca/values/0.9 "name=" Floatconverter "><component name=" ExampleComponent ">< Implementation.cpp dll= "TheExampleProject.dll" header= "ExampleImpl.h" ></implementation.cpp>        < Properties> </properties><references><stringservice>stringthing/stringservice</ Stringservice></references></component><component name= "Stringthing" >< Implementation.cpp dll= "TheExampleProject.dll" header= "StringThingImpl.h" ></implementation.cpp>        <properties> </properties><references></references></component></module>

The following is the changed Exampleimpl.componenttype file:

Listing 11. Exampleimpl.componenttype after the change
<?xml version= "1.0" encoding= "ASCII"? ><componenttype xmlns= "http://www.osoa.org/xmlns/sca/0.9"               xmlns : xs= "Http://www.w3.org/2001/XMLSchema" ><service name= "Exampleservice" ><interface.cpp header= " Example.h "></interface.cpp></service><reference name=" Stringservice "><interface.cpp Header= "StringThing.h" ></interface.cpp></reference></componentType>

Note that we used the lowercase "stringservice" to refer to the capitalized service "Stringservice". When you run Scagen again, you will find that two additional files were created. These are the proxy header files and CPP files that are referenced by "Stringservice" when called from Exampleimpl. You will need to add these two new files to your project.

Finally, the following is the new code for exampleservice, which resolves the new service using the component context:

Listing 12. Exampleservice
char* exampleimpl::tostring (float value) {    char * r = new char[100];    Now make a service call to Stringthing    ... try {        Componentcontext mycontext = Componentcontext::getcurrent ();        stringthing* Stringservice = (stringthing*) mycontext.getservice ("Stringservice");        if (Stringservice = = 0)        {            cout << "Unable to find string thing service" << Endl;        }        else        {            char* chars = stringservice->getstring ();            if (chars! = 0)            {                sprintf (R, "%s and the float is%5.5f", chars,value);                Delete chars;                return r;}}    }    catch (serviceruntimeexception& e)    {        cout << "errror from service:" << e << Endl;        // .. Just carry On    }    sprintf (R, "The Float is:%5.5f", value);    return r;}

Keep in mind that since we have a new service, we must deploy a new runtime file:

    • StringThingImpl.h
    • StringThing.h
    • Stringthingimpl.componenttype

Of course, DLL and module files are changed, so you need to copy the files as well.

Conclusion

So far, our first connected and working SCA subsystem has been completed. Figure 1 will help you review the process of parsing the service name. We hope that this example will give you some insight into the power of SCA. As an exercise, you can add some properties to the component, or try to re-package stringthing as a different DLL.

In the next article, we'll discuss inbound and outbound WEB services and their relationships with AXIS2.

Figure 1. Service Layout Reference
    • You can refer to the original English text on the DeveloperWorks global site in this article.
    • Apache Tuscany
    • SCA Assembly Model
    • SCA C + + Client and implementation

Building a simple C + + service component, part 1th: Introduction to the Service component Architecture C + + API

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.