1 #include "osrf_message.h"
4 int parse_json_result = 1;
5 int parse_json_params = 1;
7 /* utility function for debugging a DOM doc */
8 static void recurse_doc( xmlNodePtr node ) {
9 if( node == NULL ) return;
10 debug_handler("Recurse: %s => %s", node->name, node->content );
11 xmlNodePtr t = node->children;
20 osrf_message* osrf_message_init( enum M_TYPE type, int thread_trace, int protocol ) {
22 osrf_message* msg = (osrf_message*) safe_malloc(sizeof(osrf_message));
24 msg->thread_trace = thread_trace;
25 msg->protocol = protocol;
27 msg->is_exception = 0;
28 msg->parse_json_result = parse_json_result;
29 msg->parse_json_params = parse_json_params;
30 msg->parray = init_string_array(16); /* start out with a slot for 16 params. can grow */
37 void osrf_message_set_json_parse_result( int ibool ) {
38 parse_json_result = ibool;
41 void osrf_message_set_json_parse_params( int ibool ) {
42 parse_json_params = ibool;
45 void osrf_message_set_request_info(
46 osrf_message* msg, char* method_name, json* json_params ) {
48 if( msg == NULL || method_name == NULL )
49 fatal_handler( "Bad params to osrf_message_set_request_params()" );
51 if(msg->parse_json_params) {
52 if( json_params != NULL ) {
53 msg->params = json_tokener_parse(json_object_to_json_string(json_params));
54 msg->_params = json_parse_string(json_object_to_json_string(json_params));
56 msg->params = json_tokener_parse("[]");
57 msg->_params = json_parse_string("[]");
61 msg->method_name = strdup( method_name );
65 /* only works of parse_json_params is false */
66 void osrf_message_add_param( osrf_message* msg, char* param_string ) {
67 if(msg == NULL || param_string == NULL)
69 if(!msg->parse_json_params)
70 string_array_add(msg->parray, param_string);
74 void osrf_message_set_status_info(
75 osrf_message* msg, char* status_name, char* status_text, int status_code ) {
78 fatal_handler( "Bad params to osrf_message_set_status_info()" );
80 if( status_name != NULL )
81 msg->status_name = strdup( status_name );
83 if( status_text != NULL )
84 msg->status_text = strdup( status_text );
86 msg->status_code = status_code;
90 void osrf_message_set_result_content( osrf_message* msg, char* json_string ) {
91 if( msg == NULL || json_string == NULL)
92 warning_handler( "Bad params to osrf_message_set_result_content()" );
94 msg->result_string = strdup(json_string);
96 /* ----------------------------------------------------- */
97 object* o = json_parse_string(json_string);
98 char* string = o->to_json(o);
99 debug_handler("---------------------------------------------------");
100 debug_handler("Parsed JSON string \n%s\n", string);
102 debug_handler("Class is %s\n", o->classname);
103 debug_handler("---------------------------------------------------");
106 /* ----------------------------------------------------- */
108 debug_handler( "Message Parse JSON is set to: %d", msg->parse_json_result );
110 if(msg->parse_json_result) {
111 msg->result_content = json_tokener_parse(msg->result_string);
112 msg->_result_content = json_parse_string(msg->result_string);
114 char* j = object_to_json(msg->_result_content);
115 debug_handler("PARSE json result content %s", j);
122 void osrf_message_free( osrf_message* msg ) {
126 if( msg->status_name != NULL )
127 free(msg->status_name);
129 if( msg->status_text != NULL )
130 free(msg->status_text);
132 if( msg->result_content != NULL )
133 json_object_put( msg->result_content );
135 if( msg->_result_content != NULL )
136 free_object( msg->_result_content );
138 if( msg->result_string != NULL )
139 free( msg->result_string);
141 if( msg->method_name != NULL )
142 free(msg->method_name);
144 if( msg->params != NULL )
145 json_object_put( msg->params );
147 if( msg->_params != NULL )
148 free_object(msg->_params);
151 string_array_destroy(msg->parray);
158 /* here's where things get interesting */
159 char* osrf_message_to_xml( osrf_message* msg ) {
168 xmlKeepBlanksDefault(0);
170 xmlNodePtr message_node;
171 xmlNodePtr type_node;
172 xmlNodePtr thread_trace_node;
173 xmlNodePtr protocol_node;
174 xmlNodePtr status_node;
175 xmlNodePtr status_text_node;
176 xmlNodePtr status_code_node;
177 xmlNodePtr method_node = NULL;
178 xmlNodePtr method_name_node;
179 xmlNodePtr params_node = NULL;
180 xmlNodePtr result_node;
181 xmlNodePtr content_node;
184 xmlDocPtr doc = xmlReadDoc(
185 BAD_CAST "<oils:root xmlns:oils='http://open-ils.org/xml/namespaces/oils_v1'>"
186 "<oils:domainObject name='oilsMessage'/></oils:root>",
187 NULL, NULL, XML_PARSE_NSCLEAN );
189 message_node = xmlDocGetRootElement(doc)->children; /* since it's the only child */
190 type_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
191 thread_trace_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
192 protocol_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
196 sprintf(tt,"%d",msg->thread_trace);
197 xmlSetProp( thread_trace_node, BAD_CAST "name", BAD_CAST "threadTrace" );
198 xmlSetProp( thread_trace_node, BAD_CAST "value", BAD_CAST tt );
202 sprintf(prot,"%d",msg->protocol);
203 xmlSetProp( protocol_node, BAD_CAST "name", BAD_CAST "protocol" );
204 xmlSetProp( protocol_node, BAD_CAST "value", BAD_CAST prot );
206 switch(msg->m_type) {
209 xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
210 xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "CONNECT" );
214 xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
215 xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "DISCONNECT" );
220 xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
221 xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "STATUS" );
222 status_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
223 xmlSetProp( status_node, BAD_CAST "name", BAD_CAST msg->status_name );
225 status_text_node = xmlNewChild( status_node, NULL, BAD_CAST "domainObjectAttr", NULL );
226 xmlSetProp( status_text_node, BAD_CAST "name", BAD_CAST "status" );
227 xmlSetProp( status_text_node, BAD_CAST "value", BAD_CAST msg->status_text);
229 status_code_node = xmlNewChild( status_node, NULL, BAD_CAST "domainObjectAttr", NULL );
230 xmlSetProp( status_code_node, BAD_CAST "name", BAD_CAST "statusCode" );
234 sprintf(sc,"%d",msg->status_code);
235 xmlSetProp( status_code_node, BAD_CAST "value", BAD_CAST sc);
241 xmlSetProp( type_node, BAD_CAST "name", "type" );
242 xmlSetProp( type_node, BAD_CAST "value", "REQUEST" );
243 method_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
244 xmlSetProp( method_node, BAD_CAST "name", BAD_CAST "oilsMethod" );
246 if( msg->method_name != NULL ) {
248 method_name_node = xmlNewChild( method_node, NULL, BAD_CAST "domainObjectAttr", NULL );
249 xmlSetProp( method_name_node, BAD_CAST "name", BAD_CAST "method" );
250 xmlSetProp( method_name_node, BAD_CAST "value", BAD_CAST msg->method_name );
252 if( msg->parse_json_params ) {
253 if( msg->params != NULL ) {
255 //char* jj = json_object_to_json_string( msg->params );
256 char* jj = msg->_params->to_json(msg->_params);
257 params_node = xmlNewChild( method_node, NULL, BAD_CAST "params", NULL );
258 xmlNodePtr tt = xmlNewDocTextLen( doc, BAD_CAST jj, strlen(jj) );
259 xmlAddChild(params_node, tt);
263 if( msg->parray != NULL ) {
265 /* construct the json array for the params */
266 growing_buffer* buf = buffer_init(128);
267 buffer_add( buf, "[");
269 for( k=0; k!= msg->parray->size; k++) {
270 buffer_add( buf, string_array_get_string(msg->parray, k) );
271 if(string_array_get_string(msg->parray, k+1))
272 buffer_add( buf, "," );
275 buffer_add( buf, "]");
277 char* tmp = safe_malloc( (buf->n_used + 1) * sizeof(char));
278 memcpy(tmp, buf->buf, buf->n_used);
280 params_node = xmlNewChild( method_node, NULL,
281 BAD_CAST "params", NULL );
283 xmlNodePtr tt = xmlNewDocTextLen( doc, BAD_CAST tmp, strlen(tmp) );
284 xmlAddChild(params_node, tt);
295 xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
296 xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "RESULT" );
297 result_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
298 xmlSetProp( result_node, BAD_CAST "name", BAD_CAST "oilsResult" );
300 status_text_node = xmlNewChild( result_node, NULL, BAD_CAST "domainObjectAttr", NULL );
301 xmlSetProp( status_text_node, BAD_CAST "name", BAD_CAST "status" );
302 xmlSetProp( status_text_node, BAD_CAST "value", BAD_CAST msg->status_text);
304 status_code_node = xmlNewChild( result_node, NULL, BAD_CAST "domainObjectAttr", NULL );
305 xmlSetProp( status_code_node, BAD_CAST "name", BAD_CAST "statusCode" );
309 sprintf(stc,"%d",msg->status_code);
310 xmlSetProp( status_code_node, BAD_CAST "value", BAD_CAST stc);
312 content_node = xmlNewChild( result_node, NULL,
313 BAD_CAST "domainObject", BAD_CAST msg->result_string );
314 xmlSetProp( content_node, BAD_CAST "name", BAD_CAST "oilsScalar" );
319 warning_handler( "Recieved bogus message type" );
324 // -----------------------------------------------------
325 // Dump the XML doc to a string and remove the
327 // -----------------------------------------------------
329 /* passing in a '1' means we want to retain the formatting */
331 //xmlDocDumpFormatMemory( doc, &xmlbuf, &bufsize, 0 );
332 //xmlDocDumpMemoryEnc( doc, &xmlbuf, &bufsize, "UTF-8" );
333 xmlDocDumpMemoryEnc( doc, &xmlbuf, &bufsize, "UTF-8" );
335 encoded_msg = strdup( (char*) xmlbuf );
338 if( encoded_msg == NULL )
339 fatal_handler("message_to_xml(): Out of Memory");
346 /*** remove the XML declaration */
347 int len = strlen(encoded_msg);
349 memset( tmp, 0, len );
353 /* when we reach the first >, take everything after it */
354 for( i = 0; i!= len; i++ ) {
355 if( encoded_msg[i] == 62) { /* ascii > */
357 /* found_at holds the starting index of the rest of the doc*/
364 /* move the shortened doc into the tmp buffer */
365 strncpy( tmp, encoded_msg + found_at, len - found_at );
366 /* move the tmp buffer back into the allocated space */
367 memset( encoded_msg, 0, len );
368 strcpy( encoded_msg, tmp );
378 int osrf_message_from_xml( char* xml, osrf_message* msgs[] ) {
382 xmlKeepBlanksDefault(0);
384 xmlNodePtr message_node;
385 xmlDocPtr doc = xmlReadDoc(
386 BAD_CAST xml, NULL, NULL, XML_PARSE_NSCLEAN );
388 xmlNodePtr root =xmlDocGetRootElement(doc);
390 warning_handler( "Attempt to build message from incomplete xml %s", xml );
395 message_node = root->children; /* since it's the only child */
398 warning_handler( "Attempt to build message from incomplete xml %s", xml );
402 while( message_node != NULL ) {
404 xmlNodePtr cur_node = message_node->children;
405 osrf_message* new_msg = safe_malloc(sizeof(osrf_message));
406 new_msg->parse_json_result = parse_json_result;
411 xmlChar* name = NULL;
412 xmlChar* value = NULL;
414 /* we're a domainObjectAttr */
415 if( !strcmp((char*)cur_node->name,"domainObjectAttr" )) {
416 name = xmlGetProp( cur_node, BAD_CAST "name");
420 value = xmlGetProp( cur_node, BAD_CAST "value" );
423 if( (!strcmp((char*)name, "type")) ) { /* what type are we? */
425 if(!strcmp((char*)value, "CONNECT"))
426 new_msg->m_type = CONNECT;
428 if(!strcmp((char*)value, "DISCONNECT"))
429 new_msg->m_type = DISCONNECT;
431 if(!strcmp((char*)value, "STATUS"))
432 new_msg->m_type = STATUS;
434 if(!strcmp((char*)value, "REQUEST"))
435 new_msg->m_type = REQUEST;
437 if(!strcmp((char*)value, "RESULT"))
438 new_msg->m_type = RESULT;
440 } else if((!strcmp((char*)name, "threadTrace"))) {
441 new_msg->thread_trace = atoi( (char*) value );
443 } else if((!strcmp((char*)name, "protocol"))) {
444 new_msg->protocol = atoi( (char*) value );
453 /* we're a domainObject */
454 if( !strcmp((char*)cur_node->name,"domainObject" )) {
456 name = xmlGetProp( cur_node, BAD_CAST "name");
460 if( !strcmp(name,"oilsMethod") ) {
462 xmlNodePtr meth_node = cur_node->children;
464 while( meth_node != NULL ) {
466 if( !strcmp((char*)meth_node->name,"domainObjectAttr" )) {
467 char* meth_name = xmlGetProp( meth_node, BAD_CAST "value" );
469 new_msg->method_name = strdup(meth_name);
474 if( !strcmp((char*)meth_node->name,"params" ) && meth_node->children->content ) {
475 //new_msg->params = json_object_new_string( meth_node->children->content );
476 if( new_msg->parse_json_params) {
477 new_msg->params = json_tokener_parse(meth_node->children->content);
478 new_msg->_params = json_parse_string(meth_node->children->content);
480 /* XXX this will have to parse the JSON to
481 grab the strings for full support! This should only be
482 necessary for server support of
483 non-json-param-parsing, though. Ugh. */
484 new_msg->params = json_tokener_parse(meth_node->children->content);
485 new_msg->_params = json_parse_string(meth_node->children->content);
489 meth_node = meth_node->next;
493 if( !strcmp(name,"oilsResult") || new_msg->m_type == STATUS ) {
495 xmlNodePtr result_nodes = cur_node->children;
497 while( result_nodes ) {
499 if(!strcmp(result_nodes->name,"domainObjectAttr")) {
501 xmlChar* result_attr_name = xmlGetProp( result_nodes, BAD_CAST "name");
502 if(result_attr_name) {
503 xmlChar* result_attr_value = xmlGetProp( result_nodes, BAD_CAST "value" );
505 if( result_attr_value ) {
506 if((!strcmp((char*)result_attr_name, "status")))
507 new_msg->status_text = strdup((char*) result_attr_value );
509 else if((!strcmp((char*)result_attr_name, "statusCode")))
510 new_msg->status_code = atoi((char*) result_attr_value );
511 xmlFree(result_attr_value);
514 xmlFree(result_attr_name);
520 if(!strcmp(result_nodes->name,"domainObject")) {
521 xmlChar* r_name = xmlGetProp( result_nodes, BAD_CAST "name" );
523 if( !strcmp((char*)r_name,"oilsScalar") && result_nodes->children->content ) {
524 osrf_message_set_result_content( new_msg, result_nodes->children->content);
529 result_nodes = result_nodes->next;
533 if( new_msg->m_type == STATUS )
534 new_msg->status_name = strdup(name);
540 /* we're a params node */
541 if( !strcmp((char*)cur_node->name,"params" )) {
545 cur_node = cur_node->next;
548 msgs[msg_index] = new_msg;
550 message_node = message_node->next;
552 } // while message_node != null
554 xmlCleanupCharEncodingHandlers();