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.