C Language

You are currently browsing the archive for the C Language category.

This will not serve as a comprehensive tutorial in developing services and clients for Axis2/C, but rather intended to provide some help for starters.

Apache Axis2/C is an engine for web services developed in C – there’s another implementation in Java. You can find an illustration of SOA here.

You first need to download and install Apache Axis2/C 1.3.0. You can download the binaries or sources from the Apache Axis2/C website. It would be easier to install the binaries if you are a beginner.

So let’s get started with developing a service. We’ll create a service to sort a set of integers in ascending or descending order.

Service

The service should have two functions:

  • axis2_get_instant – creates the service skeleton
  • axis2_remove_instant – removes the instant

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
AXIS2_EXPORT int
  axis2_get_instance(axis2_svc_skeleton_t **inst,
                     const axutil_env_t *env)
{
 *inst = axis2_sort_create(env);
 if (!(*inst))
  return AXIS2_FAILURE;
 
 return AXIS2_SUCCESS;
}
 
AXIS2_EXPORT int
  axis2_remove_instance(axis2_svc_skeleton_t *inst,
                        const axutil_env_t *env)
{
 if (inst)
  return AXIS2_SVC_SKELETON_FREE(inst, env);
 
 return AXIS2_FAILURE;
}
 
/* Create the service skeleton */
axis2_svc_skeleton_t *
  axis2_sort_create(const axutil_env_t *env)
{
 axis2_svc_skeleton_t *svc_skeleton = NULL;
 svc_skeleton = AXIS2_MALLOC(env->allocator,
                             sizeof(axis2_svc_skeleton_t));
 
 svc_skeleton->ops = &sort_svc_skeleton_ops_var;
 
 svc_skeleton->func_array = NULL;
 
 return svc_skeleton;
}

axis2_get_instant should create axis2_svc_skeleton struct with corresponding functions assigned. These functions are

  1. init – initializes the skeleton
  2. invoke – invokes the service
  3. on_fault – this is called when an fault is detected
  4. free – frees the skeleton instant

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* Functions for axis2_svc_skeleton */
int AXIS2_CALL
  sort_free(axis2_svc_skeleton_t *svc_skeleton,
            const axutil_env_t *env);
 
axiom_node_t* AXIS2_CALL
  sort_invoke(axis2_svc_skeleton_t *svc_skeleton,
              const axutil_env_t *env,
              axiom_node_t *node,
              axis2_msg_ctx_t *msg_ctx);
 
int AXIS2_CALL
  sort_init(axis2_svc_skeleton_t *svc_skeleton,
            const axutil_env_t *env);
 
axiom_node_t* AXIS2_CALL
  sort_on_fault(axis2_svc_skeleton_t *svc_skeli,
                const axutil_env_t *env, axiom_node_t *node);
 
/* Skeleton */
static const axis2_svc_skeleton_ops_t sort_svc_skeleton_ops_var = {
 sort_init,
 sort_invoke,
 sort_on_fault,
 sort_free
};

Now comes the main part of the service – implementation of the invoke function.

This function will be called with a reference to request. The XML request will be passed as a axiom_node_t, and you can navigate through it easily using functions axiom_node_get_first_child and axiom_node_get_next_sibling.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* Process the request */
axiom_node_t* AXIS2_CALL
  sort_invoke(axis2_svc_skeleton_t *svc_skeleton,
               const axutil_env_t *env,
               axiom_node_t *node,
               axis2_msg_ctx_t *msg_ctx)
{
 return axis2_sort(env, node);
}
 
 /* Process the request */
axiom_node_t *
  axis2_sort(const axutil_env_t *env, axiom_node_t *node)
{
 AXIS2_ENV_CHECK(env, NULL);
 
 if(!node) return sort_error(env);
 
 axiom_node_t *order_node = axiom_node_get_first_child(node, env);
 axis2_char_t *order_str = get_string(order_node, env);
 
 if(!order_str) return sort_error(env);
 
 axiom_node_t *list = axiom_node_get_next_sibling(order_node, env);
 
 if(!list) return sort_error(env);
 
 axiom_node_t* current = axiom_node_get_first_child(list, env);
 
 if(!current) return sort_error(env);
 
 int i;
 
 a = AXIS2_MALLOC(env->allocator,
                  sizeof(long int) * MAX);
 
 for(i = 0; i < MAX && current; i++)
 {
  axis2_char_t *str = get_string(current, env);
  a[i] = strtol(str, NULL, 10);
 
  current = axiom_node_get_next_sibling(current, env);
 }
 
 int N = i;
 
 if(axutil_strcmp(order_str, "asc"))
  return build_sort_response(env, N, 1);
 else if(axutil_strcmp(order_str, "des"))
  return build_sort_response(env, N, -1);
 else
  return sort_error(env);
}

After parsing the input you should calculate and prepare the response of the service.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* Generate the response */
axiom_node_t *
  build_sort_response(const axutil_env_t *env, int N, int order)
{
 axis2_char_t value_str[255];
 axiom_node_t *main_node;
 int i, j;
 
 for(i = 0; i < N; i++)
  for(j = 1; j < N; j++)
   if((a[j] - a[j-1]) * order > 0)
 {
  long int temp = a[j];
  a[j] = a[j-1];
  a[j-1] = temp;
 }
 
 axiom_namespace_t *ns1 = axiom_namespace_create(env, "http://axis2/test/sort", "ns1");
 
 axiom_element_create(env, NULL, "result", ns1, &main_node);
 
 for(i = 0 ; i < N; i++)
 {
  axiom_node_t *value_node;
 
  sprintf(value_str, "%ld", a[i]);
 
  axiom_element_t *value_ele = axiom_element_create(env, main_node, "value", NULL, &value_node);
  axiom_element_set_text(value_ele, env, value_str, value_node);
 }
 
 AXIS2_FREE(env->allocator, a);
 
 return main_node;
}

That’s it now we have created the service, but we need to create the service descriptor services.xml

1
2
3
4
5
<service name="sort">
 <parameter name="ServiceClass" locked="xsd:false">sort</parameter>
 <description>Sort service example.</description>
 <operation name="sort"/>
</service>

Here’s the code of the service: sort_service.c and the descriptor: services.xml.

Then compile the service using gcc

gcc -shared -olibsort.so -I$AXIS2C_HOME/include/axis2-1.3.0/ -L$AXIS2C_HOME/lib -laxutil -laxis2_axiom -laxis2_parser -laxis2_engine -lpthread -laxis2_http_sender -laxis2_http_receiver sort_service.c

The environment variable AXIS2C_HOME should be set to the axis2 installation folder.

Copy libsort.so and services.xml to folder AXIS2C_HOME/services/sort/.

Now start the axis server or restart if it’s already running, buy executing axis2_http_server. And check if the service is correctly deployed by checking http://localhost:9090/axis2/services.

Now that the service is running fine we can start creating the client.

Client

First we should set the properties and create the svc client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 const axis2_char_t *client_home = NULL;
 axis2_svc_client_t* svc_client = NULL;
 axiom_node_t *payload = NULL;
 axiom_node_t *ret_node = NULL;
 
 /* Create environment */
 axutil_env_t *env = axutil_env_create_all("sort_client.log", AXIS2_LOG_LEVEL_TRACE);
 
 /* Location of the service */
 axis2_char_t *address = "http://localhost:9090/axis2/services/sort";
 printf("Using address : %s\n", address);
 
 /* Creating options */ 
 axis2_options_t *options = axis2_options_create(env);
 axis2_endpoint_ref_t* endpoint_ref = axis2_endpoint_ref_create(env, address);
 axis2_options_set_to(options, env, endpoint_ref);
 
 /* Creating svc client */
 client_home = AXIS2_GETENV("AXIS2C_HOME");
 if (!client_home && !strcmp(client_home, ""))
 {
  printf("AXIS2C_HOME not set\n");
  return -1;
 }
 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));
  return -1;
 }
 axis2_svc_client_set_options(svc_client, env, options);

Then build the request.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
axiom_node_t *
   build_om_request(const axutil_env_t *env)
{
 axiom_node_t *main_node;
 axiom_node_t *order_node;
 axiom_node_t *values_node;
 axis2_char_t value_str[255];
 int i;
 
 
 axiom_namespace_t *ns1 = axiom_namespace_create(env, "http://axis2/test/sort", "ns1");
 
 axiom_element_create(env, NULL, "sort", ns1, &main_node);
 
 axiom_element_t *order_ele = axiom_element_create(env, main_node, "order", NULL, &order_node);
 axiom_element_set_text(order_ele, env, "des", order_node);
 
 axiom_element_t *values_ele = axiom_element_create(env, main_node, "values", NULL, &values_node);
 
 int N = 20;
 
 for(i = 0 ; i < N; i++)
 {
  axiom_node_t *value_node;
 
  sprintf(value_str, "%ld", i + 100);
 
  axiom_element_t *value_ele = axiom_element_create(env, values_node, "value", NULL, &value_node);
  axiom_element_set_text(value_ele, env, value_str, value_node);
 }
 
 return main_node;
}

Send the request.

1
ret_node = axis2_svc_client_send_receive(svc_client, env, payload);

Here’s the code of the service: sort_client.c. Now compile the client.

gcc -o sort_client -I$AXIS2C_HOME/include/axis2-1.3.0/ -L$AXIS2C_HOME/lib -laxutil -laxis2_axiom -laxis2_parser -laxis2_engine -lpthread -laxis2_http_sender -laxis2_http_receiver sort_client.c -ldl -Wl,--rpath -Wl,$AXIS2C_HOME/lib

Run it

Run the client to see what happens.

What happens if the client sends an empty request?

Tags: , , , ,