| <?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 xmlns="http://www.w3.org/1999/xhtml"> |
| <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 Developer Guide</title> |
| <meta name="generator" content="amaya 8.5, see http://www.w3.org/Amaya/" /> |
| </head> |
| |
| <body xml:lang="en"> |
| <h1>Axis2/C Developer Guide</h1> |
| |
| <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> |
| |
| <h2>Content</h2> |
| |
| <p>This guide walks you through the following topics that might help you get |
| familiar with the Axis2/C project and its development norms in quick time.</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> |
| <a id="Programming_Model"></a> |
| |
| <h2>Programming Model</h2> |
| |
| <p>Axis2/C programming model uses a pseudo object oriented model to achieve |
| data hiding. The following example illustrates how this is done in Axis2/C. |
| 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 function 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> |
| <pre class="code"> |
| 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)->ops->bar(foo, env, data)) |
| #define AXIS2_FOO_FREE(foo, env)\ |
| ((foo)->ops->free(foo, env))</pre> |
| |
| <p></p> |
| |
| <p>The implementation file for "foo" struct is shown below.</p> |
| <pre class="code"><strong>/* foo.c */</strong> |
| #include <axis2_foo.h> |
| |
| 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->foo.ops->bar = axis2_foo_bar; |
| foo_impl->foo.ops->free = axis2_foo_free; |
| |
| return &(foo_impl->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> |
| <a id="Memory_Management"></a> |
| |
| <p>If you had a closer look into the given 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> |
| |
| <h2>Memory Management</h2> |
| |
| <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> |
| |
| <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> |
| <pre class="code"> |
| 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> |
| |
| <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> |
| <pre class="code">int AXIS2_CALL math_free(axis2_svc_skeleton_t *svc_skeleton, const axis2_env_t *env) |
| { |
| if(svc_skeleton->ops) |
| { |
| AXIS2_FREE(env->allocator, svc_skeleton->ops); |
| svc_skeleton->ops = NULL; |
| } |
| if(svc_skeleton->func_array) |
| { |
| AXIS2_ARRAY_LIST_FREE(svc_skeleton->func_array, env); |
| svc_skeleton->func_array = NULL; |
| } |
| if(svc_skeleton) |
| { |
| AXIS2_FREE(env->allocator, svc_skeleton); |
| svc_skeleton = NULL; |
| } |
| return AXIS2_SUCCESS; |
| }</pre> |
| |
| <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> |
| <pre class="code">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->allocator, sizeof(axis2_svc_skeleton_t)); |
| |
| svc_skeleton->ops = AXIS2_MALLOC(env->allocator, sizeof(axis2_svc_skeleton_ops_t)); |
| |
| svc_skeleton->ops->free = math_free; |
| ... |
| return svc_skeleton; |
| } |
| </pre> |
| |
| <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> |
| |
| <h3>Memory management guidelines for developing clients</h3> |
| 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. |
| |
| <p> <a id="Coding_Conventions"></a></p> |
| |
| <h2>Coding Conventions</h2> |
| |
| <p>Coding conventions used with the Axis2 project is listed in <a |
| href="../coding_conventions.html">this</a> document.</p> |
| <a id="Unit_and_System_Tests"></a> |
| |
| <h2>Unit Tests</h2> |
| |
| <p><a href="http://cutest.sourceforge.net/">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> |
| 1. Add the unit test to the module's test suite. |
| |
| <p>2. Add the module's test suite to the main unit test suite.</p> |
| |
| <p></p> |
| |
| <h4>Step1: Adding a unit test to a module's unit test suite</h4> |
| |
| <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 util_stream_test.c/.h placed into modules/util/test folder. Here's a |
| sample code written to test the operation |
| <code>axis2_stream_ops_read</code>.</p> |
| <pre class="code"> |
| #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->stream, actual, 10); |
| char *expected = strdup("aaaaaaaaa"); |
| CuAssertStrEquals(tc, expected, actual); |
| } |
| </pre> |
| |
| <p>The prototype of the function should be added to the header file. The test |
| suite is defined in util_test.c. You need to add the above defined test case |
| to the test suite as shown below.</p> |
| <pre class="code">#include "util_test.h" |
| #include <axis2_allocator.h> |
| #include <axis2_environment.h> |
| |
| 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> |
| |
| <h4>Step2: Adding the Module test suite to the Main Unit Test Suite</h4> |
| |
| <p>Now you need to add the util module test suite to the main test suite.</p> |
| <pre class="code">#include <CuTest.h> |
| #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->buffer); |
| } |
| |
| int main(void) |
| { |
| RunAllTests(); |
| return 0; |
| } |
| </pre> |
| |
| <p>You can either run only the unit tests written for the util module or run |
| all the tests.</p> |
| </body> |
| </html> |