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