]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_idl-core.c
adding support for jump attribute, for remote indirection; fixing incorrect comment
[Evergreen.git] / Open-ILS / src / c-apps / oils_idl-core.c
1 #include "openils/oils_idl.h"
2 /*
3  * vim:noet:ts=4:
4  */
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <libxml/globals.h>
9 #include <libxml/xmlerror.h>
10 #include <libxml/parser.h>
11 #include <libxml/tree.h>
12 #include <libxml/debugXML.h>
13 #include <libxml/xmlmemory.h>
14
15 #define PERSIST_NS "http://open-ils.org/spec/opensrf/IDL/persistence/v1"
16 #define OBJECT_NS "http://open-ils.org/spec/opensrf/IDL/objects/v1"
17 #define BASE_NS "http://opensrf.org/spec/IDL/base/v1"
18 #define REPORTER_NS "http://open-ils.org/spec/opensrf/IDL/reporter/v1"
19 #define PERM_NS "http://open-ils.org/spec/opensrf/IDL/permacrud/v1"
20
21 static xmlDocPtr idlDoc = NULL; // parse and store the IDL here
22
23 /* parse and store the IDL here */
24 static osrfHash* idlHash;
25
26 osrfHash* oilsIDL(void) { return idlHash; }
27 osrfHash* oilsIDLInit( const char* idl_filename ) {
28
29         if (idlHash) return idlHash;
30
31         char* prop_str = NULL;
32
33         idlHash = osrfNewHash();
34         osrfHash* class_def_hash = NULL;
35
36         osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML...");
37         idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE );
38         
39         if (!idlDoc) {
40                 osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!");
41                 return NULL;
42         }
43
44         osrfLogDebug(OSRF_LOG_MARK, "Initializing the Fieldmapper IDL...");
45
46         xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc);
47         xmlNodePtr kid = docRoot->children;
48         while (kid) {
49                 if (!strcmp( (char*)kid->name, "class" )) {
50
51                         class_def_hash = osrfNewHash();
52                         char* current_class_name = (char*) xmlGetProp(kid, BAD_CAST "id");
53                         
54                         osrfHashSet( class_def_hash, current_class_name, "classname" );
55                         osrfHashSet( class_def_hash, xmlGetNsProp(kid, BAD_CAST "fieldmapper", BAD_CAST OBJECT_NS), "fieldmapper" );
56                         osrfHashSet( class_def_hash, xmlGetNsProp(kid, BAD_CAST "readonly", BAD_CAST PERSIST_NS), "readonly" );
57
58                         osrfHashSet( idlHash, class_def_hash, current_class_name );
59
60                         if ((prop_str = (char*)xmlGetNsProp(kid, BAD_CAST "tablename", BAD_CAST PERSIST_NS))) {
61                                 osrfLogDebug(OSRF_LOG_MARK, "Using table '%s' for class %s", prop_str, current_class_name );
62                                 osrfHashSet(
63                                         class_def_hash,
64                                         strdup( prop_str ),
65                                         "tablename"
66                                 );
67                         }
68
69                         if ((prop_str = (char*)xmlGetNsProp(kid, BAD_CAST "virtual", BAD_CAST PERSIST_NS))) {
70                                 osrfHashSet(
71                                         class_def_hash,
72                                         strdup( prop_str ),
73                                         "virtual"
74                                 );
75                         }
76
77                         // Tokenize controller attribute into an osrfStringArray
78                         prop_str = (char*) xmlGetProp(kid, BAD_CAST "controller");
79                         if( prop_str )
80                                 osrfLogDebug(OSRF_LOG_MARK, "Controller list is %s", prop_str );
81                         osrfStringArray* controller = osrfStringArrayTokenize( prop_str, ' ' );
82                         osrfHashSet( class_def_hash, controller, "controller");
83
84                         osrfHash* current_links_hash = osrfNewHash();
85                         osrfHash* current_fields_hash = osrfNewHash();
86                         osrfHash* pcrud = osrfNewHash();
87
88                         osrfHashSet( class_def_hash, current_fields_hash, "fields" );
89                         osrfHashSet( class_def_hash, current_links_hash, "links" );
90
91                         xmlNodePtr _cur = kid->children;
92
93                         while (_cur) {
94
95                                 if (!strcmp( (char*)_cur->name, "fields" )) {
96
97                                         if( (prop_str = (char*)xmlGetNsProp(_cur, BAD_CAST "primary", BAD_CAST PERSIST_NS)) ) {
98                                                 osrfHashSet(
99                                                         class_def_hash,
100                                                         strdup( prop_str ),
101                                                         "primarykey"
102                                                 );
103                                         }
104
105                                         if( (prop_str = (char*)xmlGetNsProp(_cur, BAD_CAST "sequence", BAD_CAST PERSIST_NS)) ) {
106                                                 osrfHashSet(
107                                                         class_def_hash,
108                                                         strdup( prop_str ),
109                                                         "sequence"
110                                                 );
111                                         }
112
113                                         xmlNodePtr _f = _cur->children;
114
115                                         while(_f) {
116                                                 if (strcmp( (char*)_f->name, "field" )) {
117                                                         _f = _f->next;
118                                                         continue;
119                                                 }
120
121                                                 osrfHash* field_def_hash = osrfNewHash();
122
123                                                 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "array_position", BAD_CAST OBJECT_NS)) ) {
124                                                         osrfHashSet(
125                                                                 field_def_hash,
126                                                                 strdup( prop_str ),
127                                                                 "array_position"
128                                                         );
129                                                 }
130
131                                                 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "i18n", BAD_CAST PERSIST_NS)) ) {
132                                                         osrfHashSet(
133                                                                 field_def_hash,
134                                                                 strdup( prop_str ),
135                                                                 "i18n"
136                                                         );
137                                                 }
138
139                                                 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "virtual", BAD_CAST PERSIST_NS)) ) {
140                                                         osrfHashSet(
141                                                                 field_def_hash,
142                                                                 strdup( prop_str ),
143                                                                 "virtual"
144                                                         );
145                                                 }
146
147                                                 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "primitive", BAD_CAST PERSIST_NS)) ) {
148                                                         osrfHashSet(
149                                                                 field_def_hash,
150                                                                 strdup( prop_str ),
151                                                                 "primitive"
152                                                         );
153                                                 }
154
155                                                 if( (prop_str = (char*)xmlGetProp(_f, BAD_CAST "name")) ) {
156                                                         osrfHashSet(
157                                                                 field_def_hash,
158                                                                 strdup( prop_str ),
159                                                                 "name"
160                                                         );
161                                                         osrfLogDebug(OSRF_LOG_MARK, 
162                                                                 "Found field %s for class %s", prop_str, current_class_name );
163                                                 } else
164                                                         osrfLogDebug(OSRF_LOG_MARK, 
165                                                                 "Found field with no name for class %s", current_class_name );
166
167                                                 osrfHashSet(
168                                                         current_fields_hash,
169                                                         field_def_hash,
170                                                         prop_str
171                                                 );
172                                                 _f = _f->next;
173                                         }
174                                 }
175
176                                 if (!strcmp( (char*)_cur->name, "links" )) {
177                                         xmlNodePtr _l = _cur->children;
178
179                                         while(_l) {
180                                                 if (strcmp( (char*)_l->name, "link" )) {
181                                                         _l = _l->next;
182                                                         continue;
183                                                 }
184
185                                                 osrfHash* link_def_hash = osrfNewHash();
186
187                                                 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "reltype")) ) {
188                                                         osrfHashSet(
189                                                                 link_def_hash,
190                                                                 strdup( prop_str ),
191                                                                 "reltype"
192                                                         );
193                                                         osrfLogDebug(OSRF_LOG_MARK, "Adding link with reltype %s", prop_str );
194                                                 } else
195                                                         osrfLogDebug(OSRF_LOG_MARK, "Adding link with no reltype" );
196
197                                                 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "key")) ) {
198                                                         osrfHashSet(
199                                                                 link_def_hash,
200                                                                 strdup( prop_str ),
201                                                                 "key"
202                                                         );
203                                                         osrfLogDebug(OSRF_LOG_MARK, "Link fkey is %s", prop_str );
204                                                 } else
205                                                         osrfLogDebug(OSRF_LOG_MARK, "Link with no fkey" );
206
207                                                 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "class")) ) {
208                                                         osrfHashSet(
209                                                                 link_def_hash,
210                                                                 strdup( prop_str ),
211                                                                 "class"
212                                                         );
213                                                         osrfLogDebug(OSRF_LOG_MARK, "Link fclass is %s", prop_str );
214                                                 } else
215                                                         osrfLogDebug(OSRF_LOG_MARK, "Link with no fclass" );
216
217                                                 // Tokenize map attribute into an osrfStringArray
218                                                 prop_str = (char*) xmlGetProp(_l, BAD_CAST "map");
219                                                 if( prop_str )
220                                                         osrfLogDebug(OSRF_LOG_MARK, "Link mapping list is %s", prop_str );
221                                                 osrfStringArray* map = osrfStringArrayTokenize( prop_str, ' ' );
222                                                 osrfHashSet( link_def_hash, map, "map");
223
224                                                 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "field")) ) {
225                                                         osrfHashSet(
226                                                                 link_def_hash,
227                                                                 strdup( prop_str ),
228                                                                 "field"
229                                                         );
230                                                         osrfLogDebug(OSRF_LOG_MARK, "Link fclass is %s", prop_str );
231                                                 } else
232                                                         osrfLogDebug(OSRF_LOG_MARK, "Link with no fclass" );
233
234                                                 osrfHashSet(
235                                                         current_links_hash,
236                                                         link_def_hash,
237                                                         prop_str
238                                                 );
239
240                                                 _l = _l->next;
241                                         }
242                                 }
243 /**** Structure of permacrud in memory ****
244
245 { create :
246     { permission : [ x, y, z ],
247       global_required : "true", -- anything else, or missing, is false
248       local_context : [ f1, f2 ],
249       foreign_context : { class1 : { fkey : local_class_key, field : class1_field, context : [ a, b, c ] }, ...}
250     },
251   retrieve : null, -- no perm check, or structure similar to the others
252   update : -- like create
253     ...
254   delete : -- like create
255     ...
256 }   
257
258 **** Structure of permacrud in memory ****/
259
260                                 if (!strcmp( (char*)_cur->name, "permacrud" )) {
261                                         osrfHashSet( class_def_hash, pcrud, "permacrud" );
262                                         xmlNodePtr _l = _cur->children;
263
264                                         while(_l) {
265                                                 if (strcmp( (char*)_l->name, "actions" )) {
266                                                         _l = _l->next;
267                                                         continue;
268                                                 }
269
270                                                 xmlNodePtr _a = _l->children;
271
272                                                 while(_a) {
273                                                         const char* action_name = (const char*) _a->name;
274                                                         if (
275                                                                 strcmp( action_name, "create" ) &&
276                                                                 strcmp( action_name, "retrieve" ) &&
277                                                                 strcmp( action_name, "update" ) &&
278                                                                 strcmp( action_name, "delete" )
279                                                         ) {
280                                                                 _a = _a->next;
281                                                                 continue;
282                                                         }
283
284                                                         osrfLogDebug(OSRF_LOG_MARK, "Found Permacrud action %s for class %s",
285                                                                 action_name, current_class_name );
286
287                                                         osrfHash* action_def_hash = osrfNewHash();
288                                                         osrfHashSet( pcrud, action_def_hash, action_name );
289
290                                                         // Tokenize permission attribute into an osrfStringArray
291                                                         prop_str = (char*) xmlGetProp(_a, BAD_CAST "permission");
292                                                         if( prop_str )
293                                                                 osrfLogDebug(OSRF_LOG_MARK,
294                                                                         "Permacrud permission list is %s", prop_str );
295                                                         osrfStringArray* map = osrfStringArrayTokenize( prop_str, ' ' );
296                                                         osrfHashSet( action_def_hash, map, "permission");
297
298                                                 osrfHashSet( action_def_hash,
299                                                                 (char*)xmlGetNoNsProp(_a, BAD_CAST "global_required"), "global_required");
300
301                                                         // Tokenize context_field attribute into an osrfStringArray
302                                                         prop_str = (char*) xmlGetProp(_a, BAD_CAST "context_field");
303                                                         if( prop_str )
304                                                                 osrfLogDebug(OSRF_LOG_MARK,
305                                                                         "Permacrud context_field list is %s", prop_str );
306                                                         map = osrfStringArrayTokenize( prop_str, ' ' );
307                                                         osrfHashSet( action_def_hash, map, "local_context");
308
309                                                         osrfHash* foreign_context = osrfNewHash();
310                                                         osrfHashSet( action_def_hash, foreign_context, "foreign_context");
311
312                                                         xmlNodePtr _f = _a->children;
313
314                                                         while(_f) {
315                                                                 if ( strcmp( (char*)_f->name, "context" ) ) {
316                                                                         _f = _f->next;
317                                                                         continue;
318                                                                 }
319
320                                                                 if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "link")) ) {
321                                                                         osrfLogDebug(OSRF_LOG_MARK,
322                                                                                 "Permacrud context link definition is %s", prop_str );
323
324                                                                         osrfHash* _tmp_fcontext = osrfNewHash();
325
326                                                                         // Store pointers to elements already stored
327                                                                         // from the <link> aggregate
328                                                                         osrfHash* _flink = osrfHashGet( current_links_hash, prop_str );
329                                                                         osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "field"), "fkey" );
330                                                                         osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "key"), "field" );
331
332                                                                     if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "jump")) )
333                                                                             osrfHashSet( _tmp_fcontext, osrfStringArrayTokenize( prop_str, '.' ), "jump" );
334
335                                                                         // Tokenize field attribute into an osrfStringArray
336                                                                         const char * field_list = (char*) xmlGetProp(_f, BAD_CAST "field");
337                                                                         if( field_list )
338                                                                                 osrfLogDebug(OSRF_LOG_MARK,
339                                                                                         "Permacrud foreign context field list is %s", field_list );
340                                                                         map = osrfStringArrayTokenize( field_list, ' ' );
341                                                                         osrfHashSet( _tmp_fcontext, map, "context");
342
343                                                                         // Insert the new hash into a hash attached to the parent node
344                                                                         osrfHashSet( foreign_context, _tmp_fcontext, osrfHashGet( _flink, "class" ) );
345
346                                                                 } else {
347
348                                                                         if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "field") )) {
349                                                                                 char* map_list = strdup( prop_str );
350                                                                                 osrfLogDebug(OSRF_LOG_MARK,
351                                                                                         "Permacrud local context field list is %s", prop_str );
352                         
353                                                                                 if (strlen( map_list ) > 0) {
354                                                                                         char* st_tmp = NULL;
355                                                                                         char* _map_class = strtok_r(map_list, " ", &st_tmp);
356                                                                                         osrfStringArrayAdd(
357                                                                                                 osrfHashGet( action_def_hash, "local_context"), _map_class);
358                                                                         
359                                                                                         while ((_map_class = strtok_r(NULL, " ", &st_tmp))) {
360                                                                                                 osrfStringArrayAdd(
361                                                                                                         osrfHashGet( action_def_hash, "local_context"), _map_class);
362                                                                                         }
363                                                                                 }
364                                                                                 free(map_list);
365                                                                         }
366
367                                                                 }
368                                                                 _f = _f->next;
369                                                         }
370                                                         _a = _a->next;
371                                                 }
372                                                 _l = _l->next;
373                                         }
374                                 }
375
376                                 if (!strcmp( (char*)_cur->name, "source_definition" )) {
377                                         const char* content_str;
378                                         if( (content_str = (char*)xmlNodeGetContent(_cur)) ) {
379                                                 osrfLogDebug(OSRF_LOG_MARK, "Using source definition '%s' for class %s",
380                                                         content_str, current_class_name );
381                                                 osrfHashSet(
382                                                         class_def_hash,
383                                                         strdup( content_str ),
384                                                         "source_definition"
385                                                 );
386                                         }
387
388                                 }
389
390                                 _cur = _cur->next;
391                         } // end while
392                 }
393
394                 kid = kid->next;
395         } // end while
396
397         osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
398
399         return idlHash;
400 }
401
402 osrfHash* oilsIDLFindPath( const char* path, ... ) {
403         if(!path || strlen(path) < 1) return NULL;
404
405         osrfHash* obj = idlHash;
406
407         VA_LIST_TO_STRING(path);
408         char* buf = VA_BUF;
409
410         char* token = NULL;
411         char* t = buf;
412         char* tt;
413
414         token = strtok_r(t, "/", &tt);
415         if(!token) return NULL;
416
417         do {
418                 obj = osrfHashGet(obj, token);
419         } while( (token = strtok_r(NULL, "/", &tt)) && obj);
420
421         return obj;
422 }
423
424 static osrfHash* findClassDef( const char* classname ) {
425         if( !classname || !idlHash )
426                 return NULL;
427         else
428                 return osrfHashGet( idlHash, classname );
429 }
430
431 int oilsIDL_classIsFieldmapper ( const char* classname ) {
432         if( findClassDef( classname ) )
433                 return 1;
434         else
435                 return 0;
436 }
437
438 int oilsIDL_ntop (const char* classname, const char* fieldname) {
439         osrfHash* class_def_hash = findClassDef( classname );
440         if( !class_def_hash )
441                 return -1;                      // No such class
442         
443         osrfHash* fields_hash = osrfHashGet( class_def_hash, "fields" );
444         if( !fields_hash )
445                 return -1;                      // No list of fields fo the class
446
447         osrfHash* field_def_hash = osrfHashGet( fields_hash, fieldname );
448         if( !field_def_hash )
449                 return -1;                      // No such field
450
451         const char* pos_attr = osrfHashGet( field_def_hash, "array_position" );
452         if( !pos_attr )
453                 return -1;                      // No array_position attribute
454
455         return atoi( pos_attr );        // Return position as int
456 }
457
458 char * oilsIDL_pton (const char* classname, int pos) {
459         osrfHash* class_def_hash = findClassDef( classname );
460         if( !class_def_hash )
461                 return NULL;            // No such class
462         
463         osrfHash* fields_hash = osrfHashGet( class_def_hash, "fields" );
464         if( !fields_hash )
465                 return NULL;            // No list of fields fo the class
466
467         char* ret = NULL;
468         osrfHash* field_def_hash = NULL;
469         osrfHashIterator* iter = osrfNewHashIterator( fields_hash );
470
471         while ( ( field_def_hash = osrfHashIteratorNext( iter ) ) ) {
472                 if ( atoi( osrfHashGet( field_def_hash, "array_position" ) ) == pos ) {
473                         ret = strdup( osrfHashIteratorKey( iter ) );
474                         break;
475                 }
476         }
477
478         osrfHashIteratorFree( iter );
479
480         return ret;
481 }
482