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.
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.