| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><title>Axis2/C - Axis2/C User's Guide</title><style type="text/css" media="all"> |
| @import url("../style/maven-base.css"); |
| |
| @import url("../style/maven-classic.css");</style><link rel="stylesheet" href="../style/print.css" type="text/css" media="print"></link><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"></meta></head><body class="composite"><div id="banner"><a href="http://www.apache.org/" id="organizationLogo"><img alt="Apache Software Foundation" src="http://www.apache.org/images/asf-logo.gif"></img></a><a href="http://ws.apache.org/axis2/c" id="projectLogo"><img alt="Apache Axis2 C" src="http://ws.apache.org/axis2/images/axis.jpg"></img></a><div class="clear"><hr></hr></div></div><div id="breadcrumbs"><div class="xleft"> |
| Last published: 22 December 2006 |
| | Doc for 0.96</div><div class="xright"></div><div class="clear"><hr></hr></div></div><div id="leftColumn"><div id="navcolumn"><div id="menuAxis2_C"><h5>Axis2/C</h5><ul><li class="none"><a href="../index.html">Home</a></li><li class="expanded"><a href="../download.cgi">Download Axis2/C</a><ul><li class="none"><a href="../download.cgi">Releases</a></li><li class="none"><a href="http://svn.apache.org/viewvc/axis/axis2/c/core/trunk/" class="externalLink" title="External Link">View Source Code Online</a></li><li class="none"><a href="../svn.html">Checkout Source Code</a></li></ul></li><li class="expanded"><a href="../docs/index.html">Documentation</a><ul><li class="none"><a href="../docs/installationguide.html">Installation Guide</a></li><li class="none"><a href="../docs/developerguide.html">Developer Guide</a></li><li class="none"><a href="../docs/userguide.html">User Guide</a></li><li class="none"><a href="../docs/axis2c_manual.html">Axis2/C manual</a></li></ul></li><li class="expanded"><a href="../mail-lists.html">Get Involved</a><ul><li class="none"><a href="../mail-lists.html">Mailing Lists</a></li></ul></li><li class="expanded"><a href="../team-list.html">Project Information</a><ul><li class="none"><a href="../team-list.html">Project Team</a></li><li class="none"><a href="../issue-tracking.html">Issue Tracking</a></li></ul></li></ul></div><a href="http://maven.apache.org/" title="Built by Maven" id="poweredBy"><img alt="Built by Maven" src="../images/logos/maven-button-1.png"></img></a></div></div><div id="bodyColumn"><div class="contentBox"><div class="section"><a name="Apache_Axis2_C_User_s_Guide"></a><h2>Apache Axis2/C User's Guide</h2><div class="subsection"><a name="Content"></a><h3>Content</h3><ul> |
| <li><p><a href="#Introduction">Introduction</a></p> |
| <ul> |
| <li><a href="#What_is_Axis2_">What is Axis2/C?</a></li> |
| </ul> |
| </li> |
| <li><a href="#Web_Services_Using_Axis2">Web Services Using Axis2/C</a> |
| <ul> |
| <li><a href="#Writing_Web_Services_Using_Axis2_C">Writing Web Services |
| Using Axis2/C</a> |
| <ul> |
| <li><a href="#Creating_Web_Service__MyService_">Creating Web |
| Service (Echo service)</a></li> |
| <li><a href="#How_to_write_the_Web_Service_">How to write the Web |
| Service?</a> |
| <ul> |
| <li><a href="#Step1">Step1 :Write the echo_skeleton.c file |
| implementing the axis2_svc_skeleton.h</a></li> |
| <li><a href="#Step2">Step2 :Now we can write the echo service |
| in a file echo.c</a></li> |
| <li><a href="#Step3">Step3 :Write the services.xml file</a></li> |
| <li><a href="#Step4">Step4 :Create the Web Service |
| Folder</a></li> |
| <li><a href="#Step5">Step5 :Archive based deployment |
| model</a></li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li><a href="#Writing_Web_Services_Using_Code_Generator">Writing Web |
| Services Skeleton Using Code Generator</a> |
| <ul> |
| <li><a href="#WSDL2C_tool">WSDL2C tool</a></li> |
| <li><a href="#Implement_the_Business_Logic">Implement the Business |
| Logic</a></li> |
| <li><a href="#echoString">echoString</a></li> |
| <li><a href="#echoStringArray">echoStringArray</a></li> |
| <li><a href="#echoStruct">echoStruct</a></li> |
| <li><a href="#services_xml">services.xml</a></li> |
| </ul> |
| </li> |
| <li><a href="#deploy">Deploy the Web Service</a></li> |
| </ul> |
| </li> |
| <li><p><a href="#Web_Service_Clients_Using_Axis2">Web Service Clients Using |
| Axis2/C</a></p> |
| <ul> |
| <li><a href="#Writing_Web_Service_Clients_using_Axis2%27s_Primary_APIs">Writing |
| Web Service Clients Using Axis2's Primary APIs</a> |
| <ul> |
| <li><a href="#EchoBlockingClient">echo_blocking Client</a></li> |
| <li><a href="#EchoNonBlockingClient">echo_non_blocking |
| Client</a></li> |
| <li><a href="#EchoNonBlockingDualClient">echo_non_blocking_dual |
| Client</a></li> |
| <li><a href="#EchoBlockingDualClient">echo_blocking_dual |
| Client</a></li> |
| </ul> |
| </li> |
| <li><a href="#Writing_Web_Clients_Using_Code_Generator">Writing Web |
| Service Clients using Code Generation with Data Binding Support</a> |
| <ul> |
| <li><a href="#Codegenerator_Client_echoString">Client for |
| echoString operation</a></li> |
| <li><a href="#Codegenerator_Client_echoStringArray">Client for |
| echoStringArray operation</a></li> |
| <li><a href="#Codegenerator_Client_echoStruct">Client for |
| echoStruct operation</a></li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li><p><a href="#Providing_security_using_Rampart">Providing security using |
| Rampart/C</a></p> |
| <ul> |
| <li><a href="#Engaging_rampart_module">Engaging rampart module</a></li> |
| <li><a href="#Semantics_of_parameters_specified_in_axis2_xml">Semantics |
| of parameters specified in axis2.xml</a></li> |
| <li><a href="#Writing_own_password_callback_module">Writing own |
| password callback module</a></li> |
| <li><a href="#Adding_security_parameters_dynamically">Adding security |
| parameters dynamically</a></li> |
| </ul> |
| </li> |
| </ul><p><a id="Introduction"></a></p></div><div class="subsection"><a name="Introduction"></a><h3>Introduction</h3><p>Welcome to Axis2/C, the Apache Axis2 implementation in C. This User's Guide |
| will help you understand what Axis2/C has to offer and how to get started |
| with it.</p><p><a id="What_is_Axis2_"></a></p></div><div class="subsection"><a name="What_is_Axis2_C_"></a><h3>What is Axis2/C?</h3><p>Axis2/C is an effort to implement the <a href="http://ws.apache.org/axis2/1_0/Axis2ArchitectureGuide.html" class="externalLink" title="External Link">Axis2 |
| architecture</a> in C programming language. For more information on the |
| architecture <a href="architecture_notes.html">C Specific Architectural |
| Notes</a> are also available.</p><p>After months of continued discussion and coding in this direction, Axis2/C |
| now delivers the following key features:</p><ul> |
| <li><p style="margin-bottom: 0in;"><strong>Speed</strong> - Axis2/C uses |
| its own XML object model and StAX (Streaming API for XML) parsing to |
| achieve significant speed. In addition to that, Axis2/C is inherently |
| benefited by the speed of its implementation language, namely C, compared |
| to Java implementation.</p> |
| </li> |
| <li><p style="margin-bottom: 0in;"><strong>Low memory foot print</strong>- |
| Axis2 architecture was designed ground-up keeping in mind the low memory foot |
| print. Axis2/C strives to achieve the same with a well designed |
| memory management strategy.</p> |
| </li> |
| <li><p style="margin-bottom: 0in;"><strong>AXIOM/C</strong>- Axis2/C comes |
| with its own light-weight object model for XML, AXIOM/C which is the C |
| implementation of <a href="http://ws.apache.org/commons/axiom/OMTutorial.html" class="externalLink" title="External Link">AXIOM</a>.</p> |
| </li> |
| <li><p style="margin-bottom: 0in;"><strong>MEP Support</strong> - Supports |
| Message Exchange Patterns (MEPs)</p> |
| </li> |
| <li><p style="margin-bottom: 0in;"><strong>Flexibility</strong> - Axis2/C |
| architecture gives the developer complete freedom to insert |
| extensions into the engine (using modules and handlers) for custom SOAP |
| header processing.</p> |
| </li> |
| <li><p style="margin-bottom: 0in;"><strong>Transport Framework</strong> - |
| We have a clean and simple abstraction for integrating and using |
| transports, and the core of the engine is completely |
| transport-independent.</p> |
| </li> |
| <li><p style="margin-bottom: 0in;"><strong>Composition and |
| Extensibility</strong> - Modules and phases improve support for |
| composability and extensibility. Modules support composability and are |
| able to add support for new WS-* specifications in a simple and clean |
| manner. They are however, not hot deployable as they change the overall |
| behavior of the system.</p> |
| </li> |
| </ul><p>Axis2/C team is working hard to continuously improve the implementation. |
| Please note that this is an open-source effort. If you feel you have some |
| time to spare, please get involved and lend us a hand! The Axis2/C developer |
| community welcomes your participation and contributions.</p><p>Let us know what you think! Please send your feedback on Axis2/C to "<a href="mailto:axis-user@ws.apache.org">axis-c-user@ws.apache.org</a>" and |
| please remember to prefix the subject of the mail with [Axis2].</p><p>The following sections will guide on how to write Web service |
| clients and services.</p><p><a name="Web_Services_Using_Axis2"></a></p></div><div class="subsection"><a name="Web_Services_Using_Axis2_C"></a><h3>Web Services Using Axis2/C</h3><p>Before starting, please make sure that you have installed Axis2/C |
| correctly and whether you can run the axis2_http_server located in |
| AXIS2C_HOME/bin (See <a href="installationguide.html">Installation Guide</a> |
| for details).</p><p><a name="Writing_Web_Services_Using_Axis2_C"></a></p></div><div class="subsection"><a name="Writing_Web_Services_Using_Axis2_C"></a><h3>Writing Web Services Using Axis2/C</h3><p><a id="Creating_Web_Service__MyService_"></a></p></div><div class="subsection"><a name="Creating_Web_Service__Echo_service_"></a><h3>Creating Web Service (Echo service)</h3><p>First let's see how we can write a simple Web Service (echo service) using |
| Axis2/C's primary interfaces and how to deploy it. For this purpose we will |
| create a Web Service with one operation as follows.</p> |
| <div class="source"><pre> |
| axiom_node_t* axis2_echo_echo(axiom_node_t *echo_node){} |
| |
| </pre></div> |
| <p>You can have a peek at the complete source code for this example echo |
| service located in the "AXIS2C_HOME/samples/server/echo" directory.</p><p><a id="How_to_write_the_Web_Service_"></a></p></div><div class="subsection"><a name="How_to_write_the_Web_Service_"></a><h3>How to write the Web Service?</h3><p>Writing a new Web Service with Axis2/C involves four steps. Let's take echo |
| service as our example.</p><ol> |
| <li><p style="margin-bottom: 0in;">Write a echo_skeleton.c file which |
| implements the API given in axis2_svc_skeleton.h header file.</p> |
| </li> |
| <li>Write the service implementation source file (in this case echo.c |
| service) which implements the actual business logic.</li> |
| <li>Write a services.xml file to explain the Web service.</li> |
| <li>Create a folder with the service name under AXIS2C_HOME/services and |
| put the compiled service ( .dll or .so file) for the Web service and |
| services.xml file into that folder.</li> |
| </ol><p><a name="Step1"></a></p></div><div class="subsection"><a name="Step1_:Write_the_echo_skeleton_c_file_implementing_the_axis2_svc_skeleton_h"></a><h3>Step1 :Write the echo_skeleton.c file implementing the axis2_svc_skeleton.h</h3><p>axis2_svc_skeleton.h header file has the axis2_svc_skeleton_ops_t |
| operations struct which defines four function pointers to be implemented and |
| assigned by a service skeleton.</p><p>They are:</p> |
| <div class="source"><pre> |
| int (AXIS2_CALL * init) (axis2_svc_skeleton_t *svc_skeleton, |
| const axis2_env_t *env); |
| |
| axiom_node_t * (AXIS2_CALL* invoke)(axis2_svc_skeleton_t *svc_skeli, |
| const axis2_env_t *env, axiom_node_t *node); |
| |
| axiom_node_t *(AXIS2_CALL* on_fault)(axis2_svc_skeleton_t *svc_skeli, |
| const axis2_env_t *env, axiom_node_t *node); |
| |
| int (AXIS2_CALL *free)(axis2_svc_skeleton_t *svc_skeli, |
| const axis2_env_t *env); |
| |
| </pre></div> |
| <p>Let's implement the above functions for echo service.</p><p><i><code>/* Initialize the service */</code></i><br></br> |
| <code>int AXIS2_CALL</code><br></br> |
| <code>echo_init(axis2_svc_skeleton_t *svc_skeleton,</code><br></br> |
| <code> const axis2_env_t *env)</code><br></br> |
| <code>{</code><br></br> |
| <code> svc_skeleton->func_array = axis2_array_list_create(env, 0);</code><br></br> |
| <code> </code><i><code>/* Add the implemented operation names of the service to </code><br></br> |
| <code> * the array list of functions </code><br></br> |
| <code> */</code></i><br></br> |
| <code> AXIS2_ARRAY_LIST_ADD(svc_skeleton->func_array, env, "echoString");</code><br></br> |
| <code> </code><i><code>/* Any initialization stuff of echo service should go here */</code></i><br></br> |
| <code> </code><b><code>return</code></b><code> AXIS2_SUCCESS;</code><br></br> |
| <code>}</code><br></br> |
| <br></br> |
| <i><code>/*</code><br></br> |
| <code> * This method invokes the right service method </code><br></br> |
| <code> */</code></i><br></br> |
| <code>axiom_node_t* AXIS2_CALL</code><br></br> |
| <code>echo_invoke(axis2_svc_skeleton_t *svc_skeleton,</code><br></br> |
| <code> const axis2_env_t *env,</code><br></br> |
| <code> axiom_node_t *node)</code><br></br> |
| <code>{</code><br></br> |
| <code> </code><i><code>/* Invoke the business logic.</code><br></br> |
| <code> * Depending on the function name invoke the correct impl method.</code><br></br> |
| <code> * We have only echo in this sample, hence invoke echo method.</code><br></br> |
| <code> * To see how to deal with multiple impl methods, have a look at the</code><br></br> |
| <code> * math sample.</code><br></br> |
| <code> */</code></i><br></br> |
| <code> </code><b><code>return</code></b><code> axis2_echo_echo(env, node);</code><br></br> |
| <code>}</code><br></br> |
| <br></br> |
| <i><code>/* On fault, handle the fault */</code></i><br></br> |
| <code>axiom_node_t* AXIS2_CALL</code><br></br> |
| <code>echo_on_fault(axis2_svc_skeleton_t *svc_skeli, </code><br></br> |
| <code> const axis2_env_t *env, axiom_node_t *node)</code><br></br> |
| <code>{</code><br></br> |
| <code> </code><i><code>/* Here we are just setting a simple error message inside an element </code><br></br> |
| <code> * called 'EchoServiceError' </code><br></br> |
| <code> */</code></i><br></br> |
| <code> axiom_node_t *error_node = NULL;</code><br></br> |
| <code> axiom_node_t* text_node = NULL;</code><br></br> |
| <code> axiom_element_t *error_ele = NULL;</code><br></br> |
| <code> error_ele = axiom_element_create(env, node, "EchoServiceError", NULL, </code><br></br> |
| <code> &error_node);</code><br></br> |
| <code> AXIOM_ELEMENT_SET_TEXT(error_ele, env, "Echo service failed ", </code><br></br> |
| <code> text_node);</code><br></br> |
| <code> </code><b><code>return</code></b><code> error_node;</code><br></br> |
| <code>}</code><br></br> |
| <br></br> |
| <i><code>/* Free the resources used */</code></i><br></br> |
| <code>int AXIS2_CALL</code><br></br> |
| <code>echo_free(axis2_svc_skeleton_t *svc_skeleton,</code><br></br> |
| <code> const axis2_env_t *env)</code><br></br> |
| <code>{</code><br></br> |
| <code> </code><i><code>/* Free the function array */</code></i><br></br> |
| <code> </code><b><code>if</code></b><code>(svc_skeleton->func_array)</code><br></br> |
| <code> {</code><br></br> |
| <code> AXIS2_ARRAY_LIST_FREE(svc_skeleton->func_array, env);</code><br></br> |
| <code> svc_skeleton->func_array = NULL;</code><br></br> |
| <code> }</code><br></br> |
| <code> </code><br></br> |
| <code> </code><i><code>/* Free the function array */</code></i><br></br> |
| <code> </code><b><code>if</code></b><code>(svc_skeleton->ops)</code><br></br> |
| <code> {</code><br></br> |
| <code> AXIS2_FREE(env->allocator, svc_skeleton->ops);</code><br></br> |
| <code> svc_skeleton->ops = NULL;</code><br></br> |
| <code> }</code><br></br> |
| <code> </code><br></br> |
| <code> </code><i><code>/* Free the service skeleton */</code></i><br></br> |
| <code> </code><b><code>if</code></b><code>(svc_skeleton)</code><br></br> |
| <code> {</code><br></br> |
| <code> AXIS2_FREE(env->allocator, svc_skeleton);</code><br></br> |
| <code> svc_skeleton = NULL;</code><br></br> |
| <code> }</code><br></br> |
| <br></br> |
| <code> </code><b><code>return</code></b><code> AXIS2_SUCCESS; </code><br></br> |
| <code>}</code><br></br> |
| </p><p></p><p>Now we can write the <code>create</code> function of the |
| echo_service_skeleton as follows:</p><p><i><code>/*Create function */</code><br></br> |
| </i><code>axis2_svc_skeleton_t *</code><br></br> |
| <code>axis2_echo_create(const axis2_env_t *env)</code><br></br> |
| <code>{</code><br></br> |
| <code> axis2_svc_skeleton_t *svc_skeleton = NULL;</code><br></br> |
| <code> </code><i><code>/* Allocate memory for the structs */</code></i><br></br> |
| <code> svc_skeleton = AXIS2_MALLOC(env->allocator, </code><br></br> |
| <code> </code><b><code>sizeof</code></b><code>(axis2_svc_skeleton_t));</code><br></br> |
| <br></br> |
| <code> svc_skeleton->ops = AXIS2_MALLOC(</code><br></br> |
| <code> env->allocator, </code><b><code>sizeof</code></b><code>(axis2_svc_skeleton_ops_t));</code><br></br> |
| <br></br> |
| <code> </code><i><code>/* Assign function pointers */</code></i><br></br> |
| <code> svc_skeleton->ops->free = echo_free;</code><br></br> |
| <code> svc_skeleton->ops->init = echo_init;</code><br></br> |
| <code> svc_skeleton->ops->invoke = echo_invoke;</code><br></br> |
| <code> svc_skeleton->ops->on_fault = echo_on_fault;</code><br></br> |
| <br></br> |
| <code> </code><b><code>return</code></b><code> svc_skeleton;</code><br></br> |
| <code>}</code></p><p>In addition to the above functions, every service must have the following |
| two functions with exactly the same function signature as in xxx_skeleton.c |
| file.</p><p><code>AXIS2_EXPORT int </code><br></br> |
| <code>axis2_get_instance(axis2_svc_skeleton_t **inst,</code><br></br> |
| <code> const axis2_env_t *env)</code><br></br> |
| <code>{</code><br></br> |
| <code> *inst = axis2_echo_create(env);</code><br></br> |
| <code> </code><b><code>if</code></b><code>(!(*inst))</code><br></br> |
| <code> {</code><br></br> |
| <code> </code><b><code>return</code></b><code> AXIS2_FAILURE;</code><br></br> |
| <code> }</code><br></br> |
| <code> </code><b><code>return</code></b><code> AXIS2_SUCCESS;</code><br></br> |
| <code>}</code><br></br> |
| <br></br> |
| <code>AXIS2_EXPORT int </code><br></br> |
| <code>axis2_remove_instance(axis2_svc_skeleton_t *inst,</code><br></br> |
| <code> const axis2_env_t *env)</code><br></br> |
| <code>{</code><br></br> |
| <code> axis2_status_t status = AXIS2_FAILURE;</code><br></br> |
| <code> </code><b><code>if</code></b><code> (inst)</code><br></br> |
| <code> {</code><br></br> |
| <code> status = AXIS2_SVC_SKELETON_FREE(inst, env);</code><br></br> |
| <code> }</code><br></br> |
| <code> </code><b><code>return</code></b><code> status;</code><br></br> |
| }<br></br> |
| </p><p></p><p>Axis2/C engine can load the service dll. However, it needs to know which |
| method to call. Since C does not have reflection, we need to have some dll |
| exposing functions known to Axis2/C engine. |
| <b><code>axis2_get_instance</code></b> and |
| <b><code>axis2_remove_instance</code></b> are the two functions that need to |
| be exposed from a service dll (or any other dll of Axis2/C engine). Axis2/C |
| engine calls <code>axis2_get_instance</code> method, which creates a new |
| service instance, and casts the return pointer to |
| <code>axis2_svc_skeleton</code> interface. Then, the interface methods can be |
| called by Axis2/C engine.</p><p><a name="Step2"></a></p></div><div class="subsection"><a name="Step2_:_Now_we_can_write_the_echo_service_in_a_file_echo_c"></a><h3>Step2 : Now we can write the echo service in a file echo.c</h3><p><code>axiom_node_t *</code><br></br> |
| <code>axis2_echo_echo (const axis2_env_t *env, axiom_node_t *node)</code><br></br> |
| <code>{</code><br></br> |
| <code> axiom_node_t *text_parent_node = NULL;</code><br></br> |
| <code> axiom_node_t *text_node = NULL;</code><br></br> |
| <code> axiom_node_t *ret_node = NULL;</code><br></br> |
| <br></br> |
| <code> AXIS2_ENV_CHECK(env, NULL);</code><br></br> |
| <code> </code><br></br> |
| <code> </code><i><code>/* Expected request format is :-</code><br></br> |
| <code> * <ns1:echoString xmlns:ns1="http://localhost:9090/axis2/services/echo"></code><br></br> |
| <code> * <text>echo5</text></code><br></br> |
| <code> * </ns1:echoString></code><br></br> |
| <code> */</code></i><br></br> |
| <code> </code><b><code>if</code></b><code> (!node) </code><i><code>/* 'echoString' node */</code></i><br></br> |
| <code> {</code><br></br> |
| <code> AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INPUT_OM_NODE_NULL, AXIS2_FAILURE);</code><br></br> |
| <code> printf("Echo client ERROR: input parameter NULL\n");</code><br></br> |
| <code> </code><b><code>return</code></b><code> NULL;</code><br></br> |
| <code> }</code><br></br> |
| <br></br> |
| <code> text_parent_node = AXIOM_NODE_GET_FIRST_CHILD(node, env);</code><br></br> |
| <code> </code><b><code>if</code></b><code> (!text_parent_node) </code><i><code>/* 'text' node */</code></i><br></br> |
| <code> {</code><br></br> |
| <code> AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST, AXIS2_FAILURE);</code><br></br> |
| <code> printf("Echo client ERROR: invalid XML in request\n");</code><br></br> |
| <code> </code><b><code>return</code></b><code> NULL;</code><br></br> |
| <code> }</code><br></br> |
| <code> </code><br></br> |
| <code> text_node = AXIOM_NODE_GET_FIRST_CHILD(text_parent_node, env);</code><br></br> |
| <code> </code><b><code>if</code></b><code> (!text_node) </code><i><code>/* actual text to echo */</code></i><br></br> |
| <code> {</code><br></br> |
| <code> AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST, AXIS2_FAILURE);</code><br></br> |
| <code> printf("Echo client ERROR: invalid XML in request\n");</code><br></br> |
| <code> </code><b><code>return</code></b><code> NULL;</code><br></br> |
| <code> }</code><br></br> |
| <code> </code><br></br> |
| <code> </code><b><code>if</code></b><code> (AXIOM_NODE_GET_NODE_TYPE(text_node, env) == AXIOM_TEXT)</code><br></br> |
| <code> {</code><br></br> |
| <code> axiom_text_t *text = (axiom_text_t *)AXIOM_NODE_GET_DATA_ELEMENT(text_node, env);</code><br></br> |
| <code> </code><b><code>if</code></b><code>( text && AXIOM_TEXT_GET_VALUE(text , env))</code><br></br> |
| <code> {</code><br></br> |
| <code> axis2_char_t *text_str = AXIOM_TEXT_GET_VALUE(text, env);</code><br></br> |
| <code> printf("Echoing text value %s \n", text_str);</code><br></br> |
| <code> ret_node = build_om_programatically(env, text_str);</code><br></br> |
| <code> }</code><br></br> |
| <code> }</code><br></br> |
| <code> </code><b><code>else</code></b><br></br> |
| <code> {</code><br></br> |
| <code> AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST, AXIS2_FAILURE);</code><br></br> |
| <code> printf("Echo client ERROR: invalid XML in request\n");</code><br></br> |
| <code> </code><b><code>return</code></b><code> NULL;</code><br></br> |
| <code> }</code><br></br> |
| <code> </code><br></br> |
| <code> </code><b><code>return</code></b><code> ret_node;</code><br></br> |
| <code>}</code><br></br> |
| <br></br> |
| <i><code>/* Builds the response content */</code></i><br></br> |
| <code>axiom_node_t *</code><br></br> |
| <code>build_om_programatically(const |
| axis2_env_t *env, axis2_char_t *text)</code><br></br> |
| <code>{</code><br></br> |
| <code> axiom_node_t *echo_om_node = NULL;</code><br></br> |
| <code> axiom_element_t* echo_om_ele = NULL;</code><br></br> |
| <code> axiom_node_t* text_om_node = NULL;</code><br></br> |
| <code> axiom_element_t * text_om_ele = NULL;</code><br></br> |
| <code> axiom_namespace_t *ns1 = NULL;</code><br></br> |
| <code> </code><br></br> |
| <code> ns1 = axiom_namespace_create (env, "http://localhost:9090/axis2/services/echo", "ns1");</code><br></br> |
| <br></br> |
| <code> echo_om_ele = axiom_element_create(env, NULL, "echoString", ns1, &echo_om_node);</code><br></br> |
| <code> </code><br></br> |
| <code> text_om_ele = axiom_element_create(env, echo_om_node, "text", NULL, &text_om_node);</code><br></br> |
| <br></br> |
| <code> AXIOM_ELEMENT_SET_TEXT(text_om_ele, env, text, text_om_node);</code><br></br> |
| <code> </code><br></br> |
| <code> </code><b><code>return</code></b><code> echo_om_node;</code><br></br> |
| <code>}</code><br></br> |
| </p><p><a name="Step3"></a></p></div><div class="subsection"><a name="Step3_:Write_the_services_xml_file"></a><h3>Step3 :Write the services.xml file</h3><p>Axis2/C uses "services.xml" file to keep configurations of a Web service. |
| Each Web service deployed in Axis2/C needs a "services.xml" file containing |
| the configurations. Note that services.xml has the same semantics as Axis2 |
| Java's services.xml file. Only difference is that instead of giving package |
| qualified class name, we use the dll name for class attributes.</p><p>"services.xml" for echo will be as follows:</p><code class="code"><service name="echo"><br></br> <parameter name="ServiceClass" locked="xsd:false">echo</parameter><br></br> <description><br></br> This is a echo service<br></br> </description><br></br><br></br> <operation name="echoString"><br></br> <parameter name="wsamapping"><br></br> http://localhost:9090/axis2/services/echo/echoString<br></br> </parameter><br></br> </operation><br></br></service></code><p>Name of the service will be the name of the folder with the shared library |
| and services.xml. In this example we will have a folder named |
| "echo" in which we have the echo.dll (or libecho.so on Linux platform) and |
| services.xml file.</p><p>You can write a services.xml file to include a group of services instead |
| of a single service. This makes management and deployment of a set of related |
| services very easy. At runtime you can share information between these |
| services within a single interaction using the <code>axis2_svc_grp_ctx</code> |
| (Service Group Context ). If you hope to use this functionality, the |
| services.xml file should have following format:<br></br> |
| </p><code class="code"><serviceGroup><br></br> <service name="Service1"><br></br> <!-- details for Service1 --><br></br> </service><br></br> <service name="Service2"><br></br> <!-- details for Service2 --><br></br> </service><br></br> <module ref="ModuleName" /><br></br> <parameter name="serviceGroupParam1" locked="false">value 1</parameter><br></br></serviceGroup></code><p><strong>Note :</strong> Name of the service is a compulsory attribute</p><p><a name="Step4"></a></p></div><div class="subsection"><a name="Step4_:Create_the_Web_service_folder_in_services_folder_of_the_repository_"></a><h3>Step4 :Create the Web service folder in services folder of the repository.</h3><p>In Axis2/C , it is required to create a folder with the corresponding |
| service/service group name which will contain the shared library (compiled |
| service) and the services.xml file which describes the Web service. So for |
| this example, we will have to create a folder named "echo", which contains |
| the services.xml file and echo dll.</p><p><a name="Step5"></a></p></div><div class="subsection"><a name="Step5_:Archive_Based_Deployment_Model"></a><h3>Step5 :Archive Based Deployment Model</h3><p>Axis2 uses ".aar" (Axis Archive) file as the deployment package for the |
| Web services. Therefore, for echo service we will use "echo.aar". Note that |
| the name of the service will be the name of the archive file. To create |
| "echo.aar" user can create a zip file containing echo.so and services.xml and |
| rename the zip extension to aar. Then Axis2 understands it as a service |
| archive.</p><p><a name="Writing_Web_Services_Using_Code_Generator"></a></p></div><div class="subsection"><a name="Writing_Web_Services_Skeleton_Using_Code_Generator"></a><h3>Writing Web Services Skeleton Using Code Generator</h3><p><a id="WSDL2C_tool"></a></p></div><div class="subsection"><a name="WSDL2C_tool"></a><h3>WSDL2C tool</h3><p>Axis2/Java WSDL2C tool supports generation of Axis2/C stub and |
| skeleton. <a href="http://svn.apache.org/viewvc/webservices/axis2/trunk/java" class="externalLink" title="External Link">Axis2/Java |
| SVN</a> revision 414253 and later versions provide this facility. A basic |
| guide for the tool can be found <a href="http://ws.apache.org/axis2/1_0/userguide2.html#Writing_Web_Services_by_Code_Generating_Skeleton" class="externalLink" title="External Link">here.</a></p><p>We will run the tool with the following parameters and generate the |
| skeleton and other required files to support ADB (Axis Data Binding). In |
| order to run the tool, <span style="font-weight: bold;">set all the .jar |
| library files in the Axis2/Java to the classpath</span>. To generate code |
| with no data binding support, just replace -d adb -u with -d none</p> |
| <div class="source"><pre> |
| java org.apache.axis2.wsdl.WSDL2C -uri interoptestdoclitparameters.wsdl -ss -sd -d adb -u |
| |
| |
| </pre></div> |
| <p>If you need an XML in/out programming model, you can just ignore the data |
| binding support by setting the following parameters. |
| <pre>java org.apache.axis2.wsdl.WSDL2C -uri interoptestdoclitparameters.wsdl -ss -sd -d none</pre> |
| |
| </p><p>The WSDL <code>interoptestdoclitparameters.wsdl</code> can be found in |
| <axis2_src_dir>/test/resources directory. This is used to generate stub |
| and skeleton code throughout this User's Guide.</p><p><a id="Implement_the_Business_Logic"></a></p></div><div class="subsection"><a name="Implement_the_Business_Logic"></a><h3>Implement the Business Logic</h3><p> |
| Locate the skeleton source file from the generated files: |
| "<code>axis2_WSDLInteropTestDocLitService.c</code>". You can go through the |
| rest of the guide to add the business logic to the following operations in |
| the WSDL. |
| <ul> |
| <li>echoString - Operation that echoes a String value.</li> |
| <li>echoStringArray - Operation that accepts a string array as the input and |
| echoes them back.</li> |
| <li>echoStruct - Operation that accepts a Struct as the input and echoes |
| them back.</li> |
| </ul></p><p>Complete skeleton source file for the above operations can be found under |
| <axis2_src_dir>/samples/codegen/server/interop_doc2 directory with the |
| name "<code>axis2_WSDLInteropTestDocLitService.c</code>".</p><p><a id="echoString"></a></p></div><div class="subsection"><a name="echoString"></a><h3>echoString</h3><p>If you generate the code with data binding support, you will find the |
| following code segment in the |
| "<code>axis2_WSDLInteropTestDocLitService.c</code>". Fill the business logic |
| inside this function as shown below:</p> |
| <div class="source"><pre> |
| axis2_echoStringResponse_t* |
| axis2_WSDLInteropTestDocLitService_echoString |
| (const axis2_env_t* env ,axis2_echoString_t* param6 ) |
| { |
| /* Todo fill this with the necessary business logic *} |
| |
| |
| </pre></div> |
| <p>Once the business logic is filled, it will be as follows. The code is |
| simple and the inline comments provide explanation.</p> |
| <div class="source"><pre> |
| axis2_echoStringResponse_t* |
| axis2_WSDLInteropTestDocLitService_echoString |
| (const axis2_env_t* env ,axis2_echoString_t* param6 ) |
| { |
| axis2_echoString_t* echo_in = param6; |
| axis2_echoStringResponse_t* echo_out = NULL; |
| |
| char* echo_string = NULL; |
| |
| /* retrieve the string input */ |
| echo_string = AXIS2_ECHOSTRING_GET_PARAM0 ( echo_in, env ); |
| |
| /* create the response and set the output string */ |
| echo_out = axis2_echoStringResponse_create ( env ); |
| AXIS2_ECHOSTRUCTRESPONSE_SET_RETURN ( echo_out, env, echo_string ); |
| |
| return echo_out; |
| } |
| |
| </pre></div> |
| </div><div class="subsection"><a name="echoStringArray"></a><h3>echoStringArray</h3> |
| <div class="source"><pre> |
| axis2_echoStringArrayResponse_t* |
| axis2_WSDLInteropTestDocLitService_echoStringArray |
| (const axis2_env_t* env ,axis2_echoStringArray_t* param2 ) |
| |
| { |
| axis2_echoStringArray_t* echo_in = param2; |
| axis2_echoStringArrayResponse_t* echo_out = NULL; |
| axis2_ArrayOfstring_literal_t* array_in = NULL; |
| axis2_ArrayOfstring_literal_t* array_out = NULL; |
| char ** string_array = NULL; |
| int string_array_length = 0; |
| |
| /* retrieve the array from input*/ |
| array_in = AXIS2_ECHOSTRINGARRAY_GET_PARAM0( echo_in, env); |
| /* retrieve the string_array and array length */ |
| string_array = |
| AXIS2_ARRAYOFSTRING_LITERAL_GET_STRING |
| (array_in, env,&string_array_length ); |
| |
| /* create the output array and set the string array and length */ |
| array_out = axis2_ArrayOfstring_literal_create ( env ); |
| AXIS2_ARRAYOFSTRING_LITERAL_SET_STRING( |
| array_out, env, string_array, string_array_length ); |
| |
| /* create the response and set the output*/ |
| echo_out = axis2_echoStringArrayResponse_create ( env ); |
| AXIS2_ECHOSTRINGARRAYRESPONSE_SET_RETURN ( echo_out, env , array_out |
| ); |
| |
| return echo_out; |
| |
| </pre></div> |
| </div><div class="subsection"><a name="echoStruct"></a><h3>echoStruct</h3> |
| <div class="source"><pre> |
| axis2_echoStructResponse_t* |
| axis2_WSDLInteropTestDocLitService_echoStruct |
| (const axis2_env_t* env ,axis2_echoStruct_t* param4 ) |
| |
| { |
| axis2_echoStruct_t* echo_in = param4; |
| axis2_echoStructResponse_t* echo_out = NULL; |
| axis2_SOAPStruct_t* struct_in = NULL; |
| axis2_SOAPStruct_t* struct_out = NULL; |
| |
| float float_val = 0; |
| int int_val = 0; |
| char* string_val = NULL; |
| |
| /* retrieve the structure from input */ |
| struct_in = AXIS2_ECHOSTRUCT_GET_PARAM0( echo_in, env); |
| |
| /* retrieve each value from the structure */ |
| float_val = AXIS2_SOAPSTRUCT_GET_VARFLOAT ( struct_in, env); |
| int_val = AXIS2_SOAPSTRUCT_GET_VARINT ( struct_in, env); |
| string_val = AXIS2_SOAPSTRUCT_GET_VARSTRING ( struct_in, env); |
| |
| /* create the output structure and set values */ |
| struct_out = axis2_SOAPStruct_create( env ); |
| AXIS2_SOAPSTRUCT_SET_VARFLOAT ( struct_out, env, float_val ); |
| AXIS2_SOAPSTRUCT_SET_VARINT ( struct_out, env, int_val ); |
| AXIS2_SOAPSTRUCT_SET_VARSTRING ( struct_out, env, string_val ); |
| |
| /* create the response and set the output structure*/ |
| echo_out = axis2_echoStructResponse_create ( env ); |
| AXIS2_ECHOSTRUCTRESPONSE_SET_RETURN ( echo_out, env, struct_out ); |
| |
| return echo_out; |
| |
| </pre></div> |
| </div><div class="subsection"><a name="services_xml"></a><h3>services.xml</h3><p> |
| Axis2 uses "services.xml" to hold the configurations for a particular Web |
| service deployed in the Axis2 engine. When we generate the skeleton using the |
| WSDL2Java tool, it will generate the required services.xml for this Web |
| service as well. This is essential to <a href="#deploy">deploy the |
| service</a>. Please refer to the '<a href="#Step3">Write the |
| services.xml</a>' section in this guide to learn more about services.xml. |
| <a name="deploy"></a></p></div><div class="subsection"><a name="Deploy_the_Web_Service"></a><h3>Deploy the Web Service</h3><p>We simply put our service folder or the ".aar" file to the services |
| directory. You need restart the server for the engine to pick this |
| service.</p><p><a name="Web_Service_Clients_Using_Axis2"></a></p></div><div class="subsection"><a name="Web_Service_Clients_Using_Axis2_C"></a><h3>Web Service Clients Using Axis2/C</h3><p>Now let's see how we can write a Web service client to consume a Web |
| service.</p><p>Web services can be used to provide wide range of functionality to the |
| users ranging from simple, less time consuming operations such as |
| "getStockQuote" to time consuming business services. When we utilize (invoke |
| using client applications) these Web services, we cannot use some simple |
| generic invocation paradigm that suits all the timing complexities involved |
| in the service operations. For example, if we use a single transport channel |
| (such as HTTP) to invoke a Web service with an IN-OUT operation which takes |
| a long time to complete, then most of the time we may end up with "connection |
| time outs". On the other hand, if there are simultaneous service invocations |
| that we need to perform from a single client application, then the use of a |
| "blocking" client API will degrade the performance of the client application. |
| Similarly, there are various other consequences such as One-Way transports |
| that come into play when we need them. Let's try to analyze some common |
| service invocation paradigms.</p><p>Many Web service engines provide the users with a Blocking and |
| Non-Blocking client APIs.</p><ul> |
| <li><p style="margin-bottom: 0in;"><b>Blocking API</b> -Once the service |
| invocation is called, the client application hangs and only gets control |
| back when the operation completes, after which client receives a response |
| or a fault. This is the simplest way of invoking Web services and it also |
| suits many business situations.</p> |
| </li> |
| <li><b>Non-Blocking API</b>- This is a callback or polling based API. |
| Hence, once a service invocation is called, the client application |
| immediately gets the control back and the response is retrieved using the |
| callback object provided. This approach provides the client application |
| with the flexibility to invoke several Web services simultaneously without |
| blocking the operation that has already been invoked.</li> |
| </ul><p>Both these mechanisms work in the API level. Let's name the asynchronous |
| behavior that we can get using the <strong>Non-Blocking API</strong> as |
| <b>API Level Asynchrony.</b></p><p>Both these mechanisms use single transport connection to send the request |
| and to receive the response. They severely lack the capability of using two |
| transport connections for the request and the response (either One-Way of |
| Two-Way). So both these mechanisms fail to address the problem of long |
| running transactions (the transport connection may time-out before the |
| operation completes). A possible solution would be to use <strong>two |
| separate transport connections for request and response</strong>. The |
| asynchronous behavior that we gain using this solution can be called |
| <b>Transport Level Asynchrony</b>.</p><p>By combining API Level Asynchrony & Transport Level Asynchrony we can |
| obtain four different invocation patterns for Web services as shown in the |
| following table.</p><p></p><table class="bodyTable"><tbody> |
| <tr class="a"><td><strong>API (Blocking/Non-Blocking)</strong></td><td><strong> Dual Transports (Yes/No)</strong></td><td><strong>Description</strong></td></tr> |
| <tr class="b"><td>Blocking</td><td>No</td><td>Simplest and the familiar invocation pattern</td></tr> |
| <tr class="a"><td>Non-Blocking</td><td>No</td><td>Using callbacks or polling</td></tr> |
| <tr class="b"><td>Blocking</td><td>Yes</td><td>This is useful when the service operation is IN-OUT in nature but |
| the transport used is One-Way (e.g. SMTP)</td></tr> |
| <tr class="a"><td>Non-Blocking</td><td>Yes</td><td>This can be used to gain the maximum asynchronous behavior. No |
| blocking in the API level and also in the transport level</td></tr> |
| </tbody></table><p>Axis2/C provides the user with all these possibilities to invoke Web |
| services.</p><p>Below we describe how to write Web Services Clients using Axis2/C.</p><p><a name="Writing_Web_Service_Clients_using_Axis2%27s_Primary_APIs"></a></p></div><div class="subsection"><a name="Writing_Web_Service_Clients_Using_Axis2_s_Primary_APIs"></a><h3>Writing Web Service Clients Using Axis2's Primary APIs</h3><p><a id="EchoBlockingClient"></a></p></div><div class="subsection"><a name="echo_blocking_Client"></a><h3>echo_blocking Client</h3><p>Axis2/C provides the user with several invocation patterns for Web |
| Services, ranging from pure blocking single channel invocations to a |
| non-blocking dual channel invocation. Let's first see how we can write a |
| client to invoke "echo" operation of "echo" service using the simplest |
| blocking invocation. The client code you need to write is as follows.</p> |
| <div class="source"><pre> |
| /* 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); |
| /* Set the deploy folder */ |
| client_home = AXIS2_GETENV("AXIS2C_HOME"); |
| if (!client_home) |
| client_home = "../../deploy"; |
| /* Create service client */ |
| svc_client = axis2_svc_client_create(env, client_home); |
| if (!svc_client) |
| { |
| printf("Error creating service client\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)); |
| } |
| /* 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_echo_svc(env); |
| /* Send request */ |
| ret_node = AXIS2_SVC_CLIENT_SEND_RECEIVE(svc_client, env, payload); |
| /* Print result */ |
| if(ret_node) |
| { |
| 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("\necho client invoke SUCCESSFUL!\n"); |
| } |
| 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("echo client invoke FAILED!\n"); |
| } |
| |
| </pre></div> |
| <p>The comments in the above code explains the code. In simple terms, these |
| are the steps:</p><ol> |
| <li>Set up the options to be used in the invocation.</li> |
| <li>Create the service client.</li> |
| <li>Set the options to service client.</li> |
| <li>Build the XML payload to be sent out using AXIOM.</li> |
| <li>Send payload and receive result XML as OM.</li> |
| <li>Consume result.</li> |
| </ol><p>Options can be used to define the invocation parameters such as target |
| endpoint, soap version, addressing parameters, etc. When creating service |
| client, the deployment folder has to be passed as a parameter. It is from the |
| deploy folder, the configuration is picked up, using the axis2.xml file. The |
| send_receive function of the service client sends the XML given as a payload |
| to the server side and returns the result received. Basically this is the XML |
| in/out model. Once the result is received, the user can consume the result in |
| whichever the way(s) he wishes.</p><p><a id="EchoNonBlockingClient"></a></p></div><div class="subsection"><a name="echo_non_blocking_Client"></a><h3>echo_non_blocking Client</h3><p>In the echo_blocking client once the "send_receive" function is called, |
| the client is blocked till the operation is completed. This behavior is not |
| desirable when there are many Web service invocations to be done in a single |
| client application or within a GUI. A solution would be to use a non-blocking |
| API to invoke Web services. Axis2/C provides a callback based non-blocking |
| API for users.</p><p>A sample client for this can be found under |
| "<axis2c_home>/samples/user_guide/clients" with the name |
| echo_non_blocking.c. The changes that user may have to do with respect to the |
| "echo_blocking" client in order to make it non-blocking, would be as |
| follows:</p> |
| <div class="source"><pre>AXIS2_SVC_CLIENT_SEND_RECEIVE_NON_BLOCKING(svc_client, env, payload, callback); |
| |
| </pre></div> |
| <p>Unlike "send_receive", "send_receive_non_blocking" accepts a callback |
| struct in addition to payload. Axis2/C client API provides a callback struct |
| with the following associated functions:</p> |
| <div class="source"><pre> |
| axis2_status_t (AXIS2_CALL * |
| on_complete)( |
| struct axis2_callback *callback, |
| const axis2_env_t *env); |
| |
| axis2_status_t (AXIS2_CALL * |
| on_error)( |
| struct axis2_callback *callback, |
| const axis2_env_t *env, |
| int exception); |
| |
| axis2_bool_t (AXIS2_CALL * |
| get_complete)( |
| struct axis2_callback *callback, |
| const axis2_env_t *env); |
| |
| </pre></div> |
| <p>The user is expected to implement the "on_complete " and "on_error " |
| functions and set them on the callback using the "set_on_complete" and |
| "set_on_error" API calls. In the sample, ''on complete'' is implemented by |
| "echo_callback_on_complete" function and is set on the callback struct |
| created as shown below:</p> |
| <div class="source"><pre>AXIS2_CALLBACK_SET_ON_COMPLETE(callback, echo_callback_on_complete); |
| |
| </pre></div> |
| <p>Axis2/C engine calls the "on_complete" method once the Web service |
| response is received by the Axis2/C client API (that is service_client). This |
| will eliminate the blocking nature of the Web service invocations and |
| provide the user with the flexibility to use non-blocking API for Web |
| service clients.</p><p>Please have a look at the echo_non_blocking.c file located at |
| "<axis2c_home>/samples/user_guide/client" for more details.</p><p><a id="EchoNonBlockingDualClient"></a></p></div><div class="subsection"><a name="echo_non_blocking_dual_Client"></a><h3>echo_non_blocking_dual Client</h3><p>The solution provided by the non-blocking API has one limitation when it |
| comes to Web service invocations,it takes a long time to complete. The |
| limitation is due to the use of a single transport connection to invoke the |
| Web service and to retrieve the response. In other words, client API provides |
| a non blocking invocation mechanism for the users, but the request and the |
| response comes in a single transport (Two-Way transport) connection (like |
| HTTP). Long running Web service invocations or Web service invocations using |
| One-Way transports (like SMTP) cannot be utilized by simply using a non |
| blocking invocation.</p><p>The trivial solution is to use separate transport connections (either |
| One-Way or Two-Way) for the request and response. The next problem that needs |
| to be solved is the correlation (correlating the request and the response). |
| <a href="http://www.w3.org/2002/ws/addr/" class="externalLink" title="External Link">WS-Addressing</a> provides a neat |
| solution to this using <wsa:MessageID> and <wsa:RelatesTo> |
| headers. Axis2/C provides support for addressing based correlation mechanism |
| and a compliant client API to invoke Web services with two transport |
| connections.</p><p>Users can select between blocking or non-blocking APIs for the Web service |
| clients with two transport connections. By simply using a boolean flag, the |
| same API can be used to invoke Web services (IN-OUT operations) using two |
| separate transport connections. All you have to do is to set |
| "use_separate_listener" to true in options:</p> |
| <div class="source"><pre>AXIS2_OPTIONS_SET_USE_SEPERATE_LISTENER(options, env, AXIS2_TRUE); |
| |
| </pre></div> |
| <p>In addition to setting the use_separate_listener to true, to use dual |
| transports one has to"engage" the addressing module.</p></div><div class="subsection"><a name="Engaging_Addressing_on_Server_Side"></a><h3>Engaging Addressing on Server Side</h3><p>To engage the addressing module simply add a module reference for |
| addressing in the "axis2.xml" configuration file. This can be done by adding |
| the following line to "axis2.xml" file in the deployment folder.</p> |
| <div class="source"><pre> <module ref="addressing"/> |
| |
| </pre></div> |
| <p><strong>Note:</strong> Once you modify the "axis2.xml" file you have to restart the server. |
| You also have to have the addressing module installed in the modules folder |
| of the deployment folder. This is done by default when you make the |
| installation.</p></div><div class="subsection"><a name="Engaging_Addressing_on_Client_Side"></a><h3>Engaging Addressing on Client Side</h3><p>There are two ways of doing this:</p><ol> |
| <li>Engage addressing globally. This can be done by following the same |
| steps as done in the case of the server side; add module reference to |
| axis2.xml and have the module installed in the modules folder of the |
| deploy folder.</li> |
| <li>Engage the module on service client using the service_client API. |
| <pre>AXIS2_SVC_CLIENT_ENGAGE_MODULE(svc_client, env, AXIS2_MODULE_ADDRESSING);</pre> |
| </li> |
| </ol><p>Once addressing is engaged, echo_non_blocking_dual client would work |
| perfectly. Note that by default, Axis2/C comes with addressing enabled |
| globally.</p><p><a id="EchoBlockingDualClient"></a></p></div><div class="subsection"><a name="echo_blocking_dual_Client"></a><h3>echo_blocking_dual Client</h3><p>This is again a Two-Way transport request/response client, but this time, |
| we use a Blocking API in the client code. Sample code for this can be found |
| in the "<axis2c_home>/samples/user_guide/clients/" directory and the |
| explanation is similar to the <a href="#EchoNonBlockingDualClient">echo_non_blocking_dual client</a>, except |
| that here we do not use a callback object to handle response. This is an extremely |
| useful mechanism when the service invocation is IN-OUT in nature and the |
| transports are One-Way (e.g. SMTP). For the sample client we use two HTTP |
| connections for request and response.</p><p><a id="Writing_Web_Clients_Using_Code_Generator"></a></p></div><div class="subsection"><a name="Writing_Web_Service_Clients_using_Code_Generation_with_Data_Binding_Support"></a><h3>Writing Web Service Clients using Code Generation with Data Binding Support</h3><p>Axis2 code generator provides the data binding support for Web service |
| client generation as well. You can generate the required stubs from a given |
| WSDL with the other supporting files. Use the following parameters to |
| generate the Axis2/C stub code with data binding support. You should have |
| <a href="http://svn.apache.org/viewvc/webservices/axis2/trunk/java" class="externalLink" title="External Link">Axis2/Java |
| source SVN</a> revision 414253 or later to generate Axis2/C code.</p> |
| <div class="source"><pre>java WSDL2C -uri interoptestdoclitparameters.wsdl -d adb -u |
| |
| </pre></div> |
| <p>In order to ignore the data binding support (to use XML in/out model), |
| just use the following parameters.</p> |
| <div class="source"><pre>java WSDL2C -uri interoptestdoclitparameters.wsdl -d none |
| |
| </pre></div> |
| <p>The following section demonstrates how to use the generated code using the |
| wsdl file "interoptestdoclitparameters.wsdl" to implement the client business |
| logic.</p><p><a id="Codegenerator_Client_echoString"></a></p></div><div class="subsection"><a name="Client_for_echoString_operation"></a><h3>Client for echoString operation</h3> |
| <div class="source"><pre>#include "axis2_WSDLInteropTestDocLitService_stub.h" |
| /* |
| * demonstrates how to execute the service using databinding */ |
| void invoke_service_using_databinding ( axis2_stub_t* stub, |
| const axis2_env_t* env ); |
| int main(int argc, char** argv) |
| { |
| /* variables to keep the environment */ |
| axis2_env_t* env = NULL; |
| axis2_char_t* client_home = NULL; |
| axis2_char_t* endpoint_uri =NULL; |
| axis2_stub_t* stub= NULL; |
| /* endpoint uri: if it is NULL endpoint will be picked from the WSDL */ |
| endpoint_uri = |
| "http://localhost:9090/axis2/services/WSDLInteropTestDocLitService"; |
| env = axis2_env_create_all( "codegen_utest_blocking.log", |
| AXIS2_LOG_LEVEL_TRACE); |
| /* Set up deploy folder.*/ |
| client_home = AXIS2_GETENV("AXIS2C_HOME"); |
| if (!client_home) |
| client_home = "../../../deploy"; |
| /* create the stub using generated code */ |
| stub = axis2_WSDLInteropTestDocLitService_stub_create( env, |
| client_home , endpoint_uri); |
| /* calls the service*/ |
| invoke_service_using_databinding ( stub, env ); |
| return 0; |
| } |
| |
| void invoke_service_using_databinding ( axis2_stub_t* stub, |
| const axis2_env_t* env ) |
| { |
| /* variables used by databinding */ |
| axis2_echoString_t* echo_in = NULL; |
| axis2_echoStringResponse_t* echo_out = NULL; |
| /* variables to store data */ |
| char* echo_str = "hello"; |
| char* return_echo_str = NULL; |
| /* create the input params using databinding */ |
| echo_in = axis2_echoString_create( env ); |
| AXIS2_ECHOSTRING_SET_PARAM0( echo_in, env, echo_str ); |
| /* invoke the web service method*/ |
| echo_out = axis2_echoString( stub, env, echo_in ); |
| /* return the output params using databinding */ |
| return_echo_str = AXIS2_ECHOSTRUCTRESPONSE_GET_RETURN( echo_out, env |
| ); |
| /* print the result */ |
| printf ( "returned string %s\n", return_echo_str ); |
| } |
| </pre></div> |
| <p><a id="Codegenerator_Client_echoStringArray"></a></p></div><div class="subsection"><a name="Client_for_echoStringArray_operation"></a><h3>Client for echoStringArray operation</h3><p> |
| You can change the <code>invoke_service_using_databinding</code> function to |
| invoke the echoStringArray operation as follows. |
| |
| <div class="source"><pre>void invoke_service_using_databinding ( axis2_stub_t* stub, const |
| axis2_env_t* env ) |
| { |
| /* variables used by databinding */ |
| axis2_echoStringArray_t* echo_in = NULL; |
| axis2_echoStringArrayResponse_t* echo_out = NULL; |
| axis2_ArrayOfstring_literal_t* array_in = NULL; |
| axis2_ArrayOfstring_literal_t* array_out = NULL; |
| /* variables to store data */ |
| char *string_array[]= { "test","this","array" }; |
| int array_length = 3; |
| char **string_return_string_array = NULL; |
| int return_array_length = 0; |
| int i = 0; |
| |
| /*create the input array and set the string array and length*/ |
| array_in = axis2_ArrayOfstring_literal_create (env ); |
| AXIS2_ARRAYOFSTRING_LITERAL_SET_STRING( array_in, env, |
| string_array, array_length ); |
| |
| /* create the request and set the inputs */ |
| echo_in = axis2_echoStringArray_create ( env ); |
| AXIS2_ECHOSTRINGARRAY_SET_PARAM0( echo_in, env, array_in ); |
| |
| /* invoke the web service method*/ |
| echo_out = axis2_echoStringArray( stub, env, echo_in ); |
| |
| /* return the output params using databinding */ |
| array_out = AXIS2_ECHOSTRINGARRAYRESPONSE_GET_RETURN( echo_out, env |
| ); |
| |
| /* retrieve the string array values and length */ |
| string_return_string_array = AXIS2_ARRAYOFSTRING_LITERAL_GET_STRING |
| ( array_out, env, &return_array_length ); |
| |
| /* print the output */ |
| for ( i = 0; i < return_array_length ; i ++ ) |
| { |
| printf("value%d: %s \n", i, string_return_string_array[i] ); |
| } |
| </pre></div> |
| |
| |
| <a id="Codegenerator_Client_echoStruct"></a></p></div><div class="subsection"><a name="Client_for_echoStruct_operation"></a><h3>Client for echoStruct operation</h3> |
| <div class="source"><pre>void invoke_service_using_databinding ( axis2_stub_t* stub, |
| const axis2_env_t* env ) |
| { |
| /* variables used by databinding */ |
| axis2_echoStruct_t* echo_in = NULL; |
| axis2_echoStructResponse_t* echo_out = NULL; |
| axis2_SOAPStruct_t* struct_in = NULL; |
| axis2_SOAPStruct_t* struct_out = NULL; |
| |
| |
| /* variables to store data */ |
| float float_val = 11; |
| int int_val = 10; |
| char* string_val = "hello struct"; |
| int ret_int_val = 0; |
| float ret_float_val = 0; |
| char* ret_string_val = ""; |
| |
| /* create the struct and set input values*/ |
| struct_in = axis2_SOAPStruct_create( env ); |
| AXIS2_SOAPSTRUCT_SET_VARFLOAT ( struct_in, env, float_val ); |
| AXIS2_SOAPSTRUCT_SET_VARINT ( struct_in, env, int_val ); |
| AXIS2_SOAPSTRUCT_SET_VARSTRING ( struct_in, env, string_val ); |
| |
| /* create the request and set the struct */ |
| echo_in = axis2_echoStruct_create( env ); |
| AXIS2_ECHOSTRUCT_SET_PARAM0( echo_in, env, struct_in ); |
| /* invoke the web service method */ |
| echo_out = axis2_echoStruct( stub, env, echo_in ); |
| |
| /* retrieve the structure from response */ |
| struct_out = AXIS2_ECHOSTRUCTRESPONSE_GET_RETURN( echo_out, env ); |
| |
| /* retrieve each value from the structure */ |
| ret_float_val = AXIS2_SOAPSTRUCT_GET_VARFLOAT ( struct_out, env ); |
| ret_int_val = AXIS2_SOAPSTRUCT_GET_VARINT ( struct_out, env ); |
| ret_string_val = AXIS2_SOAPSTRUCT_GET_VARSTRING ( struct_out, env ); |
| |
| /* print the values */ |
| printf ( "returned values \n"); |
| printf (" float %f\n", ret_float_val ); |
| printf (" int %d \n", ret_int_val ); |
| printf (" string %s \n", ret_string_val); |
| } |
| |
| </pre></div> |
| <p><a id="Providing_security_using_Rampart"></a></p></div><div class="subsection"><a name="Providing_Security_using_Rampart_C"></a><h3>Providing Security using Rampart/C</h3><p>Rampart/C is the security module for Axis2/C, which supports UsernameToken |
| based authentication and Timestamps as per WS-Security specification. In this |
| User's Guide we will explain how to use Rampart inside Axis2/C.</p><p><a id="Engaging_rampart_module"></a></p></div><div class="subsection"><a name="Engaging_rampart_module"></a><h3>Engaging rampart module</h3><ul> |
| <li><b>Step 1:</b> Copy rampart directory created in |
| AXIS2C_HOME/deploy/rampart to AXIS2C_HOME/deploy/modules |
| <pre>cp $AXIS2C_HOME/deploy/rampart/rampart $AXIS2C_HOME/deploy/modules</pre> |
| </li> |
| <li><b>Step 2:</b>Add following line to the axis2.xml under axisconfig. |
| This will engage the rampart module. |
| <pre><module ref="rampart"/></pre> |
| </li> |
| <li><b>Step 3:</b>Then add the following to axis2.xml file to specify |
| In/Out flow parameters. You may find a sample axis2.xml file in |
| rampart/samples/client/echo/data/ |
| <p> <parameter name="OutflowSecurity"><action><br></br> <items>UsernameToken Timestamp</items><br></br> <user>Gajaba</user><br></br> <passwordType>passwordDigest</passwordType><br></br> <passwordCallbackClass>/home/gajaba/axis2/c/deploy/rampart/samples/callback/libpwcb.so</passwordCallbackClass><br></br> <timeToLive>360</timeToLive><br></br> </action><br></br> </parameter><br></br> </p> |
| <p class="code"> <parameter name="InflowSecurity"><br></br> |
| <action><br></br> <items>UsernameToken |
| Timestamp</items><br></br> |
| <passwordCallbackClass>/home/gajaba/axis2/c/deploy/rampart/samples/callback/libpwcb.so</passwordCallbackClass><br></br> </action><br></br> </parameter><br></br> </p> |
| |
| </li> |
| </ul><p><strong>Note:</strong> You must replace the value of |
| <code>passwordCallbackClass</code> parameter to suit your settings.</p><p>Now everything is setup to try out the sample. Start axis2 server and run |
| the sample under rampart/samples/client/echo. If everything works fine a |
| security header should be added to the outgoing SOAP message.</p><p><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><br></br> <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><br></br> <wsse:Username>Gajaba</wsse:Username><br></br> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">WNPznBN3PeLypKYXlwV7w9zJZ9o=</wsse:Password><br></br> <wsse:Nonce>ICAgICAgIDEwNDY0NDk1Mg==</wsse:Nonce><br></br> <wsu:Created>2006-08-28T11:52:27Z</wsu:Created><br></br> </wsse:UsernameToken><br></br> <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><br></br> <wsu:Created>2006-08-28T11:52:27Z</wsu:Created><br></br> <wsu:Expires>2006-08-28T11:58:27Z</wsu:Expires><br></br> </wsu:Timestamp><br></br></wsse:Security><br></br></p><p><strong>Note: </strong>For the above sample we have used the same axis2.xml file for |
| both server and the client. But in the real world this is not possible. In |
| such a situation you can specify a client home as an argument.</p> |
| <div class="source"><pre>./echo [endpoint_url] [path to your client_home] |
| |
| </pre></div> |
| </div><div class="subsection"><a name="Semantics_of_Parameters_Specified_in_axis2_xml"></a><h3>Semantics of Parameters Specified in axis2.xml</h3><table class="bodyTable"><tbody> |
| <tr class="b"><td><strong>Parameter</strong></td><td><strong>Semantic</strong></td></tr> |
| <tr class="a"><td>items</td><td>Specify the tokens to be used for the credential exchange. In the |
| above example we used both UsernameTokens and Timestamps</td></tr> |
| <tr class="b"><td>user</td><td>The username of the UsernameToken</td></tr> |
| <tr class="a"><td>passwordType</td><td>The way password is delivered. This can be either passwordText or |
| the passwordDigest. The former delivers password in plainText whilst |
| the latter delivers the hashed value of the password. Default is |
| passwordText</td></tr> |
| <tr class="b"><td>passwordCallbackClass</td><td>The module that provides the password for a particular user</td></tr> |
| <tr class="a"><td>timeToLive</td><td>The validity period of the TimestampToken after issuing. The time |
| is in seconds. In the above example, it's 6 minutes. If not |
| specified, the default is 5 minutes</td></tr> |
| </tbody></table><p><a id="Writing_own_password_callback_module"></a></p></div><div class="subsection"><a name="Writing_Your_Own_Password_Callback_Module"></a><h3>Writing Your Own Password Callback Module</h3><p>The Rampart module is not dependent on the way that passwords are stored. |
| For example, you may have passwords in a flat file or in a secured database. |
| What ever the way, Rampart expects a password callback module to retrieve |
| passwords for a given username. The sample coming under |
| "<axis2c_home>rampart/samples/callback" is a simple one containing a |
| few hard-coded passwords. It assigns a function to the function pointer.</p> |
| <div class="source"><pre>rcb->ops->callback_password = get_sample_password; |
| |
| </pre></div> |
| <p><code>callback_password</code> is a function pointer to any function which |
| has the following signature.</p> |
| <div class="source"><pre>* |
| your_function(rampart_callback_t *rcb, |
| const axis2_env_t *env, const axis2_char_t *username) |
| |
| </pre></div> |
| <p><code>your_function</code> should return the password as |
| <code>axis2_char_t</code>* per the username specified, if any. Inside your |
| function, you may write your code to supply stored passwords.</p><p>Then the path to the callback module needs to be specified in axis2.xml |
| under passwordCallbackClass. [The word Class, instead of Module is only for |
| compatibility with java implementation]</p><p><a id="Adding_security_parameters_dynamically"></a></p></div><div class="subsection"><a name="Adding_Security_Parameters_Dynamically"></a><h3>Adding Security Parameters Dynamically</h3><p>Outflow parameters specified in the axis2.xml can be added dynamically in |
| the client level. This can be done as shown in the following sample code.</p> |
| <div class="source"><pre> un_property = axis2_property_create(env); |
| AXIS2_PROPERTY_SET_VALUE(un_property, env, "Gajaba"); |
| AXIS2_OPTIONS_SET_PROPERTY(options, env, RAMPART_ACTION_USER, un_property); |
| |
| </pre></div> |
| <p>The above code will set the username parameter dynamically. All the values |
| specified in the axis2.xml will be overridden by the dynamic settings.</p></div><div class="subsection"><a name="References"></a><h3>References</h3><ul> |
| <li>Introducing Apache Axis2/C - <a href="http://www.wso2.net/articles/axis2/c/2006/09/04/introduction" class="externalLink" title="External Link">http://www.wso2.net/articles/axis2/c/2006/09/04/introduction</a></li> |
| <li>Introducing Rampart/C- <a href="http://www.wso2.net/articles/rampart/c/2006/09/19/introduction" class="externalLink" title="External Link">http://www.wso2.net/articles/rampart/c/2006/09/19/introduction</a></li> |
| </ul></div></div></div></div><div class="clear"><hr></hr></div><div id="footer"><div class="xright">© 2005-2006, Apache Software Foundation</div><div class="clear"><hr></hr></div></div></body></html> |