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