本文承接Axis2/C入门教程之一,详细分析服务端代码hello_svc.c的实现。
hello_svc.c代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
axiom_node_t *axis2_hello_greet(const axutil_env_t *env, axiom_node_t *node);
int AXIS2_CALL hello_free(axis2_svc_skeleton_t *svc_skeleton, const axutil_env_t *env);
axiom_node_t* AXIS2_CALL hello_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 hello_init(axis2_svc_skeleton_t *svc_skeleton, const axutil_env_t *env);
axiom_node_t* AXIS2_CALL hello_on_fault(axis2_svc_skeleton_t *svc_skeli, const axutil_env_t *env, axiom_node_t *node);
axiom_node_t * build_greeting_response(const axutil_env_t *env, axis2_char_t *greeting);
axiom_node_t * axis2_hello_greet(const axutil_env_t *env, axiom_node_t *node)
{
axiom_node_t *client_greeting_node = NULL;
axiom_node_t *return_node = NULL;
AXIS2_ENV_CHECK(env, NULL);
if (node)
{
client_greeting_node = axiom_node_get_first_child(node, env);
if (client_greeting_node &&
axiom_node_get_node_type(client_greeting_node, env) == AXIOM_TEXT)
{
axiom_text_t *greeting = (axiom_text_t *)axiom_node_get_data_element(client_greeting_node, env);
if (greeting && axiom_text_get_value(greeting , env))
{
const axis2_char_t *greeting_str = axiom_text_get_value(greeting, env);
printf("Client greeted saying \"%s\" \n", greeting_str);
return_node = build_greeting_response(env, "Hello Client!");
}
}
}
else
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST, AXIS2_FAILURE);
printf("ERROR: invalid XML in request\n");
return_node = build_greeting_response(env, "Client! Who are you?");
}
return return_node;
}
axiom_node_t * build_greeting_response(const axutil_env_t *env, axis2_char_t *greeting)
{
axiom_node_t* greeting_om_node = NULL;
axiom_element_t * greeting_om_ele = NULL;
greeting_om_ele = axiom_element_create(env, NULL, "greetResponse", NULL, &greeting_om_node);
axiom_element_set_text(greeting_om_ele, env, greeting, greeting_om_node);
return greeting_om_node;
}
static const axis2_svc_skeleton_ops_t hello_svc_skeleton_ops_var =
{
hello_init,
hello_invoke,
hello_on_fault,
hello_free
};
axis2_svc_skeleton_t * axis2_hello_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 = &hello_svc_skeleton_ops_var;
svc_skeleton->func_array = NULL;
return svc_skeleton;
}
int AXIS2_CALL hello_init(axis2_svc_skeleton_t *svc_skeleton, const axutil_env_t *env)
{
svc_skeleton->func_array = axutil_array_list_create(env, 0);
axutil_array_list_add(svc_skeleton->func_array, env, "helloString");
return AXIS2_SUCCESS;
}
axiom_node_t* AXIS2_CALL hello_invoke(axis2_svc_skeleton_t *svc_skeleton, const axutil_env_t *env, axiom_node_t *node, axis2_msg_ctx_t *msg_ctx)
{
return axis2_hello_greet(env, node);
}
axiom_node_t* AXIS2_CALL hello_on_fault(axis2_svc_skeleton_t *svc_skeli, const axutil_env_t *env, axiom_node_t *node)
{
axiom_node_t *error_node = NULL;
axiom_node_t* text_node = NULL;
axiom_element_t *error_ele = NULL;
error_ele = axiom_element_create(env, node, "EchoServiceError", NULL, &error_node);
axiom_element_set_text(error_ele, env, "Echo service failed ", text_node);
return error_node;
}
int AXIS2_CALL hello_free(axis2_svc_skeleton_t *svc_skeleton, const axutil_env_t *env)
{
if (svc_skeleton->func_array)
{
axutil_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;
}
AXIS2_EXPORT int axis2_get_instance(axis2_svc_skeleton_t **inst, const axutil_env_t *env)
{
*inst = axis2_hello_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)
{
axis2_status_t status = AXIS2_FAILURE;
if (inst)
{
status = AXIS2_SVC_SKELETON_FREE(inst, env);
}
return status;
}
使用Axis/C实现服务是需要遵循的步骤包括:
操作(operation)实现:
axis2_hello_greet函数实现了greet操作的业务逻辑,hello_invoke函数直接调用该函数。该函数以axiom_node的形式接收有效载荷(payload),处理它以理解请求逻辑,以axiom_node的形式准备响应并将其返回。
函数代码:
axiom_node_t * axis2_hello_greet(const axutil_env_t *env, axiom_node_t *node)
{
axiom_node_t *client_greeting_node = NULL;
axiom_node_t *return_node = NULL;
AXIS2_ENV_CHECK(env, NULL);
if (node)
{
client_greeting_node = axiom_node_get_first_child(node, env);
if (client_greeting_node &&
axiom_node_get_node_type(client_greeting_node, env) == AXIOM_TEXT)
{
axiom_text_t *greeting = (axiom_text_t *)axiom_node_get_data_element(client_greeting_node, env);
if (greeting && axiom_text_get_value(greeting , env))
{
const axis2_char_t *greeting_str = axiom_text_get_value(greeting, env);
printf("Client greeted saying \"%s\" \n", greeting_str);
return_node = build_greeting_response(env, "Hello Client!");
}
}
}
else
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SVC_SKEL_INVALID_XML_FORMAT_IN_REQUEST, AXIS2_FAILURE);
printf("ERROR: invalid XML in request\n");
return_node = build_greeting_response(env, "Client! Who are you?");
}
return return_node;
}
注:有效载荷(payload):In computing and telecommunications, the payload is the part of transmitted data that is the actual intended message. The payload excludes any headers or metadata sent solely to facilitate payload delivery.
个人理解有效载荷即包裹在传输数据对象中实际有意义的信息。
框架Create方法:axis2_hello_create创建并返回一个axis2_svc_skeleton实例。该函数最重要的部分是函数指针赋值。他们用于将接口操作映射为对应的实现函数。这部分工作通过将服务框架的ops成员(hello_svc_skeleton_ops_var)分配给ops结构变量的地址(axis2_svc_skeleton::ops)来完成。
函数代码:
static const axis2_svc_skeleton_ops_t hello_svc_skeleton_ops_var =
{
hello_init,
hello_invoke,
hello_on_fault,
hello_free
};
axis2_svc_skeleton_t * axis2_hello_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 = &hello_svc_skeleton_ops_var;
svc_skeleton->func_array = NULL;
return svc_skeleton;
}
调用操作实现:
axiom_node_t* AXIS2_CALL hello_invoke(axis2_svc_skeleton_t *svc_skeleton, const axutil_env_t *env, axiom_node_t *node, axis2_msg_ctx_t *msg_ctx)
{
return axis2_hello_greet(env, node);
}
Axis2/C调用的invoke函数参数包括一个服务框架指针,一个环境指针,一个包含请求有效载荷的axiom_node的实例和一个包含上下文信息的axis2_msg_ctx的实例。可以从上下文信息中提取与传入消息相关的必要信息。
Axis2/C期望invoke函数返回一个表示响应有效载荷的axiom_node指针。
服务描述(services.xml)
services.xml文件包含服务器启动时由Axis2/C发布引擎读取的服务详细信息。services.xml示例如下:
hello
Quick start guide hello service sample.
上述配置指定服务名称为hello。
一个service元素中可包含一个或多个operation元素。示例中仅有一个名为greet的操作。
编译服务:
Linux:
gcc -shared -olibhello.so -I$AXIS2C_HOME/include/axis2-1.6.0/ -L$AXIS2C_HOME/lib -laxutil -laxis2_axiom -laxis2_parser -laxis2_engine -lpthread -laxis2_http_sender -laxis2_http_receiver hello_svc.c
MS Windows:
cl.exe /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "AXIS2_DECLARE_EXPORT" /D "AXIS2_SVR_MULTI_THREADED" /w /nologo /I %AXIS2C_HOME%\include /c hello_svc.c
链接:
link.exe /nologo /LIBPATH:%AXIS2C_HOME%\lib axutil.lib axiom.lib axis2_parser.lib axis2_engine.lib /DLL /OUT:hello.dll *.obj
发布服务:
PATH
静态WSDL文件可以通过在service结尾增加?wsdl访问,例如对与Calculator服务,可通过浏览器访问http://localhost:9090/axis2/services/Calculator?wsdl。