Index: developerguide.html =================================================================== --- developerguide.html (revision 437531) +++ developerguide.html (working copy) @@ -3,15 +3,15 @@ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> + Axis2/C Developer Guide - +

Axis2/C Developer Guide

-

Please send your feedback to developer mailing list: axis-c-dev@ws.apache.org (Please remember to prefix the subject with [Axis2]). To subscribe to developer @@ -25,7 +25,7 @@

  • Programming model
  • Memory management
  • Coding conventions
  • -
  • Unit and System tests
  • +
  • Unit tests
  • @@ -38,18 +38,19 @@ for that struct and a source file, that contains the functional implementation.

    -

    Operations associated with a struct are bundled into an operations struct, -and the operations struct is exposed in the header file. The real -implementation struct with the data fields is hidden from the user, and lives -in the source file. To ease the user from using the complex syntax required -by the use of the operations struct, macros are provided to access the -functions associated with a given struct. 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. Actual -function implementations are mapped to the functions in the operations struct -in the source file by means of function pointer assignments.

    +

    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.

    -

    Here is a sample header file associated with the "foo" struct.

    +

    Here is a sample header file associated with the "foo" struct. (Imagine a +class called "foo" in the proper object oriented programming model.)

    /* axis2_ foo.h */
     
     typedef struct axis2_foo_ops axis2_foo_ops_t;
    @@ -69,13 +70,15 @@
     
     axis2_foo_t * axis2_foo_create(const axis2_env_t *env);
     
    -/* Macros are provided to access functions defined in the ops (operations structure)*/
    +/* Macros are provided to access functions defined in the ops structure */
     
    -#define AXIS2_FOO_BAR(foo, data)\ 
    -            ((foo)->ops->bar(data))
    +#define AXIS2_FOO_BAR(foo, env, data)\ 
    +            ((foo)->ops->bar(foo, env, data))
     #define AXIS2_FOO_FREE(foo, env)\
    -            ((for)->ops->free(env, foo))
    + ((foo)->ops->free(foo, env)) +

    +

    The implementation file for "foo" struct is shown below.

    /* foo.c */
     #include <axis2_foo.h>
    @@ -88,31 +91,33 @@
         my_type my_data; /*private data*/
     };
     
    +
     /* Function Headers */
     
    -void AXIS2_CALL axis2_foo_bar(void *data);
    -axis2_status_t AXIS2_CALL axis2_foo_free(const axis2_env_t *env, axis2_foo_t *foo);
    +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 Implementation */
    +/* 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_t and initialize private data */
    +    /* 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(void *data)
    +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(const axis2_env_t *env, axis2_foo_t *foo)
    +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 */
     }
    @@ -120,22 +125,24 @@

    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 on environment used in Axis2/C, please have a look into the architecture notes.

    Memory Management

    -

    When writing services, as well as client programs, you have to ensure that -you do proper memory management. You need to be aware of the parts of the -memory you have allocated to deallocate in order to avoid memory leaks (and -to avoid those nasty segmentation faults ;-) ).

    +

    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.

    Memory Management Guidelines for Developing Services

    -

    To understand, how the allocated memory is reclaimed, it is worth looking +

    To understand how the allocated memory is reclaimed, it is worth looking at the service skeleton interface which is defined in axis2_svc_skeleton.h

    -
    AXIS2_DECLARE_DATA struct axis2_svc_skeleton_ops
    +
    +AXIS2_DECLARE_DATA struct axis2_svc_skeleton_ops
     {
         int (AXIS2_CALL * free)(axis2_svc_skeleton_t *svc_skeli, const axis2_env_t *env);
         ...
    @@ -147,20 +154,28 @@
         axis2_array_list_t *func_array;
     };
    -

    The service skeleton implementation should implement the free function and -attach that to the operations struct of axis2_svc_skeleton_t struct. This -free function is called each time after web services request is served.

    +

    +

    The service skeleton implementation should implement the free +function and attach that to the ops struct of +axis2_svc_skeleton_t struct. This free function is +called each time after a web services request is served.

    +

    Let's try to understand this through an example.

    +

    +

    Example: Service skeleton implementation for math service.

    -

    The following code shows the implementation of math_free function which is -to be attached to the ops of axis2_svc_skeleton_t struct. Usually the memory -allocated for operations struct, function array and service skeleton struct -are cleaned in this. You may clean additional memory here if you have -allocated any specific memory blocks in math_create function or elsewhere -depending on your implementation specifics.

    +

    The following code shows the implementation of math_free +function which is to be attached to the ops of +axis2_svc_skeleton_t 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 math_create function or +elsewhere, depending on your implementation specifics.

    + +

    int AXIS2_CALL math_free(axis2_svc_skeleton_t *svc_skeleton, const axis2_env_t *env)
     {
         if(svc_skeleton->ops)
    @@ -181,10 +196,14 @@
         return AXIS2_SUCCESS;
     }
    -

    In the axis2_math_create function you assign the function pointer of -math_free function to the free 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.

    +

    + +

    In the axis2_math_create function, you assign the function +pointer of math_free function to the free 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.

    + +

    AXIS2_EXTERN axis2_svc_skeleton_t * AXIS2_CALL axis2_math_create(const axis2_env_t *env)
     {
         axis2_svc_skeleton_t *svc_skeleton = NULL;
    @@ -192,33 +211,36 @@
     
         svc_skeleton->ops = AXIS2_MALLOC(env->allocator, sizeof(axis2_svc_skeleton_ops_t));
     
    -
         svc_skeleton->ops->free = math_free;
         ...
         return svc_skeleton;
    -}
    +} +
    -

    SOAP engine frees the memory allocated for the axiom_node_t struct that -is used to from the response SOAP message. However, it is the responsibility -of the service developer to clean any additional memory allocated.

    +

    SOAP engine frees the memory allocated for the axiom_node_t +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.

    +

    +

    Memory management guidelines for developing clients

    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. +Application) that you set for each property. +

    +

    Coding Conventions

    Coding conventions used with the Axis2 project is listed in this document.

    -

    Unit and System Tests

    +

    Unit Tests

    -

    Unit Tests

    -

    CuTest library is used to write unit tests in Axis2/C.

    @@ -227,23 +249,28 @@

    2. Add the module's test suite to the main unit test suite.

    +

    +

    Step1: Adding a unit test to a module's unit test suite

    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 +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 axis2_stream_ops_read.

    -
    #include "util_stream_test.h"
    +sample code written to test the operation
    +axis2_stream_ops_read.

    +
    +#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_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);
    -}
    +} +

    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 @@ -256,15 +283,17 @@ { CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, Testaxis2_stream_ops_write); + 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; -} +} +

    Step2: Adding the Module test suite to the Main Unit Test Suite

    -

    Now you need to add the Util module test suite to the main test suite.

    +

    Now you need to add the util module test suite to the main test suite.

    #include <CuTest.h>
     #include "../../util/test/util_test.h"
     #include "../../common/test/common_test.h"
    @@ -286,44 +315,10 @@
     {   
         RunAllTests();
         return 0;
    -}
    +} +

    You can either run only the unit tests written for the util module or run all the tests.

    - -

    System Tests

    - -

    For each module, system tests should be provided in -modules/test/<module folder>. For each system test you need to add a -new function and call it from the main method.

    - -

    Example:

    - -

    To test the AXIOM module, you need to create a file named test_om.c under the -directory modules/test/xml/om. A sample test_om.c might look like as -follows.

    -
    #include <axiom_stax_builder.h>
    -#include <axiom_document.h>
    -#include <axiom_node.h>
    -#include <axiom_element.h>
    -#include <axiom_text.h>
    -#include <axis2_xml_reader.h>
    -
    -int test_om_build()
    -{
    -    axis2_xml_reader_t *reader = NULL;  
    -    axiom_node_t *node1 = NULL ,*node2 = NULL ,*node3 = NULL;
    -    axiom_element_t *ele1=NULL,*ele2=NULL,*ele3 = NULL;
    -    axis2_stax_om_builder_t *builder = NULL;
    -    axiom_document_t *document = NULL;
    -    
    -    ...
    -}
    -
    -int main(void)
    -{
    -    test_om_build();
    -    test_om_serialize();
    -}