WSO2 announced the release of the Web Services Framework for C++ (WSF/C++) version 2.0.0. Similar to WSF/PHP which is really popular among the PHP community, WSF/CPP is the C++ language binding for the Apache Axis2/C and the other supporting web services projects like Apache Sandesha/C, Apache Rampart/C.

With this release C++ developers will be able to write web services and web service clients to inter-op with .NET/Java/PHP or any other platform built-on web service standards. The release is shiped with a code generation tool that will be used to generate the code for skeletons and stubs from a WSDL, so developers only need to concentrate on their business logic as the generated code will take care of building or parsing xmls and running them on top of the framework.
Here are the key features of the new release.

  1. Support core web service standards like SOAP 1.1, SOAP 1.2, WSDL 1.1, WSDL 2.0, REST
  2. Support for web services QoS specifications.
    • WS-Addressing
    • WS-Security
    • WS-Policy
    • WS-Security-Policy
    • WS-Reliable-Messaging
  3. Support binary attachment with MTOM and SWA (With the Support for large binaries)
  4. Code generation tool.
  5. Proven interoperability with .NET.

As a side note, you will be able to participate to a free summer school training session on the WSF/CPP conducted by Nandika Jayawardane who is the project lead of both WSF/CPP and WSF/PHP on 30th July. You can register to it (for free) from here.

Once you have a web service, you can write clients to invoke that service from any language, mostly with the help of a framework written in to that particular language. When it comes to C, the most popular choice is Apache Axis2/C framework. When you are using Axis2/C to write web service clients, you need to learn about AXIOM which is a easy to use high performing XML model and the service client API which can be used to actually invoke the service. Lets look at the code.

#include <stdio.h>
#include <axiom.h>
#include <axis2_util.h>
#include <axiom_soap.h>
#include <axis2_client.h>

axiom_node_t *build_om_payload_for_helloworld_svc(
    const axutil_env_t * env);

int
main()
{
    const axutil_env_t *env = NULL;
    const axis2_char_t *address = NULL;
    axis2_endpoint_ref_t *endpoint_ref = NULL;
    axis2_options_t *options = NULL;
    const axis2_char_t *client_home = NULL;
    axis2_svc_client_t *svc_client = NULL;
    axiom_node_t *payload = NULL;
    axiom_node_t *ret_node = NULL;

    /* Set up the environment */
    env = axutil_env_create_all("helloworld.log", AXIS2_LOG_LEVEL_TRACE);

    /* Set end point reference of helloworld service */
    address = "http://localhost:9090/axis2/services/helloworld";

    /* Create EPR with given address */
    endpoint_ref = axis2_endpoint_ref_create(env, address);

    /* Setup options */
    options = axis2_options_create(env);
    axis2_options_set_to(options, env, endpoint_ref);
    axis2_options_set_action(options, env,
                             "http://ws.apache.org/axis2/c/samples/helloworldString");

    /* Set up deploy folder. It is from the deploy folder, the configuration is picked up
     * using the axis2.xml file. You need to set the AXIS2C_HOME variable to the axis2/c
     * installed dir.
     */
    client_home = AXIS2_GETENV("AXIS2C_HOME");
    if (!client_home || !strcmp(client_home, ""))
        client_home = "../..";

    /* Create service client */
    svc_client = axis2_svc_client_create(env, client_home);
    if (!svc_client)
    {
        /* reporting the error */
        printf
            ("Error creating service client, Please check AXIS2C_HOME again\\n");
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                        "Stub invoke FAILED: Error code:" " %d :: %s",
                        env->error->error_number,
                        AXIS2_ERROR_GET_MESSAGE(env->error));
        return -1;
    }

    /* Set service client options */
    axis2_svc_client_set_options(svc_client, env, options);

    /* Build the SOAP request message payload using OM API. */
    payload = build_om_payload_for_helloworld_svc(env);

    /* Send request */
    ret_node = axis2_svc_client_send_receive(svc_client, env, payload);

    if (ret_node)
    {
        /* extracting out the content from the response */
        axis2_char_t *om_str = NULL;
        om_str = axiom_node_to_string(ret_node, env);
        if (om_str)
            printf("\\nReceived OM : %s\\n", om_str);
        printf("\\nhelloworld client invoke SUCCESSFUL!\\n");

        AXIS2_FREE(env->allocator, om_str);
        ret_node = NULL;
    }
    else
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                        "Stub invoke FAILED: Error code:" " %d :: %s",
                        env->error->error_number,
                        AXIS2_ERROR_GET_MESSAGE(env->error));
        printf("helloworld client invoke FAILED!\\n");
    }

    /* freeing the allocated memory */
    if (svc_client)
    {
        axis2_svc_client_free(svc_client, env);
        svc_client = NULL;
    }

    if (env)
    {
        axutil_env_free((axutil_env_t *) env);
        env = NULL;
    }

    return 0;
}

Here is the implementation of the “build_om_payload_for_helloworld_svc” function that build the request SOAP message using Axiom/C. Note that axiom_element and axiom_node has one to one association. We use node to to navigate the XML, where as axiom_element to store the data.

/* build SOAP request message content using OM
           <ns1:greet xmlns:ns1="http://ws.apache.org/axis2/services/helloworld">
                <text>Hello World</text>
           </ns1:greet>
*/
axiom_node_t *
build_om_payload_for_helloworld_svc(
    const axutil_env_t * env)
{
    axiom_node_t *helloworld_om_node = NULL;
    axiom_element_t *helloworld_om_ele = NULL;
    axiom_node_t *text_om_node = NULL;
    axiom_element_t *text_om_ele = NULL;
    axiom_namespace_t *ns1 = NULL;
    axis2_char_t *om_str = NULL;

    ns1 =
       axiom_namespace_create(env, "http://ws.apache.org/axis2/services/helloworld",
                               "ns1");
    helloworld_om_ele =
        axiom_element_create(env, NULL, "greet", ns1, &helloworld_om_node);
    text_om_ele =
        axiom_element_create(env, helloworld_om_node, "text", NULL, &text_om_node);
    axiom_element_set_text(text_om_ele, env, "Hello World!", text_om_node);
    om_str = axiom_node_to_string(helloworld_om_node, env);

    if (om_str)
    {
        printf("\\nSending OM : %s\\n", om_str);
        AXIS2_FREE(env->allocator, om_str);
        om_str = NULL;
    }
    return helloworld_om_node;
}

So lets see how the same thing is done with C++. For C++ we use WSO2 WSF/C++

#include <stdio.h>
#include <WSSOAPClient.h>
#include <OMElement.h>
#include <iostream>
#include <AxisFault.h>
using namespace std;
using namespace wso2wsf;

OMElement build_om_payload_for_helloworld_svc();

int main()
{
    WSSOAPClient * sc = new WSSOAPClient("http://localhost:9090/axis2/services/helloworld");
    sc->initializeClient("helloworld_blocking.log", AXIS2_LOG_LEVEL_TRACE);
    {
        /* generating the payload */
        OMElement * payload = build_om_payload_for_helloworld_svc();

        OMElement * response;
        try
        {
            /* invoking the web service */
            response = sc->request(payload, "http://ws.apache.org/axis2/c/samples/helloworldString");

            /* printing the response */
            if (response)
            {
                cout << endl << "Response: " << response << endl;
            }
        }

        /* handling the fault */
        catch (AxisFault & e)
        {
            if (sc->getLastSOAPFault())
            {
                cout << endl << "Response: " << sc->getLastSOAPFault() << endl;
            }
            else
            {
                cout << endl << "Response: " << e << endl;
            }
        }
        delete payload;
    }
    delete sc;
}

You can see lines of code is reduced a lot. And you can see it from the code to build the request XML as well.

/* building the request soap message
   <ns1:greet xmlns:ns1="http://ws.apache.org/axis2/services/helloworld">
        <text>Hello World</text>
   </ns1:greet>
 */
OMElement build_om_payload_for_helloworld_svc()
{
    OMNamespace * ns = new OMNamespace("http://ws.apache.org/axis2/services/helloworld", "ns1");
    OMElement * payload = new OMElement(NULL,"greet", ns);
    OMElement * child = new OMElement(payload,"text", NULL);
    child->setText("Hello World!");

    return payload;
}

WSF/C++ is build on top of Axis2/C. You can see the WSF/C++ API is designed very carefully to make it easy to use without breaking the flexibility provided in the C API. So C++ developers can straightaway use WSF/C++ to develop their web service consumers. Anyway Axis2/C API still has the power of embedding easily in to scripting languages (Like it is done in WSF/PHP, WSF/Ruby) and probably deploy in legacy systems that doesn’t support C++ compiled binaries. So you have the options to select the most sutiable one for your application.


© 2007 Dimuthu’s Blog | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress