]> git.evergreen-ils.org Git - Evergreen.git/blob - OpenSRF/src/libstack/osrf_message.c
slowly replacing libjson with objson calls..
[Evergreen.git] / OpenSRF / src / libstack / osrf_message.c
1 #include "osrf_message.h"
2
3 /* default to true */
4 int parse_json_result = 1;
5 int parse_json_params = 1;
6
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;
12         while(t) {
13                 recurse_doc(t);
14                 t = t->next;
15         }
16 }
17
18
19
20 osrf_message* osrf_message_init( enum M_TYPE type, int thread_trace, int protocol ) {
21
22         osrf_message* msg                       = (osrf_message*) safe_malloc(sizeof(osrf_message));
23         msg->m_type                                     = type;
24         msg->thread_trace                       = thread_trace;
25         msg->protocol                           = protocol;
26         msg->next                                       = NULL;
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 */
31         msg->params                                     = NULL;
32
33         return msg;
34 }
35
36
37 void osrf_message_set_json_parse_result( int ibool ) {
38         parse_json_result = ibool;
39 }
40
41 void osrf_message_set_json_parse_params( int ibool ) {
42         parse_json_params = ibool;
43 }
44
45 void osrf_message_set_request_info( 
46                 osrf_message* msg, char* method_name, json* json_params ) {
47
48         if( msg == NULL || method_name == NULL )
49                 fatal_handler( "Bad params to osrf_message_set_request_params()" );
50
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));
55                 } else {
56                         msg->params = json_tokener_parse("[]");
57                         msg->_params = json_parse_string("[]");
58                 }
59         }
60
61         msg->method_name = strdup( method_name );
62 }
63
64
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)
68                 return;
69         if(!msg->parse_json_params)
70                 string_array_add(msg->parray, param_string);
71 }
72
73
74 void osrf_message_set_status_info( 
75                 osrf_message* msg, char* status_name, char* status_text, int status_code ) {
76
77         if( msg == NULL )
78                 fatal_handler( "Bad params to osrf_message_set_status_info()" );
79
80         if( status_name != NULL ) 
81                 msg->status_name = strdup( status_name );
82
83         if( status_text != NULL )
84                 msg->status_text = strdup( status_text );
85
86         msg->status_code = status_code;
87 }
88
89
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()" );
93
94         msg->result_string =    strdup(json_string);
95
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);
101         if(o->classname)
102                 debug_handler("Class is %s\n", o->classname);
103         debug_handler("---------------------------------------------------");
104         free_object(o);
105         free(string);
106         /* ----------------------------------------------------- */
107
108         debug_handler( "Message Parse JSON is set to: %d",  msg->parse_json_result );
109
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);
113
114                 char* j = object_to_json(msg->_result_content);
115                 debug_handler("PARSE json result content %s", j);
116                 free(j);
117         } 
118 }
119
120
121
122 void osrf_message_free( osrf_message* msg ) {
123         if( msg == NULL )
124                 return;
125
126         if( msg->status_name != NULL )
127                 free(msg->status_name);
128
129         if( msg->status_text != NULL )
130                 free(msg->status_text);
131
132         if( msg->result_content != NULL )
133                 json_object_put( msg->result_content );
134
135         if( msg->_result_content != NULL )
136                 free_object( msg->_result_content );
137
138         if( msg->result_string != NULL )
139                 free( msg->result_string);
140
141         if( msg->method_name != NULL )
142                 free(msg->method_name);
143
144         if( msg->params != NULL )
145                 json_object_put( msg->params );
146
147         if( msg->_params != NULL )
148                 free_object(msg->_params);
149
150
151         string_array_destroy(msg->parray);
152
153         free(msg);
154 }
155
156
157                 
158 /* here's where things get interesting */
159 char* osrf_message_to_xml( osrf_message* msg ) {
160
161         if( msg == NULL )
162                 return NULL;
163
164         int                     bufsize;
165         xmlChar*                xmlbuf;
166         char*                   encoded_msg;
167
168         xmlKeepBlanksDefault(0);
169
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;
182
183
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 );
188
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 );
193
194         char tt[64];
195         memset(tt,0,64);
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 );
199
200         char prot[64];
201         memset(prot,0,64);
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 );
205
206         switch(msg->m_type) {
207
208                 case CONNECT: 
209                         xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
210                         xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "CONNECT" );
211                         break;
212
213                 case DISCONNECT:
214                         xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
215                         xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "DISCONNECT" );
216                         break;
217
218                 case STATUS:
219
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 );
224
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);
228
229                         status_code_node = xmlNewChild( status_node, NULL, BAD_CAST "domainObjectAttr", NULL );
230                         xmlSetProp( status_code_node, BAD_CAST "name", BAD_CAST "statusCode" );
231
232                         char sc[64];
233                         memset(sc,0,64);
234                         sprintf(sc,"%d",msg->status_code);
235                         xmlSetProp( status_code_node, BAD_CAST "value", BAD_CAST sc);
236                         
237                         break;
238
239                 case REQUEST:
240
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" );
245
246                         if( msg->method_name != NULL ) {
247
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 );
251
252                                 if( msg->parse_json_params ) {
253                                         if( msg->params != NULL ) {
254
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);
260                                         }
261
262                                 } else {
263                                         if( msg->parray != NULL ) {
264
265                                                 /* construct the json array for the params */
266                                                 growing_buffer* buf = buffer_init(128);
267                                                 buffer_add( buf, "[");
268                                                 int k;
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, "," );
273                                                 }
274
275                                                 buffer_add( buf, "]");
276
277                                                 char* tmp = safe_malloc( (buf->n_used + 1) * sizeof(char));
278                                                 memcpy(tmp, buf->buf, buf->n_used);
279
280                                                 params_node = xmlNewChild( method_node, NULL, 
281                                                         BAD_CAST "params", NULL );
282                                                 
283                                                 xmlNodePtr tt = xmlNewDocTextLen( doc, BAD_CAST tmp, strlen(tmp) );
284                                                 xmlAddChild(params_node, tt);
285
286                                                 buffer_free(buf);
287                                         }
288                                 }
289                         }
290
291                         break;
292
293                 case RESULT:
294
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" );
299
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);
303
304                         status_code_node = xmlNewChild( result_node, NULL, BAD_CAST "domainObjectAttr", NULL );
305                         xmlSetProp( status_code_node, BAD_CAST "name", BAD_CAST "statusCode" );
306
307                         char stc[64];
308                         memset(stc,0,64);
309                         sprintf(stc,"%d",msg->status_code);
310                         xmlSetProp( status_code_node, BAD_CAST "value", BAD_CAST stc);
311
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" );
315
316                         break;
317
318                 default:
319                         warning_handler( "Recieved bogus message type" );
320                         return NULL;
321         }
322
323
324         // -----------------------------------------------------
325         // Dump the XML doc to a string and remove the 
326         // xml declaration
327         // -----------------------------------------------------
328
329         /* passing in a '1' means we want to retain the formatting */
330
331         //xmlDocDumpFormatMemory( doc, &xmlbuf, &bufsize, 0 );
332         //xmlDocDumpMemoryEnc( doc, &xmlbuf, &bufsize, "UTF-8" );
333         xmlDocDumpMemoryEnc( doc, &xmlbuf, &bufsize, "UTF-8" );
334
335         encoded_msg = strdup( (char*) xmlbuf );
336
337
338         if( encoded_msg == NULL ) 
339                 fatal_handler("message_to_xml(): Out of Memory");
340
341         xmlFree(xmlbuf);
342         xmlFreeDoc( doc );
343         xmlCleanupParser();
344
345
346         /*** remove the XML declaration */
347         int len = strlen(encoded_msg);
348         char tmp[len];
349         memset( tmp, 0, len );
350         int i;
351         int found_at = 0;
352
353         /* when we reach the first >, take everything after it */
354         for( i = 0; i!= len; i++ ) {
355                 if( encoded_msg[i] == 62) { /* ascii > */
356
357                         /* found_at holds the starting index of the rest of the doc*/
358                         found_at = i + 1; 
359                         break;
360                 }
361         }
362
363         if( found_at ) {
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 );
369         }
370
371         return encoded_msg;
372
373 }
374
375
376
377
378 int osrf_message_from_xml( char* xml, osrf_message* msgs[] ) {
379
380         if(!xml) return 0;
381
382         xmlKeepBlanksDefault(0);
383
384         xmlNodePtr      message_node;
385         xmlDocPtr       doc = xmlReadDoc( 
386                         BAD_CAST xml, NULL, NULL, XML_PARSE_NSCLEAN );
387
388         xmlNodePtr root =xmlDocGetRootElement(doc);
389         if(!root) {
390                 warning_handler( "Attempt to build message from incomplete xml %s", xml );
391                 return 0;
392         }
393
394         int msg_index = 0;
395         message_node = root->children; /* since it's the only child */
396
397         if(!message_node) {
398                 warning_handler( "Attempt to build message from incomplete xml %s", xml );
399                 return 0;
400         }
401
402         while( message_node != NULL ) {
403
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;
407         
408
409                 while( cur_node ) {
410
411                         xmlChar* name = NULL; 
412                         xmlChar* value = NULL;
413                         
414                         /* we're a domainObjectAttr */
415                         if( !strcmp((char*)cur_node->name,"domainObjectAttr" )) {
416                                 name = xmlGetProp( cur_node, BAD_CAST "name");
417         
418                                 if(name) {
419         
420                                         value = xmlGetProp( cur_node, BAD_CAST "value" );
421                                         if(value) {
422         
423                                                 if( (!strcmp((char*)name, "type")) ) { /* what type are we? */
424         
425                                                         if(!strcmp((char*)value, "CONNECT"))
426                                                                 new_msg->m_type = CONNECT;
427         
428                                                         if(!strcmp((char*)value, "DISCONNECT"))
429                                                                 new_msg->m_type = DISCONNECT;
430                 
431                                                         if(!strcmp((char*)value, "STATUS"))
432                                                                 new_msg->m_type = STATUS;
433                 
434                                                         if(!strcmp((char*)value, "REQUEST"))
435                                                                 new_msg->m_type = REQUEST;
436                                                         
437                                                         if(!strcmp((char*)value, "RESULT"))
438                                                                 new_msg->m_type = RESULT;
439                         
440                                                 } else if((!strcmp((char*)name, "threadTrace"))) {
441                                                         new_msg->thread_trace = atoi( (char*) value );
442                         
443                                                 } else if((!strcmp((char*)name, "protocol"))) {
444                                                         new_msg->protocol = atoi( (char*) value );
445                                                 }
446         
447                                                 xmlFree(value);
448                                         }
449                                         xmlFree(name);
450                                 }
451                         }
452         
453                         /* we're a domainObject */
454                         if( !strcmp((char*)cur_node->name,"domainObject" )) {
455         
456                                 name = xmlGetProp( cur_node, BAD_CAST "name");
457         
458                                 if(name) {
459
460                                         if( !strcmp(name,"oilsMethod") ) {
461         
462                                                 xmlNodePtr meth_node = cur_node->children;
463         
464                                                 while( meth_node != NULL ) {
465         
466                                                         if( !strcmp((char*)meth_node->name,"domainObjectAttr" )) {
467                                                                 char* meth_name = xmlGetProp( meth_node, BAD_CAST "value" );
468                                                                 if(meth_name) {
469                                                                         new_msg->method_name = strdup(meth_name);
470                                                                         xmlFree(meth_name);
471                                                                 }
472                                                         }
473         
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);
479                                                                 } else {
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);
486                                                                 }       
487                                                         }
488
489                                                         meth_node = meth_node->next;
490                                                 }
491                                         } //oilsMethod
492         
493                                         if( !strcmp(name,"oilsResult") || new_msg->m_type == STATUS ) {
494         
495                                                 xmlNodePtr result_nodes = cur_node->children;
496         
497                                                 while( result_nodes ) {
498         
499                                                         if(!strcmp(result_nodes->name,"domainObjectAttr")) {
500         
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" );
504         
505                                                                         if( result_attr_value ) {
506                                                                                 if((!strcmp((char*)result_attr_name, "status"))) 
507                                                                                         new_msg->status_text = strdup((char*) result_attr_value );
508         
509                                                                                 else if((!strcmp((char*)result_attr_name, "statusCode"))) 
510                                                                                         new_msg->status_code = atoi((char*) result_attr_value );
511                                                                                 xmlFree(result_attr_value);
512                                                                         }
513         
514                                                                         xmlFree(result_attr_name);
515                                                                 }
516         
517                                                         }
518                                                 
519         
520                                                         if(!strcmp(result_nodes->name,"domainObject")) {
521                                                                 xmlChar* r_name = xmlGetProp( result_nodes, BAD_CAST "name" );
522                                                                 if(r_name) {
523                                                                         if( !strcmp((char*)r_name,"oilsScalar") && result_nodes->children->content ) {
524                                                                                 osrf_message_set_result_content( new_msg, result_nodes->children->content);
525                                                                         }
526                                                                         xmlFree(r_name);
527                                                                 }
528                                                         }
529                                                         result_nodes = result_nodes->next;
530                                                 }
531                                         }
532                                         
533                                         if( new_msg->m_type == STATUS ) 
534                                                 new_msg->status_name = strdup(name); 
535
536                                         xmlFree(name);
537                                 }
538                         }
539         
540                         /* we're a params node */
541                         if( !strcmp((char*)cur_node->name,"params" )) {
542         
543                         }
544         
545                         cur_node = cur_node->next;
546                 }
547         
548                 msgs[msg_index] = new_msg;
549                 msg_index++;
550                 message_node = message_node->next;
551
552         } // while message_node != null
553
554         xmlCleanupCharEncodingHandlers();
555         xmlFreeDoc( doc );
556         xmlCleanupParser();
557
558         return msg_index;
559
560 }
561
562