<?xml version="1.0" encoding="iso-8859-1"?> | |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" | |
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> | |
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> | |
<title>Axis2/C User's Guide</title> | |
<meta name="generator" content="Bluefish 1.0.5"/> | |
</head> | |
<body xml:lang="en"> | |
<h1>Apache Axis2/C User's Guide</h1> | |
<h2>Content</h2> | |
<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> | |
<a id="Introduction"></a> | |
<h2>Introduction</h2> | |
<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> | |
<a id="What_is_Axis2_"></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">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">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> | |
<a name="Web_Services_Using_Axis2"></a> | |
<h2>Web Services Using Axis2/C</h2> | |
<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> | |
<a name="Writing_Web_Services_Using_Axis2_C"></a> | |
<h3>Writing Web Services Using Axis2/C</h3> | |
<a id="Creating_Web_Service__MyService_"></a> | |
<h4>Creating Web Service (Echo service)</h4> | |
<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> | |
<pre> | |
axiom_node_t* axis2_echo_echo(axiom_node_t *echo_node){}</pre> | |
<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> | |
<a id="How_to_write_the_Web_Service_"></a> | |
<h4>How to write the Web Service?</h4> | |
<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> | |
<a name="Step1"></a> | |
<h4>Step1 :Write the echo_skeleton.c file implementing the | |
axis2_svc_skeleton.h</h4> | |
<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> | |
<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> | |
<P>Let's implement the above functions for echo service.</p> | |
<p><i><code>/* Initialize the service */</code></i><br /> | |
<code>int AXIS2_CALL</code><br /> | |
<code>echo_init(axis2_svc_skeleton_t *svc_skeleton,</code><br /> | |
<code>                        const axis2_env_t *env)</code><br /> | |
<code>{</code><br /> | |
<code>    svc_skeleton->func_array = axis2_array_list_create(env, 0);</code><br | |
/> | |
<code>    </code><i><code>/* Add the implemented operation names of the service to  </code><br | |
/> | |
<code>     * the array list of functions </code><br /> | |
<code>Â Â Â Â Â */</code></i><br /> | |
<code>    AXIS2_ARRAY_LIST_ADD(svc_skeleton->func_array, env, "echoString");</code><br | |
/> | |
<code>    </code><i><code>/* Any initialization stuff of echo service should go here */</code></i><br | |
/> | |
<code>Â Â Â Â </code><b><code>return</code></b><code>Â AXIS2_SUCCESS;</code><br /> | |
<code>}</code><br /> | |
<br /> | |
<i><code>/*</code><br /> | |
<code> * This method invokes the right service method </code><br /> | |
<code>Â */</code></i><br /> | |
<code>axiom_node_t*Â AXIS2_CALL</code><br /> | |
<code>echo_invoke(axis2_svc_skeleton_t *svc_skeleton,</code><br /> | |
<code>            const axis2_env_t *env,</code><br /> | |
<code>            axiom_node_t *node)</code><br /> | |
<code>{</code><br /> | |
<code>    </code><i><code>/* Invoke the business logic.</code><br /> | |
<code>     * Depending on the function name invoke the correct impl method.</code><br | |
/> | |
<code>     * We have only echo in this sample, hence invoke echo method.</code><br | |
/> | |
<code>     * To see how to deal with multiple impl methods, have a look at the</code><br | |
/> | |
<code>     * math sample.</code><br /> | |
<code>Â Â Â Â Â */</code></i><br /> | |
<code>    </code><b><code>return</code></b><code> axis2_echo_echo(env, node);</code><br | |
/> | |
<code>}</code><br /> | |
<br /> | |
<i><code>/* On fault, handle the fault */</code></i><br /> | |
<code>axiom_node_t*Â AXIS2_CALL</code><br /> | |
<code>echo_on_fault(axis2_svc_skeleton_t *svc_skeli, </code><br /> | |
<code>              const axis2_env_t *env, axiom_node_t *node)</code><br /> | |
<code>{</code><br /> | |
<code>   </code><i><code>/* Here we are just setting a simple error message inside an element </code><br | |
/> | |
<code>    * called 'EchoServiceError' </code><br /> | |
<code>Â Â Â Â */</code></i><br /> | |
<code>    axiom_node_t *error_node = NULL;</code><br /> | |
<code>    axiom_node_t* text_node = NULL;</code><br /> | |
<code>    axiom_element_t *error_ele = NULL;</code><br /> | |
<code>    error_ele = axiom_element_create(env, node, "EchoServiceError", NULL, </code><br | |
/> | |
<code>Â Â Â Â Â Â Â Â &error_node);</code><br /> | |
<code>    AXIOM_ELEMENT_SET_TEXT(error_ele, env, "Echo service failed ", </code><br | |
/> | |
<code>Â Â Â Â Â Â Â Â text_node);</code><br /> | |
<code>Â Â Â Â </code><b><code>return</code></b><code>Â error_node;</code><br /> | |
<code>}</code><br /> | |
<br /> | |
<i><code>/* Free the resources used */</code></i><br /> | |
<code>int AXIS2_CALL</code><br /> | |
<code>echo_free(axis2_svc_skeleton_t *svc_skeleton,</code><br /> | |
<code>            const axis2_env_t *env)</code><br /> | |
<code>{</code><br /> | |
<code>    </code><i><code>/* Free the function array */</code></i><br /> | |
<code>Â Â Â Â </code><b><code>if</code></b><code>(svc_skeleton->func_array)</code><br | |
/> | |
<code>Â Â Â Â {</code><br /> | |
<code>        AXIS2_ARRAY_LIST_FREE(svc_skeleton->func_array, env);</code><br | |
/> | |
<code>        svc_skeleton->func_array = NULL;</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<code>Â Â Â Â </code><br /> | |
<code>    </code><i><code>/* Free the function array */</code></i><br /> | |
<code>Â Â Â Â </code><b><code>if</code></b><code>(svc_skeleton->ops)</code><br | |
/> | |
<code>Â Â Â Â {</code><br /> | |
<code>        AXIS2_FREE(env->allocator, svc_skeleton->ops);</code><br | |
/> | |
<code>        svc_skeleton->ops = NULL;</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<code>Â Â Â Â </code><br /> | |
<code>    </code><i><code>/* Free the service skeleton */</code></i><br /> | |
<code>Â Â Â Â </code><b><code>if</code></b><code>(svc_skeleton)</code><br /> | |
<code>Â Â Â Â {</code><br /> | |
<code>        AXIS2_FREE(env->allocator, svc_skeleton);</code><br /> | |
<code>        svc_skeleton = NULL;</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<br /> | |
<code>Â Â Â Â </code><b><code>return</code></b><code>Â AXIS2_SUCCESS;Â </code><br /> | |
<code>}</code><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 /> | |
</i><code>axis2_svc_skeleton_t *</code><br /> | |
<code>axis2_echo_create(const axis2_env_t *env)</code><br /> | |
<code>{</code><br /> | |
<code>    axis2_svc_skeleton_t *svc_skeleton = NULL;</code><br /> | |
<code>    </code><i><code>/* Allocate memory for the structs */</code></i><br | |
/> | |
<code>    svc_skeleton = AXIS2_MALLOC(env->allocator, </code><br /> | |
<code>Â Â Â Â Â Â Â Â </code><b><code>sizeof</code></b><code>(axis2_svc_skeleton_t));</code><br | |
/> | |
<br /> | |
<code>    svc_skeleton->ops = AXIS2_MALLOC(</code><br /> | |
<code>        env->allocator, </code><b><code>sizeof</code></b><code>(axis2_svc_skeleton_ops_t));</code><br | |
/> | |
<br /> | |
<code>    </code><i><code>/* Assign function pointers */</code></i><br /> | |
<code>    svc_skeleton->ops->free = echo_free;</code><br /> | |
<code>    svc_skeleton->ops->init = echo_init;</code><br /> | |
<code>    svc_skeleton->ops->invoke = echo_invoke;</code><br /> | |
<code>    svc_skeleton->ops->on_fault = echo_on_fault;</code><br /> | |
<br /> | |
<code>Â Â Â Â </code><b><code>return</code></b><code>Â svc_skeleton;</code><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 /> | |
<code>axis2_get_instance(axis2_svc_skeleton_t **inst,</code><br /> | |
<code>                   const axis2_env_t *env)</code><br /> | |
<code>{</code><br /> | |
<code>    *inst = axis2_echo_create(env);</code><br /> | |
<code>Â Â Â Â </code><b><code>if</code></b><code>(!(*inst))</code><br /> | |
<code>Â Â Â Â {</code><br /> | |
<code>Â Â Â Â Â Â Â Â </code><b><code>return</code></b><code>Â AXIS2_FAILURE;</code><br | |
/> | |
<code>Â Â Â Â }</code><br /> | |
<code>Â Â Â Â </code><b><code>return</code></b><code>Â AXIS2_SUCCESS;</code><br /> | |
<code>}</code><br /> | |
<br /> | |
<code>AXIS2_EXPORT int </code><br /> | |
<code>axis2_remove_instance(axis2_svc_skeleton_t *inst,</code><br /> | |
<code>                      const axis2_env_t *env)</code><br /> | |
<code>{</code><br /> | |
<code>    axis2_status_t status = AXIS2_FAILURE;</code><br /> | |
<code>Â Â Â Â </code><b><code>if</code></b><code>Â (inst)</code><br /> | |
<code>Â Â Â Â {</code><br /> | |
<code>        status = AXIS2_SVC_SKELETON_FREE(inst, env);</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<code>Â Â Â Â </code><b><code>return</code></b><code>Â status;</code><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> | |
<a name="Step2"></a> | |
<h4>Step2 : Now we can write the echo service in a file echo.c</h4> | |
<p><code>axiom_node_t *</code><br /> | |
<code>axis2_echo_echo (const axis2_env_t *env, axiom_node_t *node)</code><br | |
/> | |
<code>{</code><br /> | |
<code>    axiom_node_t *text_parent_node = NULL;</code><br /> | |
<code>    axiom_node_t *text_node = NULL;</code><br /> | |
<code>    axiom_node_t *ret_node = NULL;</code><br /> | |
<br /> | |
<code>    AXIS2_ENV_CHECK(env, NULL);</code><br /> | |
<code>Â Â Â </code><br /> | |
<code>    </code><i><code>/* Expected request format is :-</code><br /> | |
<code>     * <ns1:echoString xmlns:ns1="http://localhost:9090/axis2/services/echo"></code><br | |
/> | |
<code>Â Â Â Â Â *Â Â Â Â Â Â <text>echo5</text></code><br /> | |
<code>Â Â Â Â Â *Â </ns1:echoString></code><br /> | |
<code>Â Â Â Â Â */</code></i><br /> | |
<code>    </code><b><code>if</code></b><code> (!node) </code><i><code>/* 'echoString' node */</code></i><br | |
/> | |
<code>Â Â Â Â {</code><br /> | |
<code>        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INPUT_OM_NODE_NULL, AXIS2_FAILURE);</code><br | |
/> | |
<code>        printf("Echo client ERROR: input parameter NULL\n");</code><br | |
/> | |
<code>Â Â Â Â Â Â Â Â </code><b><code>return</code></b><code>Â NULL;</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<br /> | |
<code>    text_parent_node = AXIOM_NODE_GET_FIRST_CHILD(node, env);</code><br | |
/> | |
<code>    </code><b><code>if</code></b><code> (!text_parent_node) </code><i><code>/* 'text' node */</code></i><br | |
/> | |
<code>Â Â Â Â {</code><br /> | |
<code>        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST, AXIS2_FAILURE);</code><br | |
/> | |
<code>        printf("Echo client ERROR: invalid XML in request\n");</code><br | |
/> | |
<code>Â Â Â Â Â Â Â Â </code><b><code>return</code></b><code>Â NULL;</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<code>Â Â Â Â </code><br /> | |
<code>    text_node = AXIOM_NODE_GET_FIRST_CHILD(text_parent_node, env);</code><br | |
/> | |
<code>    </code><b><code>if</code></b><code> (!text_node) </code><i><code>/* actual text to echo */</code></i><br | |
/> | |
<code>Â Â Â Â {</code><br /> | |
<code>        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST, AXIS2_FAILURE);</code><br | |
/> | |
<code>        printf("Echo client ERROR: invalid XML in request\n");</code><br | |
/> | |
<code>Â Â Â Â Â Â Â Â </code><b><code>return</code></b><code>Â NULL;</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<code>Â Â Â Â </code><br /> | |
<code>    </code><b><code>if</code></b><code> (AXIOM_NODE_GET_NODE_TYPE(text_node, env) == AXIOM_TEXT)</code><br | |
/> | |
<code>Â Â Â Â {</code><br /> | |
<code>        axiom_text_t *text = (axiom_text_t *)AXIOM_NODE_GET_DATA_ELEMENT(text_node, env);</code><br | |
/> | |
<code>        </code><b><code>if</code></b><code>( text && AXIOM_TEXT_GET_VALUE(text , env))</code><br | |
/> | |
<code>Â Â Â Â Â Â Â Â {</code><br /> | |
<code>            axis2_char_t *text_str = AXIOM_TEXT_GET_VALUE(text, env);</code><br | |
/> | |
<code>            printf("Echoing text value  %s \n", text_str);</code><br /> | |
<code>            ret_node = build_om_programatically(env, text_str);</code><br | |
/> | |
<code>Â Â Â Â Â Â Â Â }</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<code>Â Â Â Â </code><b><code>else</code></b><br /> | |
<code>Â Â Â Â {</code><br /> | |
<code>        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST, AXIS2_FAILURE);</code><br | |
/> | |
<code>        printf("Echo client ERROR: invalid XML in request\n");</code><br | |
/> | |
<code>Â Â Â Â Â Â Â Â </code><b><code>return</code></b><code>Â NULL;</code><br /> | |
<code>Â Â Â Â }</code><br /> | |
<code>Â Â Â Â Â Â Â Â </code><br /> | |
<code>Â Â Â Â </code><b><code>return</code></b><code>Â ret_node;</code><br /> | |
<code>}</code><br /> | |
<br /> | |
<i><code>/* Builds the response content */</code></i><br /> | |
<code>axiom_node_t *</code><br /> | |
<code>build_om_programatically(const | |
axis2_env_t *env, axis2_char_t *text)</code><br /> | |
<code>{</code><br /> | |
<code>    axiom_node_t *echo_om_node = NULL;</code><br /> | |
<code>    axiom_element_t* echo_om_ele = NULL;</code><br /> | |
<code>    axiom_node_t* text_om_node = NULL;</code><br /> | |
<code>    axiom_element_t * text_om_ele = NULL;</code><br /> | |
<code>    axiom_namespace_t *ns1 = NULL;</code><br /> | |
<code>Â Â Â Â </code><br /> | |
<code>    ns1 = axiom_namespace_create (env, "http://localhost:9090/axis2/services/echo", "ns1");</code><br | |
/> | |
<br /> | |
<code>    echo_om_ele = axiom_element_create(env, NULL, "echoString", ns1, &echo_om_node);</code><br | |
/> | |
<code>Â Â Â Â </code><br /> | |
<code>    text_om_ele = axiom_element_create(env, echo_om_node, "text", NULL, &text_om_node);</code><br | |
/> | |
<br /> | |
<code>    AXIOM_ELEMENT_SET_TEXT(text_om_ele, env, text, text_om_node);</code><br | |
/> | |
<code>Â Â Â Â </code><br /> | |
<code>Â Â Â Â </code><b><code>return</code></b><code>Â echo_om_node;</code><br /> | |
<code>}</code><br /> | |
</p> | |
<a name="Step3"></a> | |
<h4>Step3 :Write the services.xml file</h4> | |
<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 /> <parameter name="ServiceClass" locked="xsd:false">echo</parameter><br /> <description><br /> This is a echo service<br /> </description><br /><br /> <operation name="echoString"><br /> <parameter name="wsamapping"><br /> http://localhost:9090/axis2/services/echo/echoString<br /> </parameter><br /> </operation><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 /> | |
</p> | |
<code class="code"><serviceGroup><br /> <service name="Service1"><br /> <!-- details for Service1 --><br /> </service><br /> <service name="Service2"><br /> <!-- details for Service2 --><br /> </service><br /> <module ref="ModuleName" /><br /> <parameter name="serviceGroupParam1" locked="false">value 1</parameter><br /></serviceGroup></code> | |
<p><strong>Note :</strong> Name of the service is a compulsory attribute</p> | |
<a name="Step4"></a> | |
<h4>Step4 :Create the Web service folder in services folder of the | |
repository.</h4> | |
<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> | |
<a name="Step5"></a> | |
<h4>Step5 :Archive Based Deployment Model</h4> | |
<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> | |
<a name="Writing_Web_Services_Using_Code_Generator"></a> | |
<h3>Writing Web Services Skeleton Using Code Generator</h3> | |
<a id="WSDL2C_tool"></a> | |
<h4>WSDL2C tool</h4> | |
<p>Axis2/Java WSDL2C tool supports generation of Axis2/C stub and | |
skeleton. <a | |
href="http://svn.apache.org/viewvc/webservices/axis2/trunk/java">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">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> | |
<pre> | |
java org.apache.axis2.wsdl.WSDL2C -uri interoptestdoclitparameters.wsdl -ss -sd -d adb -u | |
</pre> | |
<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>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> | |
<a id="Implement_the_Business_Logic"></a> | |
<h4>Implement the Business Logic</h4> | |
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>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> | |
<a id="echoString"></a> | |
<h4>echoString</h4> | |
<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> | |
<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> | |
<p>Once the business logic is filled, it will be as follows. The code is | |
simple and the inline comments provide explanation.</p> | |
<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> | |
<h4><a id="echoStringArray">echoStringArray</a></h4> | |
<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> | |
<h4><a id="echoStruct">echoStruct</a></h4> | |
<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> | |
<h4><a id="services_xml">services.xml</a></h4> | |
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> | |
<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> | |
<a name="Web_Service_Clients_Using_Axis2"></a> | |
<h2>Web Service Clients Using Axis2/C</h2> | |
<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 border="1" cellpadding="0" cellspacing="0" width="100%"> | |
<tbody> | |
<tr> | |
<td><strong>API (Blocking/Non-Blocking)</strong></td> | |
<td><strong>Â Dual Transports (Yes/No)</strong></td> | |
<td><strong>Description</strong></td> | |
</tr> | |
<tr> | |
<td>Blocking</td> | |
<td>No</td> | |
<td>Simplest and the familiar invocation pattern</td> | |
</tr> | |
<tr> | |
<td>Non-Blocking</td> | |
<td>No</td> | |
<td>Using callbacks or polling</td> | |
</tr> | |
<tr> | |
<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> | |
<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> | |
<a name="Writing_Web_Service_Clients_using_Axis2%27s_Primary_APIs"></a> | |
<h3>Writing Web Service Clients Using Axis2's Primary APIs</h3> | |
<a id="EchoBlockingClient"></a> | |
<h4>echo_blocking Client</h4> | |
<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> | |
<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> | |
<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> | |
<a id="EchoNonBlockingClient"></a> | |
<h4>echo_non_blocking Client</h4> | |
<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> | |
<pre>AXIS2_SVC_CLIENT_SEND_RECEIVE_NON_BLOCKING(svc_client, env, payload, callback);</pre> | |
<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> | |
<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> | |
<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> | |
<pre>AXIS2_CALLBACK_SET_ON_COMPLETE(callback, echo_callback_on_complete);</pre> | |
<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> | |
<a id="EchoNonBlockingDualClient"></a> | |
<h4>echo_non_blocking_dual Client</h4> | |
<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/">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> | |
<pre>AXIS2_OPTIONS_SET_USE_SEPERATE_LISTENER(options, env, AXIS2_TRUE);</pre> | |
<p>In addition to setting the use_separate_listener to true, to use dual | |
transports one has to"engage" the addressing module.</p> | |
<h5>Engaging Addressing on Server Side</h5> | |
<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> | |
<pre> <module ref="addressing"/></pre> | |
<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> | |
<h5>Engaging Addressing on Client Side</h5> | |
<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> | |
<a id="EchoBlockingDualClient"></a> | |
<h4>echo_blocking_dual Client</h4> | |
<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> | |
<a id="Writing_Web_Clients_Using_Code_Generator"></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">Axis2/Java | |
source SVN</a> revision 414253 or later to generate Axis2/C code.</p> | |
<pre>java WSDL2C -uri interoptestdoclitparameters.wsdl -d adb -u</pre> | |
<p>In order to ignore the data binding support (to use XML in/out model), | |
just use the following parameters.</p> | |
<pre>java WSDL2C -uri interoptestdoclitparameters.wsdl -d none</pre> | |
<p>The following section demonstrates how to use the generated code using the | |
wsdl file "interoptestdoclitparameters.wsdl" to implement the client business | |
logic.</p> | |
<a id="Codegenerator_Client_echoString"></a> | |
<h4>Client for echoString operation</h4> | |
<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> | |
<a id="Codegenerator_Client_echoStringArray"></a> | |
<h4>Client for echoStringArray operation</h4> | |
You can change the <code>invoke_service_using_databinding</code> function to | |
invoke the echoStringArray operation as follows. | |
<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> | |
<a id="Codegenerator_Client_echoStruct"></a> | |
<h4>Client for echoStruct operation</h4> | |
<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> | |
<a id="Providing_security_using_Rampart"></a> | |
<h2>Providing Security using Rampart/C</h2> | |
<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> | |
<a id="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 /> <items>UsernameToken Timestamp</items><br /> <user>Gajaba</user><br /> <passwordType>passwordDigest</passwordType><br /> <passwordCallbackClass>/home/gajaba/axis2/c/deploy/rampart/samples/callback/libpwcb.so</passwordCallbackClass><br /> <timeToLive>360</timeToLive><br /> </action><br /> </parameter><br /> </p> | |
<p class="code"> <parameter name="InflowSecurity"><br /> | |
<action><br /> <items>UsernameToken | |
Timestamp</items><br /> | |
<passwordCallbackClass>/home/gajaba/axis2/c/deploy/rampart/samples/callback/libpwcb.so</passwordCallbackClass><br /> </action><br /> </parameter><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 /> <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><br /> <wsse:Username>Gajaba</wsse:Username><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 /> <wsse:Nonce>ICAgICAgIDEwNDY0NDk1Mg==</wsse:Nonce><br /> <wsu:Created>2006-08-28T11:52:27Z</wsu:Created><br /> </wsse:UsernameToken><br /> <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><br /> <wsu:Created>2006-08-28T11:52:27Z</wsu:Created><br /> <wsu:Expires>2006-08-28T11:58:27Z</wsu:Expires><br /> </wsu:Timestamp><br /></wsse:Security><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> | |
<pre class="code">./echo [endpoint_url] [path to your client_home]</pre> | |
<h3><a id="Semantics_of_parameters_specified_in_axis2_xml">Semantics of Parameters Specified in axis2.xml</a></h3> | |
<table border="1" cellpadding="0" cellspacing="0" width="100%"> | |
<tbody> | |
<tr> | |
<td><strong>Parameter</strong></td> | |
<td><strong>Semantic</strong></td> | |
</tr> | |
<tr> | |
<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> | |
<td>user</td> | |
<td>The username of the UsernameToken</td> | |
</tr> | |
<tr> | |
<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> | |
<td>passwordCallbackClass</td> | |
<td>The module that provides the password for a particular user</td> | |
</tr> | |
<tr> | |
<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> | |
<a id="Writing_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> | |
<pre class="code">rcb->ops->callback_password = get_sample_password;</pre> | |
<p><code>callback_password</code> is a function pointer to any function which | |
has the following signature.</p> | |
<pre class="code"><code>axis2_char_t</code>* | |
your_function(rampart_callback_t *rcb, | |
const axis2_env_t *env, const axis2_char_t *username)</pre> | |
<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> | |
<a id="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> | |
<pre class="code"> 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> | |
<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> | |
<h2>References</h2> | |
<ul> | |
<li>Introducing Apache Axis2/C - <a | |
href="http://www.wso2.net/articles/axis2/c/2006/09/04/introduction">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">http://www.wso2.net/articles/rampart/c/2006/09/19/introduction</a></li> | |
</ul> | |
</body> | |
</html> |