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 */
32 msg->_result_content = NULL;
38 void osrf_message_set_json_parse_result( int ibool ) {
39 // parse_json_result = ibool;
42 void osrf_message_set_json_parse_params( int ibool ) {
43 // parse_json_params = ibool;
46 void osrf_message_set_method( osrf_message* msg, char* method_name ) {
47 if( msg == NULL || method_name == NULL ) return;
48 msg->method_name = strdup( method_name );
52 /* uses the object passed in directly, do not FREE! */
53 void osrf_message_add_object_param( osrf_message* msg, object* o ) {
55 if(msg->parse_json_params) {
57 msg->_params = json_parse_string("[]");
58 msg->_params->push(msg->_params, json_parse_string(o->to_json(o)));
62 void osrf_message_set_params( osrf_message* msg, object* o ) {
63 if(!msg || !o) return;
65 char* j = object_to_json(o);
66 debug_handler("Setting params to\n%s", j);
69 if(msg->parse_json_params) {
71 warning_handler("passing non-array to osrf_message_set_params()");
74 if(msg->_params) free_object(msg->_params);
75 char* j = o->to_json(o);
76 msg->_params = json_parse_string(j);
82 /* only works if parse_json_params is false */
83 void osrf_message_add_param( osrf_message* msg, char* param_string ) {
84 if(msg == NULL || param_string == NULL) return;
85 if(!msg->_params) msg->_params = new_object(NULL);
86 msg->_params->push(msg->_params, json_parse_string(param_string));
89 if(!msg->parse_json_params)
90 string_array_add(msg->parray, param_string);
95 void osrf_message_set_status_info(
96 osrf_message* msg, char* status_name, char* status_text, int status_code ) {
99 fatal_handler( "Bad params to osrf_message_set_status_info()" );
101 if( status_name != NULL )
102 msg->status_name = strdup( status_name );
104 if( status_text != NULL )
105 msg->status_text = strdup( status_text );
107 msg->status_code = status_code;
111 void osrf_message_set_result_content( osrf_message* msg, char* json_string ) {
112 if( msg == NULL || json_string == NULL)
113 warning_handler( "Bad params to osrf_message_set_result_content()" );
115 msg->result_string = strdup(json_string);
116 debug_handler( "Message Parse JSON result is set to: %d", msg->parse_json_result );
118 if(msg->parse_json_result)
119 msg->_result_content = json_parse_string(msg->result_string);
124 void osrf_message_free( osrf_message* msg ) {
128 if( msg->status_name != NULL )
129 free(msg->status_name);
131 if( msg->status_text != NULL )
132 free(msg->status_text);
134 if( msg->_result_content != NULL )
135 free_object( msg->_result_content );
137 if( msg->result_string != NULL )
138 free( msg->result_string);
140 if( msg->method_name != NULL )
141 free(msg->method_name);
143 if( msg->_params != NULL )
144 free_object(msg->_params);
146 string_array_destroy(msg->parray);
151 char* osrf_message_serialize(osrf_message* msg) {
152 if( msg == NULL ) return NULL;
153 object* json = new_object(NULL);
154 json->set_class(json, "osrfMessage");
156 char sc[64]; memset(sc,0,64);
162 sprintf(tt,"%d",msg->thread_trace);
163 json->add_key(json, "threadTrace", new_object(tt));
165 switch(msg->m_type) {
168 json->add_key(json, "type", new_object("CONNECT"));
172 json->add_key(json, "type", new_object("DISCONNECT"));
176 json->add_key(json, "type", new_object("STATUS"));
177 payload = new_object(NULL);
178 payload->set_class(payload, msg->status_name);
179 payload->add_key(payload, "status", new_object(msg->status_text));
180 sprintf(sc,"%d",msg->status_code);
181 payload->add_key(payload, "statusCode", new_object(sc));
182 json->add_key(json, "payload", payload);
186 json->add_key(json, "type", new_object("REQUEST"));
187 payload = new_object(NULL);
188 payload->set_class(payload, "osrfMethod");
189 payload->add_key(payload, "method", new_object(msg->method_name));
190 str = object_to_json(msg->_params);
191 payload->add_key(payload, "params", json_parse_string(str));
193 json->add_key(json, "payload", payload);
198 json->add_key(json, "type", new_object("RESULT"));
199 payload = new_object(NULL);
200 payload->set_class(payload,"osrfResult");
201 payload->add_key(payload, "status", new_object(msg->status_text));
202 sprintf(sc,"%d",msg->status_code);
203 payload->add_key(payload, "statusCode", new_object(sc));
204 str = object_to_json(msg->_result_content);
205 payload->add_key(payload, "content", json_parse_string(str));
207 json->add_key(json, "payload", payload);
211 object* wrapper = new_object(NULL);
212 wrapper->push(wrapper, json);
213 char* j = wrapper->to_json(wrapper);
214 free_object(wrapper);
219 int osrf_message_deserialize(char* string, osrf_message* msgs[], int count) {
220 if(!string || !msgs || count <= 0) return 0;
222 object* json = json_parse_string(string);
223 if(json == NULL) return 0;
227 for( x = 0; x < json->size && x < count; x++ ) {
229 object* message = json->get_index(json, x);
231 if(message && !message->is_null &&
232 message->classname && !strcmp(message->classname, "osrfMessage")) {
234 osrf_message* new_msg = safe_malloc(sizeof(osrf_message));
236 object* tmp = message->get_key(message, "type");
238 if(tmp && tmp->string_data) {
239 char* t = tmp->string_data;
241 if(!strcmp(t, "CONNECT")) new_msg->m_type = CONNECT;
242 if(!strcmp(t, "DISCONNECT")) new_msg->m_type = DISCONNECT;
243 if(!strcmp(t, "STATUS")) new_msg->m_type = STATUS;
244 if(!strcmp(t, "REQUEST")) new_msg->m_type = REQUEST;
245 if(!strcmp(t, "RESULT")) new_msg->m_type = RESULT;
248 tmp = message->get_key(message, "threadTrace");
251 new_msg->thread_trace = tmp->num_value;
253 new_msg->thread_trace = atoi(tmp->string_data);
257 tmp = message->get_key(message, "protocol");
260 new_msg->protocol = tmp->num_value;
262 new_msg->protocol = atoi(tmp->string_data);
265 tmp = message->get_key(message, "payload");
268 new_msg->status_name = strdup(tmp->classname);
270 object* tmp0 = tmp->get_key(tmp,"method");
271 if(tmp0 && tmp0->string_data)
272 new_msg->method_name = strdup(tmp0->string_data);
274 tmp0 = tmp->get_key(tmp,"params");
276 char* s = tmp0->to_json(tmp0);
277 new_msg->_params = json_parse_string(s);
281 tmp0 = tmp->get_key(tmp,"status");
282 if(tmp0 && tmp0->string_data)
283 new_msg->status_text = strdup(tmp0->string_data);
285 tmp0 = tmp->get_key(tmp,"statusCode");
287 if(tmp0->is_string && tmp0->string_data)
288 new_msg->status_code = atoi(tmp0->string_data);
290 new_msg->status_code = tmp0->num_value;
293 tmp0 = tmp->get_key(tmp,"content");
295 char* s = tmp0->to_json(tmp0);
296 new_msg->_result_content = json_parse_string(s);
301 msgs[numparsed++] = new_msg;
308 /* here's where things get interesting */
309 char* osrf_message_to_xml( osrf_message* msg ) {
311 if( msg == NULL ) return NULL;
313 xmlKeepBlanksDefault(0);
315 xmlNodePtr message_node;
316 xmlNodePtr type_node;
317 xmlNodePtr thread_trace_node;
318 xmlNodePtr protocol_node;
319 xmlNodePtr status_node;
320 xmlNodePtr status_text_node;
321 xmlNodePtr status_code_node;
322 xmlNodePtr method_node = NULL;
323 xmlNodePtr method_name_node;
324 xmlNodePtr params_node = NULL;
325 xmlNodePtr result_node;
326 xmlNodePtr content_node;
329 xmlDocPtr doc = xmlReadDoc(
330 BAD_CAST "<oils:root xmlns:oils='http://open-ils.org/xml/namespaces/oils_v1'>"
331 "<oils:domainObject name='oilsMessage'/></oils:root>",
332 NULL, NULL, XML_PARSE_NSCLEAN );
334 message_node = xmlDocGetRootElement(doc)->children; /* since it's the only child */
335 type_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
336 thread_trace_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
337 protocol_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
341 sprintf(tt,"%d",msg->thread_trace);
342 xmlSetProp( thread_trace_node, BAD_CAST "name", BAD_CAST "threadTrace" );
343 xmlSetProp( thread_trace_node, BAD_CAST "value", BAD_CAST tt );
347 sprintf(prot,"%d",msg->protocol);
348 xmlSetProp( protocol_node, BAD_CAST "name", BAD_CAST "protocol" );
349 xmlSetProp( protocol_node, BAD_CAST "value", BAD_CAST prot );
351 switch(msg->m_type) {
354 xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
355 xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "CONNECT" );
359 xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
360 xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "DISCONNECT" );
365 xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
366 xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "STATUS" );
367 status_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
368 xmlSetProp( status_node, BAD_CAST "name", BAD_CAST msg->status_name );
370 status_text_node = xmlNewChild( status_node, NULL, BAD_CAST "domainObjectAttr", NULL );
371 xmlSetProp( status_text_node, BAD_CAST "name", BAD_CAST "status" );
372 xmlSetProp( status_text_node, BAD_CAST "value", BAD_CAST msg->status_text);
374 status_code_node = xmlNewChild( status_node, NULL, BAD_CAST "domainObjectAttr", NULL );
375 xmlSetProp( status_code_node, BAD_CAST "name", BAD_CAST "statusCode" );
379 sprintf(sc,"%d",msg->status_code);
380 xmlSetProp( status_code_node, BAD_CAST "value", BAD_CAST sc);
386 xmlSetProp( type_node, BAD_CAST "name", "type" );
387 xmlSetProp( type_node, BAD_CAST "value", "REQUEST" );
388 method_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
389 xmlSetProp( method_node, BAD_CAST "name", BAD_CAST "oilsMethod" );
391 if( msg->method_name != NULL ) {
393 method_name_node = xmlNewChild( method_node, NULL, BAD_CAST "domainObjectAttr", NULL );
394 xmlSetProp( method_name_node, BAD_CAST "name", BAD_CAST "method" );
395 xmlSetProp( method_name_node, BAD_CAST "value", BAD_CAST msg->method_name );
397 if( msg->parse_json_params ) {
398 if( msg->_params != NULL ) {
400 //char* jj = json_object_to_json_string( msg->params );
401 char* jj = msg->_params->to_json(msg->_params);
402 params_node = xmlNewChild( method_node, NULL, BAD_CAST "params", NULL );
403 xmlNodePtr tt = xmlNewDocTextLen( doc, BAD_CAST jj, strlen(jj) );
404 xmlAddChild(params_node, tt);
408 if( msg->parray != NULL ) {
410 /* construct the json array for the params */
411 growing_buffer* buf = buffer_init(128);
412 buffer_add( buf, "[");
414 for( k=0; k!= msg->parray->size; k++) {
415 buffer_add( buf, string_array_get_string(msg->parray, k) );
416 if(string_array_get_string(msg->parray, k+1))
417 buffer_add( buf, "," );
420 buffer_add( buf, "]");
422 char* tmp = safe_malloc( (buf->n_used + 1) * sizeof(char));
423 memcpy(tmp, buf->buf, buf->n_used);
425 params_node = xmlNewChild( method_node, NULL,
426 BAD_CAST "params", NULL );
428 xmlNodePtr tt = xmlNewDocTextLen( doc, BAD_CAST tmp, strlen(tmp) );
429 xmlAddChild(params_node, tt);
440 xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
441 xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "RESULT" );
442 result_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
443 xmlSetProp( result_node, BAD_CAST "name", BAD_CAST "oilsResult" );
445 status_text_node = xmlNewChild( result_node, NULL, BAD_CAST "domainObjectAttr", NULL );
446 xmlSetProp( status_text_node, BAD_CAST "name", BAD_CAST "status" );
447 xmlSetProp( status_text_node, BAD_CAST "value", BAD_CAST msg->status_text);
449 status_code_node = xmlNewChild( result_node, NULL, BAD_CAST "domainObjectAttr", NULL );
450 xmlSetProp( status_code_node, BAD_CAST "name", BAD_CAST "statusCode" );
454 sprintf(stc,"%d",msg->status_code);
455 xmlSetProp( status_code_node, BAD_CAST "value", BAD_CAST stc);
457 content_node = xmlNewChild( result_node, NULL,
458 BAD_CAST "domainObject", BAD_CAST msg->result_string );
459 xmlSetProp( content_node, BAD_CAST "name", BAD_CAST "oilsScalar" );
464 warning_handler( "Recieved bogus message type" );
469 // -----------------------------------------------------
470 // Dump the XML doc to a string and remove the
472 // -----------------------------------------------------
474 /* passing in a '1' means we want to retain the formatting */
476 //xmlDocDumpFormatMemory( doc, &xmlbuf, &bufsize, 0 );
477 //xmlDocDumpMemoryEnc( doc, &xmlbuf, &bufsize, "UTF-8" );
482 xmlDocDumpMemoryEnc( doc, &xmlbuf, &bufsize, "UTF-8" );
484 encoded_msg = strdup( (char*) xmlbuf );
487 if( encoded_msg == NULL )
488 fatal_handler("message_to_xml(): Out of Memory");
497 xmlBufferPtr xmlbuf = xmlBufferCreate();
498 xmlNodeDump( xmlbuf, doc, xmlDocGetRootElement(doc), 0, 0);
500 char* xml = strdup( (char*) (xmlBufferContent(xmlbuf)));
501 xmlBufferFree(xmlbuf);
503 int l = strlen(xml)-1;
504 if( xml[l] == 10 || xml[l] == 13 )
513 int len = strlen(encoded_msg);
515 memset( tmp, 0, len );
519 for( i = 0; i!= len; i++ ) {
520 if( encoded_msg[i] == 62) {
528 strncpy( tmp, encoded_msg + found_at, len - found_at );
529 memset( encoded_msg, 0, len );
530 strcpy( encoded_msg, tmp );
541 int osrf_message_from_xml( char* xml, osrf_message* msgs[] ) {
545 xmlKeepBlanksDefault(0);
547 xmlNodePtr message_node;
548 xmlDocPtr doc = xmlReadDoc(
549 BAD_CAST xml, NULL, NULL, XML_PARSE_NSCLEAN );
551 xmlNodePtr root =xmlDocGetRootElement(doc);
553 warning_handler( "Attempt to build message from incomplete xml %s", xml );
558 message_node = root->children; /* since it's the only child */
561 warning_handler( "Attempt to build message from incomplete xml %s", xml );
565 while( message_node != NULL ) {
567 xmlNodePtr cur_node = message_node->children;
568 osrf_message* new_msg = safe_malloc(sizeof(osrf_message));
569 new_msg->parse_json_result = parse_json_result;
574 xmlChar* name = NULL;
575 xmlChar* value = NULL;
577 /* we're a domainObjectAttr */
578 if( !strcmp((char*)cur_node->name,"domainObjectAttr" )) {
579 name = xmlGetProp( cur_node, BAD_CAST "name");
583 value = xmlGetProp( cur_node, BAD_CAST "value" );
586 if( (!strcmp((char*)name, "type")) ) { /* what type are we? */
588 if(!strcmp((char*)value, "CONNECT"))
589 new_msg->m_type = CONNECT;
591 if(!strcmp((char*)value, "DISCONNECT"))
592 new_msg->m_type = DISCONNECT;
594 if(!strcmp((char*)value, "STATUS"))
595 new_msg->m_type = STATUS;
597 if(!strcmp((char*)value, "REQUEST"))
598 new_msg->m_type = REQUEST;
600 if(!strcmp((char*)value, "RESULT"))
601 new_msg->m_type = RESULT;
603 } else if((!strcmp((char*)name, "threadTrace"))) {
604 new_msg->thread_trace = atoi( (char*) value );
606 } else if((!strcmp((char*)name, "protocol"))) {
607 new_msg->protocol = atoi( (char*) value );
616 /* we're a domainObject */
617 if( !strcmp((char*)cur_node->name,"domainObject" )) {
619 name = xmlGetProp( cur_node, BAD_CAST "name");
623 if( !strcmp(name,"oilsMethod") ) {
625 xmlNodePtr meth_node = cur_node->children;
627 while( meth_node != NULL ) {
629 if( !strcmp((char*)meth_node->name,"domainObjectAttr" )) {
630 char* meth_name = xmlGetProp( meth_node, BAD_CAST "value" );
632 new_msg->method_name = strdup(meth_name);
637 if( !strcmp((char*)meth_node->name,"params" ) && meth_node->children->content ) {
638 //new_msg->params = json_object_new_string( meth_node->children->content );
639 if( new_msg->parse_json_params) {
640 //new_msg->params = json_tokener_parse(meth_node->children->content);
641 new_msg->_params = json_parse_string(meth_node->children->content);
643 /* XXX this will have to parse the JSON to
644 grab the strings for full support! This should only be
645 necessary for server support of
646 non-json-param-parsing, though. Ugh. */
647 //new_msg->params = json_tokener_parse(meth_node->children->content);
648 new_msg->_params = json_parse_string(meth_node->children->content);
652 meth_node = meth_node->next;
656 if( !strcmp(name,"oilsResult") || new_msg->m_type == STATUS ) {
658 xmlNodePtr result_nodes = cur_node->children;
660 while( result_nodes ) {
662 if(!strcmp(result_nodes->name,"domainObjectAttr")) {
664 xmlChar* result_attr_name = xmlGetProp( result_nodes, BAD_CAST "name");
665 if(result_attr_name) {
666 xmlChar* result_attr_value = xmlGetProp( result_nodes, BAD_CAST "value" );
668 if( result_attr_value ) {
669 if((!strcmp((char*)result_attr_name, "status")))
670 new_msg->status_text = strdup((char*) result_attr_value );
672 else if((!strcmp((char*)result_attr_name, "statusCode")))
673 new_msg->status_code = atoi((char*) result_attr_value );
674 xmlFree(result_attr_value);
677 xmlFree(result_attr_name);
683 if(!strcmp(result_nodes->name,"domainObject")) {
684 xmlChar* r_name = xmlGetProp( result_nodes, BAD_CAST "name" );
686 if( !strcmp((char*)r_name,"oilsScalar") && result_nodes->children->content ) {
687 osrf_message_set_result_content( new_msg, result_nodes->children->content);
692 result_nodes = result_nodes->next;
696 if( new_msg->m_type == STATUS )
697 new_msg->status_name = strdup(name);
703 /* we're a params node */
704 if( !strcmp((char*)cur_node->name,"params" )) {
708 cur_node = cur_node->next;
711 msgs[msg_index] = new_msg;
713 message_node = message_node->next;
715 } // while message_node != null
717 xmlCleanupCharEncodingHandlers();