]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_idl-core.c
When loading the IDL code in C or Perl: generate the array_positions
[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                                         prop_str,
65                                         "tablename"
66                                 );
67                         }
68
69                         if ((prop_str = (char*)xmlGetNsProp(kid, BAD_CAST "restrict_primary", BAD_CAST PERSIST_NS))) {
70                                 osrfLogDebug(OSRF_LOG_MARK, "Delete restriction policy set at '%s' for pkey of class %s", prop_str, current_class_name );
71                                 osrfHashSet(
72                                         class_def_hash,
73                                         prop_str,
74                                         "restrict_primary"
75                                 );
76                         }
77
78                         if ((prop_str = (char*)xmlGetNsProp(kid, BAD_CAST "virtual", BAD_CAST PERSIST_NS))) {
79                                 osrfHashSet(
80                                         class_def_hash,
81                                         prop_str,
82                                         "virtual"
83                                 );
84                         }
85
86                         // Tokenize controller attribute into an osrfStringArray
87                         prop_str = (char*) xmlGetProp(kid, BAD_CAST "controller");
88                         if( prop_str )
89                                 osrfLogDebug(OSRF_LOG_MARK, "Controller list is %s", prop_str );
90                         osrfStringArray* controller = osrfStringArrayTokenize( prop_str, ' ' );
91                         xmlFree( prop_str );
92                         osrfHashSet( class_def_hash, controller, "controller");
93
94                         osrfHash* current_links_hash = osrfNewHash();
95                         osrfHash* current_fields_hash = osrfNewHash();
96
97                         osrfHashSet( class_def_hash, current_fields_hash, "fields" );
98                         osrfHashSet( class_def_hash, current_links_hash, "links" );
99
100                         xmlNodePtr _cur = kid->children;
101
102                         while (_cur) {
103
104                                 if (!strcmp( (char*)_cur->name, "fields" )) {
105
106                                         if( (prop_str = (char*)xmlGetNsProp(_cur, BAD_CAST "primary", BAD_CAST PERSIST_NS)) ) {
107                                                 osrfHashSet(
108                                                         class_def_hash,
109                                                         prop_str,
110                                                         "primarykey"
111                                                 );
112                                         }
113
114                                         if( (prop_str = (char*)xmlGetNsProp(_cur, BAD_CAST "sequence", BAD_CAST PERSIST_NS)) ) {
115                                                 osrfHashSet(
116                                                         class_def_hash,
117                                                         prop_str,
118                                                         "sequence"
119                                                 );
120                                         }
121
122                                         unsigned int array_pos = 0;
123                                         char array_pos_buf[ 7 ];  // For up to 1,000,000 fields per class
124                                         xmlNodePtr _f = _cur->children;
125
126                                         while(_f) {
127                                                 if (strcmp( (char*)_f->name, "field" )) {
128                                                         _f = _f->next;
129                                                         continue;
130                                                 }
131
132                                                 osrfHash* field_def_hash = osrfNewHash();
133
134                                                 // Insert array_position
135                                                 snprintf( array_pos_buf, sizeof( array_pos_buf ), "%u", array_pos++ );
136                                                 osrfHashSet( field_def_hash, strdup( array_pos_buf ), "array_position" );
137
138                                                 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "i18n", BAD_CAST PERSIST_NS)) ) {
139                                                         osrfHashSet(
140                                                                 field_def_hash,
141                                                                 prop_str,
142                                                                 "i18n"
143                                                         );
144                                                 }
145
146                                                 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "virtual", BAD_CAST PERSIST_NS)) ) {
147                                                         osrfHashSet(
148                                                                 field_def_hash,
149                                                                 prop_str,
150                                                                 "virtual"
151                                                         );
152                                                 } else {   // default to virtual
153                                                         osrfHashSet(
154                                                                 field_def_hash,
155                                                                 "false",
156                                                                 "virtual"
157                                                         );
158                                                 }
159
160                                                 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "primitive", BAD_CAST PERSIST_NS)) ) {
161                                                         osrfHashSet(
162                                                                 field_def_hash,
163                                                                 prop_str,
164                                                                 "primitive"
165                                                         );
166                                                 }
167
168                                                 if( (prop_str = (char*)xmlGetProp(_f, BAD_CAST "name")) ) {
169                                                         osrfHashSet(
170                                                                 field_def_hash,
171                                                                 prop_str,
172                                                                 "name"
173                                                         );
174                                                         osrfLogDebug(OSRF_LOG_MARK, 
175                                                                 "Found field %s for class %s", prop_str, current_class_name );
176                                                 } else
177                                                         osrfLogDebug(OSRF_LOG_MARK, 
178                                                                 "Found field with no name for class %s", current_class_name );
179
180                                                 osrfHashSet(
181                                                         current_fields_hash,
182                                                         field_def_hash,
183                                                         prop_str
184                                                 );
185                                                 _f = _f->next;
186                                         }
187                                 }
188
189                                 if (!strcmp( (char*)_cur->name, "links" )) {
190                                         xmlNodePtr _l = _cur->children;
191
192                                         while(_l) {
193                                                 if (strcmp( (char*)_l->name, "link" )) {
194                                                         _l = _l->next;
195                                                         continue;
196                                                 }
197
198                                                 osrfHash* link_def_hash = osrfNewHash();
199
200                                                 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "reltype")) ) {
201                                                         osrfHashSet(
202                                                                 link_def_hash,
203                                                                 prop_str,
204                                                                 "reltype"
205                                                         );
206                                                         osrfLogDebug(OSRF_LOG_MARK, "Adding link with reltype %s", prop_str );
207                                                 } else
208                                                         osrfLogDebug(OSRF_LOG_MARK, "Adding link with no reltype" );
209
210                                                 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "key")) ) {
211                                                         osrfHashSet(
212                                                                 link_def_hash,
213                                                                 prop_str,
214                                                                 "key"
215                                                         );
216                                                         osrfLogDebug(OSRF_LOG_MARK, "Link fkey is %s", prop_str );
217                                                 } else
218                                                         osrfLogDebug(OSRF_LOG_MARK, "Link with no fkey" );
219
220                                                 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "class")) ) {
221                                                         osrfHashSet(
222                                                                 link_def_hash,
223                                                                 prop_str,
224                                                                 "class"
225                                                         );
226                                                         osrfLogDebug(OSRF_LOG_MARK, "Link fclass is %s", prop_str );
227                                                 } else
228                                                         osrfLogDebug(OSRF_LOG_MARK, "Link with no fclass" );
229
230                                                 // Tokenize map attribute into an osrfStringArray
231                                                 prop_str = (char*) xmlGetProp(_l, BAD_CAST "map");
232                                                 if( prop_str )
233                                                         osrfLogDebug(OSRF_LOG_MARK, "Link mapping list is %s", prop_str );
234                                                 osrfStringArray* map = osrfStringArrayTokenize( prop_str, ' ' );
235                                                 osrfHashSet( link_def_hash, map, "map");
236                                                 xmlFree( prop_str );
237
238                                                 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "field")) ) {
239                                                         osrfHashSet(
240                                                                 link_def_hash,
241                                                                 prop_str,
242                                                                 "field"
243                                                         );
244                                                         osrfLogDebug(OSRF_LOG_MARK, "Link fclass is %s", prop_str );
245                                                 } else
246                                                         osrfLogDebug(OSRF_LOG_MARK, "Link with no fclass" );
247
248                                                 osrfHashSet(
249                                                         current_links_hash,
250                                                         link_def_hash,
251                                                         prop_str
252                                                 );
253
254                                                 _l = _l->next;
255                                         }
256                                 }
257 /**** Structure of permacrud in memory ****
258
259 { create :
260     { permission : [ x, y, z ],
261       global_required : "true", -- anything else, or missing, is false
262       local_context : [ f1, f2 ],
263       foreign_context : { class1 : { fkey : local_class_key, field : class1_field, context : [ a, b, c ] }, ...}
264     },
265   retrieve : null, -- no perm check, or structure similar to the others
266   update : -- like create
267     ...
268   delete : -- like create
269     ...
270 }   
271
272 **** Structure of permacrud in memory ****/
273
274                                 if (!strcmp( (char*)_cur->name, "permacrud" )) {
275                                         osrfHash* pcrud = osrfNewHash();
276                                         osrfHashSet( class_def_hash, pcrud, "permacrud" );
277                                         xmlNodePtr _l = _cur->children;
278
279                                         while(_l) {
280                                                 if (strcmp( (char*)_l->name, "actions" )) {
281                                                         _l = _l->next;
282                                                         continue;
283                                                 }
284
285                                                 xmlNodePtr _a = _l->children;
286
287                                                 while(_a) {
288                                                         const char* action_name = (const char*) _a->name;
289                                                         if (
290                                                                 strcmp( action_name, "create" ) &&
291                                                                 strcmp( action_name, "retrieve" ) &&
292                                                                 strcmp( action_name, "update" ) &&
293                                                                 strcmp( action_name, "delete" )
294                                                         ) {
295                                                                 _a = _a->next;
296                                                                 continue;
297                                                         }
298
299                                                         osrfLogDebug(OSRF_LOG_MARK, "Found Permacrud action %s for class %s",
300                                                                 action_name, current_class_name );
301
302                                                         osrfHash* action_def_hash = osrfNewHash();
303                                                         osrfHashSet( pcrud, action_def_hash, action_name );
304
305                                                         // Tokenize permission attribute into an osrfStringArray
306                                                         prop_str = (char*) xmlGetProp(_a, BAD_CAST "permission");
307                                                         if( prop_str )
308                                                                 osrfLogDebug(OSRF_LOG_MARK,
309                                                                         "Permacrud permission list is %s", prop_str );
310                                                         osrfStringArray* map = osrfStringArrayTokenize( prop_str, ' ' );
311                                                         osrfHashSet( action_def_hash, map, "permission");
312                                                         xmlFree( prop_str );
313
314                                                 osrfHashSet( action_def_hash,
315                                                                 (char*)xmlGetNoNsProp(_a, BAD_CAST "global_required"), "global_required");
316
317                                                         // Tokenize context_field attribute into an osrfStringArray
318                                                         prop_str = (char*) xmlGetProp(_a, BAD_CAST "context_field");
319                                                         if( prop_str )
320                                                                 osrfLogDebug(OSRF_LOG_MARK,
321                                                                         "Permacrud context_field list is %s", prop_str );
322                                                         map = osrfStringArrayTokenize( prop_str, ' ' );
323                                                         osrfHashSet( action_def_hash, map, "local_context");
324                                                         xmlFree( prop_str );
325
326                                                         osrfHash* foreign_context = osrfNewHash();
327                                                         osrfHashSet( action_def_hash, foreign_context, "foreign_context");
328
329                                                         xmlNodePtr _f = _a->children;
330
331                                                         while(_f) {
332                                                                 if ( strcmp( (char*)_f->name, "context" ) ) {
333                                                                         _f = _f->next;
334                                                                         continue;
335                                                                 }
336
337                                                                 if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "link")) ) {
338                                                                         osrfLogDebug(OSRF_LOG_MARK,
339                                                                                 "Permacrud context link definition is %s", prop_str );
340
341                                                                         osrfHash* _tmp_fcontext = osrfNewHash();
342
343                                                                         // Store pointers to elements already stored
344                                                                         // from the <link> aggregate
345                                                                         osrfHash* _flink = osrfHashGet( current_links_hash, prop_str );
346                                                                         osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "field"), "fkey" );
347                                                                         osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "key"), "field" );
348                                                                         xmlFree( prop_str );
349
350                                                                     if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "jump")) )
351                                                                             osrfHashSet( _tmp_fcontext, osrfStringArrayTokenize( prop_str, '.' ), "jump" );
352                                                                         xmlFree( prop_str );
353
354                                                                         // Tokenize field attribute into an osrfStringArray
355                                                                         char * field_list = (char*) xmlGetProp(_f, BAD_CAST "field");
356                                                                         if( field_list )
357                                                                                 osrfLogDebug(OSRF_LOG_MARK,
358                                                                                         "Permacrud foreign context field list is %s", field_list );
359                                                                         map = osrfStringArrayTokenize( field_list, ' ' );
360                                                                         osrfHashSet( _tmp_fcontext, map, "context");
361                                                                         xmlFree( field_list );
362
363                                                                         // Insert the new hash into a hash attached to the parent node
364                                                                         osrfHashSet( foreign_context, _tmp_fcontext, osrfHashGet( _flink, "class" ) );
365
366                                                                 } else {
367
368                                                                         if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "field") )) {
369                                                                                 char* map_list = prop_str;
370                                                                                 osrfLogDebug(OSRF_LOG_MARK,
371                                                                                         "Permacrud local context field list is %s", prop_str );
372                         
373                                                                                 if (strlen( map_list ) > 0) {
374                                                                                         char* st_tmp = NULL;
375                                                                                         char* _map_class = strtok_r(map_list, " ", &st_tmp);
376                                                                                         osrfStringArrayAdd(
377                                                                                                 osrfHashGet( action_def_hash, "local_context"), _map_class);
378                                                                         
379                                                                                         while ((_map_class = strtok_r(NULL, " ", &st_tmp))) {
380                                                                                                 osrfStringArrayAdd(
381                                                                                                         osrfHashGet( action_def_hash, "local_context"), _map_class);
382                                                                                         }
383                                                                                 }
384                                                                                 xmlFree(map_list);
385                                                                         }
386
387                                                                 }
388                                                                 _f = _f->next;
389                                                         }
390                                                         _a = _a->next;
391                                                 }
392                                                 _l = _l->next;
393                                         }
394                                 }
395
396                                 if (!strcmp( (char*)_cur->name, "source_definition" )) {
397                                         char* content_str;
398                                         if( (content_str = (char*)xmlNodeGetContent(_cur)) ) {
399                                                 osrfLogDebug(OSRF_LOG_MARK, "Using source definition '%s' for class %s",
400                                                         content_str, current_class_name );
401                                                 osrfHashSet(
402                                                         class_def_hash,
403                                                         content_str,
404                                                         "source_definition"
405                                                 );
406                                         }
407
408                                 }
409
410                                 _cur = _cur->next;
411                         } // end while
412                 }
413
414                 kid = kid->next;
415         } // end while
416
417         osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
418
419         return idlHash;
420 }
421
422 osrfHash* oilsIDLFindPath( const char* path, ... ) {
423         if(!path || strlen(path) < 1) return NULL;
424
425         osrfHash* obj = idlHash;
426
427         VA_LIST_TO_STRING(path);
428         char* buf = VA_BUF;
429
430         char* token = NULL;
431         char* t = buf;
432         char* tt;
433
434         token = strtok_r(t, "/", &tt);
435         if(!token) return NULL;
436
437         do {
438                 obj = osrfHashGet(obj, token);
439         } while( (token = strtok_r(NULL, "/", &tt)) && obj);
440
441         return obj;
442 }
443
444 static osrfHash* findClassDef( const char* classname ) {
445         if( !classname || !idlHash )
446                 return NULL;
447         else
448                 return osrfHashGet( idlHash, classname );
449 }
450
451 osrfHash* oilsIDL_links( const char* classname ) {
452         osrfHash* classdef = findClassDef( classname );
453         if( classdef )
454                 return osrfHashGet( classdef, "links" );
455         else
456                 return NULL;
457 }
458
459 osrfHash* oilsIDL_fields( const char* classname ) {
460         osrfHash* classdef = findClassDef( classname );
461         if( classdef )
462                 return osrfHashGet( classdef, "fields" );
463         else
464                 return NULL;
465 }
466
467 int oilsIDL_classIsFieldmapper ( const char* classname ) {
468         if( findClassDef( classname ) )
469                 return 1;
470         else
471                 return 0;
472 }
473
474 // For a given class: return the array_position associated with a 
475 // specified field. (or -1 if it doesn't exist)
476 int oilsIDL_ntop (const char* classname, const char* fieldname) {
477         osrfHash* fields_hash = oilsIDL_fields( classname );
478         if( !fields_hash )
479                 return -1;     // No such class, or no fields for it
480
481         osrfHash* field_def_hash = osrfHashGet( fields_hash, fieldname );
482         if( !field_def_hash )
483                 return -1;                      // No such field
484
485         const char* pos_attr = osrfHashGet( field_def_hash, "array_position" );
486         if( !pos_attr )
487                 return -1;                      // No array_position attribute
488
489         return atoi( pos_attr );        // Return position as int
490 }
491
492 // For a given class: return a copy of the name of the field 
493 // at a specified array_position (or NULL if there is none)
494 char * oilsIDL_pton (const char* classname, int pos) {
495         osrfHash* fields_hash = oilsIDL_fields( classname );
496         if( !fields_hash )
497                 return NULL;     // No such class, or no fields for it
498
499         char* ret = NULL;
500         osrfHash* field_def_hash = NULL;
501         osrfHashIterator* iter = osrfNewHashIterator( fields_hash );
502
503         while ( ( field_def_hash = osrfHashIteratorNext( iter ) ) ) {
504                 if ( atoi( osrfHashGet( field_def_hash, "array_position" ) ) == pos ) {
505                         ret = strdup( osrfHashIteratorKey( iter ) );
506                         break;
507                 }
508         }
509
510         osrfHashIteratorFree( iter );
511
512         return ret;
513 }
514