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