Axis2C unofficial vs. Axis2C Staff

2.4k views Asked by At

I´m going to be developing an application that will be using some framework for SOAP based web services. I did some research and I kind of like Axis2C framework but here in some topics I found out that original Axis2C implementation suffered from memory leaks and that it´s official development has been stoped.

Luckily, there exists Axis2C unofficial branch and also Staff framework based on Axis2C. Now, the question is, which of this Axis2C descendants is better or easier to use? I know, that Staff wraps the Axis2C in C++, but I don´t mind plain C. Does Staff also fix the memory leaks?

Thanks for any advice.

2

There are 2 answers

2
loentar On BEST ANSWER

I can't tell you that work on Axis2/C has been stopped, it's keeping going but very-very slow. If you look into trunk repo, you can see only 5 commits in this year... Trunk version 1.7.0(unreleased) has many changes and new features, but release date is still not known.

Original Axis2/C-1.6.0 really have memory leaks and known issues, it's not suitable for production. Axis2/C-unofficial is based on original Axis2/C-1.6.0 and fixes most critical issues and gives other useful features. But unofficial branch, of course, has the same API as original, and you will take the same time to develop the service or client. It's not easier or harder in use.

If we talking about WSF Staff, it intended for fast developing of WEB services and clients. In contrast to Axis2/C you need to write only few lines of code to start your service or client working. You don't need to know about internal message structure: you working only with simple (bool, int, string, etc.) or complex (struct, typedef, std containers...) types (and of course you can have low-level access to message). Axis2/C has similar feature named ADB (Axis data binding) but it's done by C-way, and you need to write additional lines of code to get access to request and result.

Please note ADB (and generated services) has memory leaks, and it's not fixed in unofficial branch.

To compare what's easier in use - ADB or Staff I would like to give this example:

Note: you need to write the code between { and } by hand.

Axis2/C way of implementing the add operation of Calculator service WITHOUT ADB (traditional) from Axis2/C samples:

axiom_node_t *
axis2_calc_add(
    const axutil_env_t * env,
    axiom_node_t * node)
{
    axiom_node_t *param1_node = NULL;
    axiom_node_t *param1_text_node = NULL;
    axis2_char_t *param1_str = NULL;
    long int param1 = 0;
    axiom_node_t *param2_node = NULL;
    axiom_node_t *param2_text_node = NULL;
    axis2_char_t *param2_str = NULL;
    long int param2 = 0;

    if (!node)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INPUT_OM_NODE_NULL,
                        AXIS2_FAILURE);
        printf("Calculator client request ERROR: input parameter NULL\n");
        return NULL;
    }

    /* iterating to the first child element skipping (empty) text elements */
    for (param1_node = axiom_node_get_first_child(node, env);
         param1_node && axiom_node_get_node_type(param1_node, env) != AXIOM_ELEMENT;
         param1_node = axiom_node_get_next_sibling(param1_node, env));

    if (!param1_node)
    {
        AXIS2_ERROR_SET(env->error,
                        AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                        AXIS2_FAILURE);
        printf("Calculator service  ERROR: invalid XML in request\n");
        return NULL;
    }
    param1_text_node = axiom_node_get_first_child(param1_node, env);
    if (!param1_text_node)
    {
        AXIS2_ERROR_SET(env->error,
                        AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                        AXIS2_FAILURE);
        printf("Calculator service  ERROR: invalid XML in request\n");
        return NULL;
    }
    if (axiom_node_get_node_type(param1_text_node, env) == AXIOM_TEXT)
    {
        axiom_text_t *text =
            (axiom_text_t *) axiom_node_get_data_element(param1_text_node, env);
        if (text && axiom_text_get_value(text, env))
        {
            param1_str = (axis2_char_t *) axiom_text_get_value(text, env);
        }
    }
    else
    {
        AXIS2_ERROR_SET(env->error,
                        AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                        AXIS2_FAILURE);
        printf("Calculator service ERROR: invalid XML in request\n");
        return NULL;
    }

    /* iterating to the second child element skipping (empty) text elements */
    for (param2_node = axiom_node_get_next_sibling(param1_node, env);
         param2_node && axiom_node_get_node_type(param2_node, env) != AXIOM_ELEMENT;
         param2_node = axiom_node_get_next_sibling(param2_node, env));
    if (!param2_node)
    {
        AXIS2_ERROR_SET(env->error,
                        AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                        AXIS2_FAILURE);
        printf("Calculator service  ERROR: invalid XML in request\n");
        return NULL;
    }
    param2_text_node = axiom_node_get_first_child(param2_node, env);
    if (!param2_text_node)
    {
        AXIS2_ERROR_SET(env->error,
                        AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                        AXIS2_FAILURE);
        printf("Calculator service  ERROR: invalid XML in request\n");
        return NULL;
    }
    if (axiom_node_get_node_type(param2_text_node, env) == AXIOM_TEXT)
    {
        axiom_text_t *text =
            (axiom_text_t *) axiom_node_get_data_element(param2_text_node, env);
        if (text && axiom_text_get_value(text, env))
        {
            param2_str = (axis2_char_t *) axiom_text_get_value(text, env);
        }
    }
    else
    {
        AXIS2_ERROR_SET(env->error,
                        AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST,
                        AXIS2_FAILURE);
        printf("Calculator service ERROR: invalid XML in request\n");
        return NULL;
    }

    if (param1_str && param2_str)
    {
        long int result = 0;
        axis2_char_t result_str[255];

        axiom_element_t *ele1 = NULL;
        axiom_node_t *node1 = NULL,
            *node2 = NULL;
        axiom_namespace_t *ns1 = NULL;
        axiom_text_t *text1 = NULL;

        param1 = strtol(param1_str, NULL, 10);
        param2 = strtol(param2_str, NULL, 10);
        result = param1 + param2;
        sprintf(result_str, "%ld", result);

        ns1 = axiom_namespace_create(env,
                                     "http://axis2/test/namespace1", "ns1");
        ele1 = axiom_element_create(env, NULL, "result", ns1, &node1);
        text1 = axiom_text_create(env, node1, result_str, &node2);

        return node1;
    }

    AXIS2_ERROR_SET(env->error,
                    AXIS2_ERROR_SVC_SKEL_INVALID_OPERATION_PARAMETERS_IN_SOAP_REQUEST,
                    AXIS2_FAILURE);
    printf("Calculator service ERROR: invalid parameters\n");
    return NULL;
}

Axis2/C way of implementing the add operation of Calculator service WITH ADB from Axis2/C codegen samples:

    adb_addResponse_t * axis2_skel_Calculator_add(const axutil_env_t * env,
                                                    adb_add_t * add) 
{
    adb_addResponse_t * add_res = NULL;
    int ret_val = 0;
    int val1 = 0;
    int val2 = 0;
    val1 = adb_add_get_arg_0_0(add, env);
    val2 = adb_add_get_arg_1_0(add, env);
    ret_val = val1 + val2;
    add_res = adb_addResponse_create(env);
    adb_addResponse_set_addReturn(add_res, env, ret_val);
    return add_res;
}

Staff's way of implementing the add operation of Calculator service:

int CalculatorImpl::add(int param_1, int param_2)
{
  return param_1 + param_2;
}

Regarding codegenerating and compilation process it will be:

For Axis2/C:

# generate service from WSDL
WSDL2C.sh -uri Calculator.wsdl -u -ss -sd
# implement src/axis2_skel_Calculator.c
# compile and install
cd src
# build
sh build.sh
# install
sudo mkdir $AXIS2C_HOME/services/calculator
sudo cp lib*.so ../resources/*.xml $AXIS2C_HOME/services/calculator

For WSF Staff:

# generate service from WSDL
staff_codegen -pwsdl -tcomponent_all Calculator.wsdl
# implement src/CalculatorImpl.cpp
# build and install
make && sudo -E make install

Of course you can use WSF Staff on Axis2/C-unofficial to get all benefits from both.

1
rash.m2k On

Turns out just today I discovered Axis2c-unofficial while doing a google search, I'll need to check it out.

As for Axis2c (the WSO2 version), I'm currently using it in my mobile app (Qt based - Meego/BB10), chances are you will not want to write the code yourself but generate it from the WSDL file. Like loentar said the WSO2 version is really just a wrapper around Axis2c, but it does make it a bit easier to setup. I would say use the WSO2 version or use the unofficial one, I found the Axis2c tricky to compile (I was a total newbie to C/C++/Qt/SOAP and I was trying to cross compile it for Meego/BB10 - you can imagine how that went!), also remember STAFF is Qt based wrapper around it so thats another dependency.

Bottom line is USE the code generator but beware:

1 - the code generator has a 'rest of xml node' (can't remember the name of the method/name) but basically all xml it is unable to map goes into this node and you can run xpath queries against this. Sometimes however this node gets put BEFORE actual real node objects so the xml just gets dumped into this node and not the node object you actually want.

2 - The generated code is big - I mean really big! My mobile library is around 190mb and around 40mb without debug.

3 - The code gen is java so you can just use eclipse to have the code generate your code getters too!

The 3rd point is very important, personally I find this means I need to write even less code because each item in the XML is mapped to a string and from my QML code (GUI code) I simply address this string.

I may have gone off in a tangent - given a choice though I'd rather use Java though to generate the code (better support), hopefully this helps though.

Response to JeFf:

In my woes to try and compile WSO2 for BB10, i realised that WSO2 simply includes the Axis2c folder, it compile the various asix2c libs first (I think it does it first), and then the WSO2 libs (sandesh, savan etc.), I was fortunate that all I really wanted was the XML serialisation/deserialsation of the WSDL and not really any advanced soap features (I certainly don't know much about soap other than the very basics).

It MAY be possible to simply replace the axis2c libs with the unofficial libs, assuming the header files/api is exactly the same. Or even simply drop the unofficial folder over the official one.

I myself have to compile the binaries in eclipse first (BB10 SDK), it's a long and arduous task, but unlike Nokias Meego SDK there is no cross compilation tool for BB10, in Meego it was very simple I had to make zero changes.