]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libstack/osrf_message.c
more tweaking to point to the right header files, etc.
[OpenSRF.git] / 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                 else
55                         msg->params = json_tokener_parse("[]");
56         }
57
58         msg->method_name = strdup( method_name );
59 }
60
61
62 /* only works of parse_json_params is false */
63 void osrf_message_add_param( osrf_message* msg, char* param_string ) {
64         if(msg == NULL || param_string == NULL)
65                 return;
66         if(!msg->parse_json_params)
67                 string_array_add(msg->parray, param_string);
68 }
69
70
71 void osrf_message_set_status_info( 
72                 osrf_message* msg, char* status_name, char* status_text, int status_code ) {
73
74         if( msg == NULL )
75                 fatal_handler( "Bad params to osrf_message_set_status_info()" );
76
77         if( status_name != NULL ) 
78                 msg->status_name = strdup( status_name );
79
80         if( status_text != NULL )
81                 msg->status_text = strdup( status_text );
82
83         msg->status_code = status_code;
84 }
85
86
87 void osrf_message_set_result_content( osrf_message* msg, char* json_string ) {
88         if( msg == NULL || json_string == NULL)
89                 warning_handler( "Bad params to osrf_message_set_result_content()" );
90
91         msg->result_string =    strdup(json_string);
92
93         /* ----------------------------------------------------- */
94         object* o = json_parse_string(json_string);
95         char* string = o->to_json(o);
96         debug_handler("---------------------------------------------------");
97         debug_handler("Parsed JSON string \n%s\n", string);
98         if(o->classname)
99                 debug_handler("Class is %s\n", o->classname);
100         debug_handler("---------------------------------------------------");
101         free_object(o);
102         free(string);
103         /* ----------------------------------------------------- */
104
105         debug_handler( "Message Parse JSON is set to: %d",  msg->parse_json_result );
106
107         if(msg->parse_json_result)
108                 msg->result_content = json_tokener_parse(msg->result_string);
109 }
110
111
112
113 void osrf_message_free( osrf_message* msg ) {
114         if( msg == NULL )
115                 return;
116
117         if( msg->status_name != NULL )
118                 free(msg->status_name);
119
120         if( msg->status_text != NULL )
121                 free(msg->status_text);
122
123         if( msg->result_content != NULL )
124                 json_object_put( msg->result_content );
125
126         if( msg->result_string != NULL )
127                 free( msg->result_string);
128
129         if( msg->method_name != NULL )
130                 free(msg->method_name);
131
132         if( msg->params != NULL )
133                 json_object_put( msg->params );
134
135         string_array_destroy(msg->parray);
136
137         free(msg);
138 }
139
140
141                 
142 /* here's where things get interesting */
143 char* osrf_message_to_xml( osrf_message* msg ) {
144
145         if( msg == NULL )
146                 return NULL;
147
148         int                     bufsize;
149         xmlChar*                xmlbuf;
150         char*                   encoded_msg;
151
152         xmlKeepBlanksDefault(0);
153
154         xmlNodePtr      message_node;
155         xmlNodePtr      type_node;
156         xmlNodePtr      thread_trace_node;
157         xmlNodePtr      protocol_node;
158         xmlNodePtr      status_node;
159         xmlNodePtr      status_text_node;
160         xmlNodePtr      status_code_node;
161         xmlNodePtr      method_node = NULL;
162         xmlNodePtr      method_name_node;
163         xmlNodePtr      params_node = NULL;
164         xmlNodePtr      result_node;
165         xmlNodePtr      content_node;
166
167
168         xmlDocPtr       doc = xmlReadDoc( 
169                         BAD_CAST "<oils:root xmlns:oils='http://open-ils.org/xml/namespaces/oils_v1'>"
170                         "<oils:domainObject name='oilsMessage'/></oils:root>", 
171                         NULL, NULL, XML_PARSE_NSCLEAN );
172
173         message_node = xmlDocGetRootElement(doc)->children; /* since it's the only child */
174         type_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
175         thread_trace_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
176         protocol_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObjectAttr", NULL );
177
178         char tt[64];
179         memset(tt,0,64);
180         sprintf(tt,"%d",msg->thread_trace);
181         xmlSetProp( thread_trace_node, BAD_CAST "name", BAD_CAST "threadTrace" );
182         xmlSetProp( thread_trace_node, BAD_CAST "value", BAD_CAST tt );
183
184         char prot[64];
185         memset(prot,0,64);
186         sprintf(prot,"%d",msg->protocol);
187         xmlSetProp( protocol_node, BAD_CAST "name", BAD_CAST "protocol" );
188         xmlSetProp( protocol_node, BAD_CAST "value", BAD_CAST prot );
189
190         switch(msg->m_type) {
191
192                 case CONNECT: 
193                         xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
194                         xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "CONNECT" );
195                         break;
196
197                 case DISCONNECT:
198                         xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
199                         xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "DISCONNECT" );
200                         break;
201
202                 case STATUS:
203
204                         xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
205                         xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "STATUS" );
206                         status_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
207                         xmlSetProp( status_node, BAD_CAST "name", BAD_CAST msg->status_name );
208
209                         status_text_node = xmlNewChild( status_node, NULL, BAD_CAST "domainObjectAttr", NULL );
210                         xmlSetProp( status_text_node, BAD_CAST "name", BAD_CAST "status" );
211                         xmlSetProp( status_text_node, BAD_CAST "value", BAD_CAST msg->status_text);
212
213                         status_code_node = xmlNewChild( status_node, NULL, BAD_CAST "domainObjectAttr", NULL );
214                         xmlSetProp( status_code_node, BAD_CAST "name", BAD_CAST "statusCode" );
215
216                         char sc[64];
217                         memset(sc,0,64);
218                         sprintf(sc,"%d",msg->status_code);
219                         xmlSetProp( status_code_node, BAD_CAST "value", BAD_CAST sc);
220                         
221                         break;
222
223                 case REQUEST:
224
225                         xmlSetProp( type_node, BAD_CAST "name", "type" );
226                         xmlSetProp( type_node, BAD_CAST "value", "REQUEST" );
227                         method_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
228                         xmlSetProp( method_node, BAD_CAST "name", BAD_CAST "oilsMethod" );
229
230                         if( msg->method_name != NULL ) {
231
232                                 method_name_node = xmlNewChild( method_node, NULL, BAD_CAST "domainObjectAttr", NULL );
233                                 xmlSetProp( method_name_node, BAD_CAST "name", BAD_CAST "method" );
234                                 xmlSetProp( method_name_node, BAD_CAST "value", BAD_CAST msg->method_name );
235
236                                 if( msg->parse_json_params ) {
237                                         if( msg->params != NULL ) {
238
239                                                 char* jj = json_object_to_json_string( msg->params );
240                                                 params_node = xmlNewChild( method_node, NULL, BAD_CAST "params", NULL );
241                                                 xmlNodePtr tt = xmlNewDocTextLen( doc, BAD_CAST jj, strlen(jj) );
242                                                 xmlAddChild(params_node, tt);
243                                         }
244
245                                 } else {
246                                         if( msg->parray != NULL ) {
247
248                                                 /* construct the json array for the params */
249                                                 growing_buffer* buf = buffer_init(128);
250                                                 buffer_add( buf, "[");
251                                                 int k;
252                                                 for( k=0; k!= msg->parray->size; k++) {
253                                                         buffer_add( buf, string_array_get_string(msg->parray, k) );
254                                                         if(string_array_get_string(msg->parray, k+1))
255                                                                 buffer_add( buf, "," );
256                                                 }
257
258                                                 buffer_add( buf, "]");
259
260                                                 char* tmp = safe_malloc( (buf->n_used + 1) * sizeof(char));
261                                                 memcpy(tmp, buf->buf, buf->n_used);
262
263                                                 params_node = xmlNewChild( method_node, NULL, 
264                                                         BAD_CAST "params", NULL );
265                                                 
266                                                 xmlNodePtr tt = xmlNewDocTextLen( doc, BAD_CAST tmp, strlen(tmp) );
267                                                 xmlAddChild(params_node, tt);
268
269                                                 buffer_free(buf);
270                                         }
271                                 }
272                         }
273
274                         break;
275
276                 case RESULT:
277
278                         xmlSetProp( type_node, BAD_CAST "name", BAD_CAST "type" );
279                         xmlSetProp( type_node, BAD_CAST "value", BAD_CAST "RESULT" );
280                         result_node = xmlNewChild( message_node, NULL, BAD_CAST "domainObject", NULL );
281                         xmlSetProp( result_node, BAD_CAST "name", BAD_CAST "oilsResult" );
282
283                         status_text_node = xmlNewChild( result_node, NULL, BAD_CAST "domainObjectAttr", NULL );
284                         xmlSetProp( status_text_node, BAD_CAST "name", BAD_CAST "status" );
285                         xmlSetProp( status_text_node, BAD_CAST "value", BAD_CAST msg->status_text);
286
287                         status_code_node = xmlNewChild( result_node, NULL, BAD_CAST "domainObjectAttr", NULL );
288                         xmlSetProp( status_code_node, BAD_CAST "name", BAD_CAST "statusCode" );
289
290                         char stc[64];
291                         memset(stc,0,64);
292                         sprintf(stc,"%d",msg->status_code);
293                         xmlSetProp( status_code_node, BAD_CAST "value", BAD_CAST stc);
294
295                         content_node = xmlNewChild( result_node, NULL, 
296                                         BAD_CAST "domainObject", BAD_CAST msg->result_string );
297                         xmlSetProp( content_node, BAD_CAST "name", BAD_CAST "oilsScalar" );
298
299                         break;
300
301                 default:
302                         warning_handler( "Recieved bogus message type" );
303                         return NULL;
304         }
305
306
307         // -----------------------------------------------------
308         // Dump the XML doc to a string and remove the 
309         // xml declaration
310         // -----------------------------------------------------
311
312         /* passing in a '1' means we want to retain the formatting */
313
314         //xmlDocDumpFormatMemory( doc, &xmlbuf, &bufsize, 0 );
315         //xmlDocDumpMemoryEnc( doc, &xmlbuf, &bufsize, "UTF-8" );
316         xmlDocDumpMemoryEnc( doc, &xmlbuf, &bufsize, "UTF-8" );
317
318         encoded_msg = strdup( (char*) xmlbuf );
319
320
321         if( encoded_msg == NULL ) 
322                 fatal_handler("message_to_xml(): Out of Memory");
323
324         xmlFree(xmlbuf);
325         xmlFreeDoc( doc );
326         xmlCleanupParser();
327
328
329         /*** remove the XML declaration */
330         int len = strlen(encoded_msg);
331         char tmp[len];
332         memset( tmp, 0, len );
333         int i;
334         int found_at = 0;
335
336         /* when we reach the first >, take everything after it */
337         for( i = 0; i!= len; i++ ) {
338                 if( encoded_msg[i] == 62) { /* ascii > */
339
340                         /* found_at holds the starting index of the rest of the doc*/
341                         found_at = i + 1; 
342                         break;
343                 }
344         }
345
346         if( found_at ) {
347                 /* move the shortened doc into the tmp buffer */
348                 strncpy( tmp, encoded_msg + found_at, len - found_at );
349                 /* move the tmp buffer back into the allocated space */
350                 memset( encoded_msg, 0, len );
351                 strcpy( encoded_msg, tmp );
352         }
353
354         return encoded_msg;
355
356 }
357
358
359
360
361 int osrf_message_from_xml( char* xml, osrf_message* msgs[] ) {
362
363         if(!xml) return 0;
364
365         xmlKeepBlanksDefault(0);
366
367         xmlNodePtr      message_node;
368         xmlDocPtr       doc = xmlReadDoc( 
369                         BAD_CAST xml, NULL, NULL, XML_PARSE_NSCLEAN );
370
371         xmlNodePtr root =xmlDocGetRootElement(doc);
372         if(!root) {
373                 warning_handler( "Attempt to build message from incomplete xml %s", xml );
374                 return 0;
375         }
376
377         int msg_index = 0;
378         message_node = root->children; /* since it's the only child */
379
380         if(!message_node) {
381                 warning_handler( "Attempt to build message from incomplete xml %s", xml );
382                 return 0;
383         }
384
385         while( message_node != NULL ) {
386
387                 xmlNodePtr cur_node = message_node->children;
388                 osrf_message* new_msg = safe_malloc(sizeof(osrf_message));
389                 new_msg->parse_json_result = parse_json_result;
390         
391
392                 while( cur_node ) {
393
394                         xmlChar* name = NULL; 
395                         xmlChar* value = NULL;
396                         
397                         /* we're a domainObjectAttr */
398                         if( !strcmp((char*)cur_node->name,"domainObjectAttr" )) {
399                                 name = xmlGetProp( cur_node, BAD_CAST "name");
400         
401                                 if(name) {
402         
403                                         value = xmlGetProp( cur_node, BAD_CAST "value" );
404                                         if(value) {
405         
406                                                 if( (!strcmp((char*)name, "type")) ) { /* what type are we? */
407         
408                                                         if(!strcmp((char*)value, "CONNECT"))
409                                                                 new_msg->m_type = CONNECT;
410         
411                                                         if(!strcmp((char*)value, "DISCONNECT"))
412                                                                 new_msg->m_type = DISCONNECT;
413                 
414                                                         if(!strcmp((char*)value, "STATUS"))
415                                                                 new_msg->m_type = STATUS;
416                 
417                                                         if(!strcmp((char*)value, "REQUEST"))
418                                                                 new_msg->m_type = REQUEST;
419                                                         
420                                                         if(!strcmp((char*)value, "RESULT"))
421                                                                 new_msg->m_type = RESULT;
422                         
423                                                 } else if((!strcmp((char*)name, "threadTrace"))) {
424                                                         new_msg->thread_trace = atoi( (char*) value );
425                         
426                                                 } else if((!strcmp((char*)name, "protocol"))) {
427                                                         new_msg->protocol = atoi( (char*) value );
428                                                 }
429         
430                                                 xmlFree(value);
431                                         }
432                                         xmlFree(name);
433                                 }
434                         }
435         
436                         /* we're a domainObject */
437                         if( !strcmp((char*)cur_node->name,"domainObject" )) {
438         
439                                 name = xmlGetProp( cur_node, BAD_CAST "name");
440         
441                                 if(name) {
442
443                                         if( !strcmp(name,"oilsMethod") ) {
444         
445                                                 xmlNodePtr meth_node = cur_node->children;
446         
447                                                 while( meth_node != NULL ) {
448         
449                                                         if( !strcmp((char*)meth_node->name,"domainObjectAttr" )) {
450                                                                 char* meth_name = xmlGetProp( meth_node, BAD_CAST "value" );
451                                                                 if(meth_name) {
452                                                                         new_msg->method_name = strdup(meth_name);
453                                                                         xmlFree(meth_name);
454                                                                 }
455                                                         }
456         
457                                                         if( !strcmp((char*)meth_node->name,"params" ) && meth_node->children->content ) {
458                                                                 //new_msg->params = json_object_new_string( meth_node->children->content );
459                                                                 if( new_msg->parse_json_params) {
460                                                                         new_msg->params = json_tokener_parse(meth_node->children->content);
461                                                                 } else {
462                                                                         /* XXX this will have to parse the JSON to 
463                                                                                 grab the strings for full support! This should only be 
464                                                                                 necessary for server support of 
465                                                                                 non-json-param-parsing, though. Ugh. */
466                                                                         new_msg->params = json_tokener_parse(meth_node->children->content);
467                                                                 }       
468                                                         }
469
470                                                         meth_node = meth_node->next;
471                                                 }
472                                         } //oilsMethod
473         
474                                         if( !strcmp(name,"oilsResult") || new_msg->m_type == STATUS ) {
475         
476                                                 xmlNodePtr result_nodes = cur_node->children;
477         
478                                                 while( result_nodes ) {
479         
480                                                         if(!strcmp(result_nodes->name,"domainObjectAttr")) {
481         
482                                                                 xmlChar* result_attr_name = xmlGetProp( result_nodes, BAD_CAST "name");
483                                                                 if(result_attr_name) {
484                                                                         xmlChar* result_attr_value = xmlGetProp( result_nodes, BAD_CAST "value" );
485         
486                                                                         if( result_attr_value ) {
487                                                                                 if((!strcmp((char*)result_attr_name, "status"))) 
488                                                                                         new_msg->status_text = strdup((char*) result_attr_value );
489         
490                                                                                 else if((!strcmp((char*)result_attr_name, "statusCode"))) 
491                                                                                         new_msg->status_code = atoi((char*) result_attr_value );
492                                                                                 xmlFree(result_attr_value);
493                                                                         }
494         
495                                                                         xmlFree(result_attr_name);
496                                                                 }
497         
498                                                         }
499                                                 
500         
501                                                         if(!strcmp(result_nodes->name,"domainObject")) {
502                                                                 xmlChar* r_name = xmlGetProp( result_nodes, BAD_CAST "name" );
503                                                                 if(r_name) {
504                                                                         if( !strcmp((char*)r_name,"oilsScalar") && result_nodes->children->content ) {
505                                                                                 osrf_message_set_result_content( new_msg, result_nodes->children->content);
506                                                                         }
507                                                                         xmlFree(r_name);
508                                                                 }
509                                                         }
510                                                         result_nodes = result_nodes->next;
511                                                 }
512                                         }
513                                         
514                                         if( new_msg->m_type == STATUS ) 
515                                                 new_msg->status_name = strdup(name); 
516
517                                         xmlFree(name);
518                                 }
519                         }
520         
521                         /* we're a params node */
522                         if( !strcmp((char*)cur_node->name,"params" )) {
523         
524                         }
525         
526                         cur_node = cur_node->next;
527                 }
528         
529                 msgs[msg_index] = new_msg;
530                 msg_index++;
531                 message_node = message_node->next;
532
533         } // while message_node != null
534
535         xmlCleanupCharEncodingHandlers();
536         xmlFreeDoc( doc );
537         xmlCleanupParser();
538
539         return msg_index;
540
541 }
542
543