blob: a9ad794c25c48db3781143611f65cb8f978dcd24 [file] [log] [blame]
<!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 Developer 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/viewcvs.cgi/webservices/axis2/trunk/c/" 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="Axis2_C_Developer_Guide"></a><h2>Axis2/C Developer Guide</h2><p>Please send your feedback to developer mailing list: <a href="mailto:axis-c-dev@ws.apache.org">axis-c-dev@ws.apache.org</a> (Please
remember to prefix the subject with [Axis2]). To subscribe to developer
mailing lists see <a href="../mail-lists.html">here</a>.</p><div class="subsection"><a name="Content"></a><h3>Content</h3><p>This guide walks you through the following topics with the aim of helping you get
familiar with the Axis2/C project and its development norms quickly.</p><ul>
<li><a href="#Programming_Model">Programming model</a></li>
<li><a href="#Memory_Management">Memory management</a></li>
<li><a href="#Coding_Conventions">Coding conventions</a></li>
<li><a href="#Unit_Tests">Unit tests</a></li>
</ul><p><a id="Programming_Model"></a></p></div><div class="subsection"><a name="Programming_Model"></a><h3>Programming Model</h3><p>Axis2/C programming model uses a pseudo object oriented model to achieve
data hiding. The following example illustrates how this is done.
Each struct corresponds to the "class" concept in object oriented
programming. Hence, each struct has its own header file, that exposes the API
for that struct and a source file, that contains the functional
implementation.</p><p>Operations associated with a struct are bundled into an operations struct
('ops' struct), and this ops struct is exposed in the header file. The real
implementation struct ('impl' struct) with the data fields is hidden from the
user, and lives in the source file. To ease the user from the complex syntax
required to access the functions in a given ops struct, macros are provided
to access them. Since the data is hidden, it is the usual practice to provide
*getter* and *setter* methods for the data fields of the struct, in addition to
the other processing functionality. The actual functional implementations in
the source file are mapped to the ops struct functions declared in the header
file by means of function pointer assignments.</p><p>Here is a sample header file associated with the "foo" struct. (Imagine a
class called "foo" in the proper object oriented programming model.)</p><strong>/* axis2_ foo.h */</strong>
<div class="source"><pre>
typedef struct axis2_foo_ops axis2_foo_ops_t;
typedef struct axis2_foo axis2_foo_t;
struct axis2_foo_ops
{
void (AXIS2_CALL *bar)(axis2_foo_t *foo, const axis2_env_t *env, void *data);
axis2_status_t (AXIS2_CALL *free)(axis2_foo_t *foo, const axis2_env_t *env);
};
struct axis2_foo
{
axis2_foo_ops_t *ops;
}
axis2_foo_t * axis2_foo_create(const axis2_env_t *env);
/* Macros are provided to access functions defined in the ops structure */
#define AXIS2_FOO_BAR(foo, env, data)\
((foo)-&gt;ops-&gt;bar(foo, env, data))
#define AXIS2_FOO_FREE(foo, env)\
((foo)-&gt;ops-&gt;free(foo, env))
</pre></div>
<p></p><p>The implementation file for "foo" struct is shown below.</p>
<div class="source"><pre>
#include &lt;axis2_foo.h&gt;
typedef struct axis2_foo_impl axis2_foo_impl_t;
struct axis2_foo_impl
{
axis2_foo_t foo;
my_type my_data; /*private data*/
};
/* Function Headers */
void AXIS2_CALL axis2_foo_bar(axis2_foo_t *foo, const axis2_env_t *env, void *data);
axis2_status_t AXIS2_CALL axis2_foo_free(axis2_foo_t *foo, const axis2_env_t *env);
/* Function Implementations */
axis2_foo_t * AXIS2_CALL axis2_foo_create(const axis2_env_t *env)
{
axis2_foo_impl_t * foo_impl = NULL;
/* create axis2_foo_impl_t structure and initialize private data */
/* create ops structure of foo */
/* bind ops to functions */
foo_impl-&gt;foo.ops-&gt;bar = axis2_foo_bar;
foo_impl-&gt;foo.ops-&gt;free = axis2_foo_free;
return &amp;(foo_impl-&gt;foo);
}
void AXIS2_CALL axis2_foo_bar(axis2_foo_t *foo, const axis2_env_t *env, void *data)
{
/* do something */
}
axis2_status_t AXIS2_CALL axis2_foo_free(axis2_foo_t *foo, const axis2_env_t *env)
{
/* do the dirty work of cleaning the allocated memory */
}
</pre></div>
<p><a id="Memory_Management"></a></p><p>If you take a closer look at the sample above, you will see that
almost all functions take a double pointer to the axis2_env struct. To learn
more about the Axis2/C environment, please have a look at the <a href="architecture_notes.html">architecture notes</a>.</p></div><div class="subsection"><a name="Memory_Management"></a><h3>Memory Management</h3><p>When writing services as well as client programs, you have to ensure that
you do proper memory management. You need to be careful to deallocate the
memory you have allocated in order to avoid memory leaks (and to avoid those
nasty segmentation faults ;-) ). Remebering where you allocate memory is a
good practice, which will help you to properly free such allocated memory.</p></div><div class="subsection"><a name="Memory_Management_Guidelines_for_Developing_Services"></a><h3>Memory Management Guidelines for Developing Services</h3><p>To understand how the allocated memory is reclaimed, it is worth looking
at the service skeleton interface which is defined in :
<strong>axis2_svc_skeleton.h</strong></p>
<div class="source"><pre>
AXIS2_DECLARE_DATA struct axis2_svc_skeleton_ops
{
int (AXIS2_CALL * free)(axis2_svc_skeleton_t *svc_skeli, const axis2_env_t *env);
...
};
AXIS2_DECLARE_DATA struct axis2_svc_skeleton
{
axis2_svc_skeleton_ops_t *ops;
axis2_array_list_t *func_array;
};
</pre></div>
<p></p><p>The service skeleton implementation should implement the <code>free</code>
function and attach that to the ops struct of
<code>axis2_svc_skeleton_t</code> struct. This <code>free</code> function is
called each time after a web services request is served.</p><p>Let's try to understand this through an example.</p><p></p><p>Example: <b>Service skeleton implementation for math service.</b></p><p>The following code shows the implementation of <code>math_free</code>
function which is to be attached to the ops of
<code>axis2_svc_skeleton_t</code> struct. Usually the memory allocated for
the operations struct, the function array and the service skeleton struct are
cleaned inside this. You may clean additional memory here if you have
allocated any specific memory blocks in <code>math_create</code> function or
elsewhere, depending on your implementation specifics.</p><p></p>
<div class="source"><pre>int AXIS2_CALL math_free(axis2_svc_skeleton_t *svc_skeleton, const axis2_env_t *env)
{
if(svc_skeleton-&gt;ops)
{
AXIS2_FREE(env-&gt;allocator, svc_skeleton-&gt;ops);
svc_skeleton-&gt;ops = NULL;
}
if(svc_skeleton-&gt;func_array)
{
AXIS2_ARRAY_LIST_FREE(svc_skeleton-&gt;func_array, env);
svc_skeleton-&gt;func_array = NULL;
}
if(svc_skeleton)
{
AXIS2_FREE(env-&gt;allocator, svc_skeleton);
svc_skeleton = NULL;
}
return AXIS2_SUCCESS;
}
</pre></div>
<p></p><p>In the <code>axis2_math_create</code> function, you assign the function
pointer of <code>math_free</code> function to the <code>free</code> function
of the operations struct. As you can see, now the SOAP engine has a function
reference to perform garbage collection after each service request.</p><p></p>
<div class="source"><pre>AXIS2_EXTERN axis2_svc_skeleton_t * AXIS2_CALL axis2_math_create(const axis2_env_t *env)
{
axis2_svc_skeleton_t *svc_skeleton = NULL;
svc_skeleton = AXIS2_MALLOC(env-&gt;allocator, sizeof(axis2_svc_skeleton_t));
svc_skeleton-&gt;ops = AXIS2_MALLOC(env-&gt;allocator, sizeof(axis2_svc_skeleton_ops_t));
svc_skeleton-&gt;ops-&gt;free = math_free;
...
return svc_skeleton;
}
</pre></div>
<p>SOAP engine frees the memory allocated for the <code>axiom_node_t</code>
struct that is used to form the response SOAP message. However, it is the
responsibility of the service developer to clean any additional memory
allocated.</p><p></p></div><div class="subsection"><a name="Memory_Management_Guidelines_for_Developing_Clients"></a><h3>Memory Management Guidelines for Developing Clients</h3><p>
Most of the memory allocated in the client side (including SOAP request and
reply messges), should be cleaned in the client side itself. Memory allocated
for properties are taken care of by the SOAP engine. SOAP engine reclaims the
memory allocated for properties based on the scope (Request, Session or
Application) that you set for each property.
<a id="Coding_Conventions"></a></p></div><div class="subsection"><a name="Coding_Conventions"></a><h3>Coding Conventions</h3><p>Coding conventions used with the Axis2 project is listed in <a href="../coding_conventions.html">this</a> document.</p><p><a id="Unit_Tests"></a></p></div><div class="subsection"><a name="Unit_Tests"></a><h3>Unit Tests</h3><p><a href="http://cutest.sourceforge.net/" class="externalLink" title="External Link">CuTest</a> library is used to
write unit tests in Axis2/C.</p><p>You need to follow two steps to write a unit test for a module.</p><p>
1. Add the unit test to the module's test suite.
</p><p>2. Add the module's test suite to the main unit test suite.</p><p></p></div><div class="subsection"><a name="Step1:_Adding_a_unit_test_to_a_module_s_unit_test_suite"></a><h3>Step1: Adding a unit test to a module's unit test suite</h3><p>This section illustrates how to add a unit test case to the util module.
Let's take, for example, the unit tests for axis2 stream. There are two files
named <code>util_stream_test.c/.h</code> placed into modules/util/test folder. Here's a
sample code written to test the operation
<code>axis2_stream_ops_read</code>.</p>
<div class="source"><pre>
#include "util_stream_test.h"
void Testaxis2_stream_ops_read(CuTest *tc)
{
char actual[10];
axis2_allocator_t *allocator = axis2_allocator_init(NULL);
axis2_env_t *env = axis2_environment_create(allocator, NULL, NULL, NULL, NULL);
axis2_stream_read(env-&gt;stream, actual, 10);
char *expected = strdup("aaaaaaaaa");
CuAssertStrEquals(tc, expected, actual);
}
</pre></div>
<p>The prototype of the function should be added to the header file. The test
suite is defined in <code>util_test.c</code>. You need to add the above defined test case
to the test suite as shown below.</p>
<div class="source"><pre>#include "util_test.h"
#include &lt;axis2_allocator.h&gt;
#include &lt;axis2_environment.h&gt;
CuSuite* axis2_utilGetSuite()
{
CuSuite* suite = CuSuiteNew();
SUITE_ADD_TEST(suite, Testaxis2_stream_ops_read);
SUITE_ADD_TEST(suite, Testaxis2_log_ops_write);
SUITE_ADD_TEST(suite, Testaxis2_hash_ops_get);
return suite;
}
</pre></div>
</div><div class="subsection"><a name="Step2:_Adding_the_Module_test_suite_to_the_Main_Unit_Test_Suite"></a><h3>Step2: Adding the Module test suite to the Main Unit Test Suite</h3><p>Now, you need to add the util module test suite to the main test suite.</p>
<div class="source"><pre>#include &lt;CuTest.h&gt;
#include "../../util/test/util_test.h"
#include "../../common/test/common_test.h"
void RunAllTests(void)
{
CuString *output = CuStringNew();
CuSuite* suite = CuSuiteNew();
CuSuiteAddSuite(suite, axis2_utilGetSuite());
CuSuiteAddSuite(suite, axis2_commonGetSuite());
CuSuiteRun(suite);
CuSuiteSummary(suite, output);
CuSuiteDetails(suite, output);
printf("%s\n", output-&gt;buffer);
}
int main(void)
{
RunAllTests();
return 0;
}
</pre></div>
<p>You can either run only the unit tests written for the util module or
all the tests.</p></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>