1 #include "openils/oils_idl.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>
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"
21 static xmlDocPtr idlDoc = NULL; // parse and store the IDL here
23 /* parse and store the IDL here */
24 static osrfHash* idlHash;
26 osrfHash* oilsIDL(void) { return idlHash; }
27 osrfHash* oilsIDLInit( const char* idl_filename ) {
29 if (idlHash) return idlHash;
31 char* prop_str = NULL;
33 idlHash = osrfNewHash();
34 osrfHash* class_def_hash = NULL;
36 osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML...");
37 idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE );
40 osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!");
44 osrfLogDebug(OSRF_LOG_MARK, "Initializing the Fieldmapper IDL...");
46 xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc);
47 xmlNodePtr kid = docRoot->children;
49 if (!strcmp( (char*)kid->name, "class" )) {
51 class_def_hash = osrfNewHash();
52 char* current_class_name = (char*) xmlGetProp(kid, BAD_CAST "id");
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" );
58 osrfHashSet( idlHash, class_def_hash, current_class_name );
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 );
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 );
78 if ((prop_str = (char*)xmlGetNsProp(kid, BAD_CAST "virtual", BAD_CAST PERSIST_NS))) {
86 // Tokenize controller attribute into an osrfStringArray
87 prop_str = (char*) xmlGetProp(kid, BAD_CAST "controller");
89 osrfLogDebug(OSRF_LOG_MARK, "Controller list is %s", prop_str );
90 osrfStringArray* controller = osrfStringArrayTokenize( prop_str, ' ' );
91 osrfHashSet( class_def_hash, controller, "controller");
93 osrfHash* current_links_hash = osrfNewHash();
94 osrfHash* current_fields_hash = osrfNewHash();
95 osrfHash* pcrud = osrfNewHash();
97 osrfHashSet( class_def_hash, current_fields_hash, "fields" );
98 osrfHashSet( class_def_hash, current_links_hash, "links" );
100 xmlNodePtr _cur = kid->children;
104 if (!strcmp( (char*)_cur->name, "fields" )) {
106 if( (prop_str = (char*)xmlGetNsProp(_cur, BAD_CAST "primary", BAD_CAST PERSIST_NS)) ) {
114 if( (prop_str = (char*)xmlGetNsProp(_cur, BAD_CAST "sequence", BAD_CAST PERSIST_NS)) ) {
122 xmlNodePtr _f = _cur->children;
125 if (strcmp( (char*)_f->name, "field" )) {
130 osrfHash* field_def_hash = osrfNewHash();
132 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "array_position", BAD_CAST OBJECT_NS)) ) {
140 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "i18n", BAD_CAST PERSIST_NS)) ) {
148 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "virtual", BAD_CAST PERSIST_NS)) ) {
156 if( (prop_str = (char*)xmlGetNsProp(_f, BAD_CAST "primitive", BAD_CAST PERSIST_NS)) ) {
164 if( (prop_str = (char*)xmlGetProp(_f, BAD_CAST "name")) ) {
170 osrfLogDebug(OSRF_LOG_MARK,
171 "Found field %s for class %s", prop_str, current_class_name );
173 osrfLogDebug(OSRF_LOG_MARK,
174 "Found field with no name for class %s", current_class_name );
185 if (!strcmp( (char*)_cur->name, "links" )) {
186 xmlNodePtr _l = _cur->children;
189 if (strcmp( (char*)_l->name, "link" )) {
194 osrfHash* link_def_hash = osrfNewHash();
196 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "reltype")) ) {
202 osrfLogDebug(OSRF_LOG_MARK, "Adding link with reltype %s", prop_str );
204 osrfLogDebug(OSRF_LOG_MARK, "Adding link with no reltype" );
206 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "key")) ) {
212 osrfLogDebug(OSRF_LOG_MARK, "Link fkey is %s", prop_str );
214 osrfLogDebug(OSRF_LOG_MARK, "Link with no fkey" );
216 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "class")) ) {
222 osrfLogDebug(OSRF_LOG_MARK, "Link fclass is %s", prop_str );
224 osrfLogDebug(OSRF_LOG_MARK, "Link with no fclass" );
226 // Tokenize map attribute into an osrfStringArray
227 prop_str = (char*) xmlGetProp(_l, BAD_CAST "map");
229 osrfLogDebug(OSRF_LOG_MARK, "Link mapping list is %s", prop_str );
230 osrfStringArray* map = osrfStringArrayTokenize( prop_str, ' ' );
231 osrfHashSet( link_def_hash, map, "map");
233 if( (prop_str = (char*)xmlGetProp(_l, BAD_CAST "field")) ) {
239 osrfLogDebug(OSRF_LOG_MARK, "Link fclass is %s", prop_str );
241 osrfLogDebug(OSRF_LOG_MARK, "Link with no fclass" );
252 /**** Structure of permacrud in memory ****
255 { permission : [ x, y, z ],
256 global_required : "true", -- anything else, or missing, is false
257 local_context : [ f1, f2 ],
258 foreign_context : { class1 : { fkey : local_class_key, field : class1_field, context : [ a, b, c ] }, ...}
260 retrieve : null, -- no perm check, or structure similar to the others
261 update : -- like create
263 delete : -- like create
267 **** Structure of permacrud in memory ****/
269 if (!strcmp( (char*)_cur->name, "permacrud" )) {
270 osrfHashSet( class_def_hash, pcrud, "permacrud" );
271 xmlNodePtr _l = _cur->children;
274 if (strcmp( (char*)_l->name, "actions" )) {
279 xmlNodePtr _a = _l->children;
282 const char* action_name = (const char*) _a->name;
284 strcmp( action_name, "create" ) &&
285 strcmp( action_name, "retrieve" ) &&
286 strcmp( action_name, "update" ) &&
287 strcmp( action_name, "delete" )
293 osrfLogDebug(OSRF_LOG_MARK, "Found Permacrud action %s for class %s",
294 action_name, current_class_name );
296 osrfHash* action_def_hash = osrfNewHash();
297 osrfHashSet( pcrud, action_def_hash, action_name );
299 // Tokenize permission attribute into an osrfStringArray
300 prop_str = (char*) xmlGetProp(_a, BAD_CAST "permission");
302 osrfLogDebug(OSRF_LOG_MARK,
303 "Permacrud permission list is %s", prop_str );
304 osrfStringArray* map = osrfStringArrayTokenize( prop_str, ' ' );
305 osrfHashSet( action_def_hash, map, "permission");
307 osrfHashSet( action_def_hash,
308 (char*)xmlGetNoNsProp(_a, BAD_CAST "global_required"), "global_required");
310 // Tokenize context_field attribute into an osrfStringArray
311 prop_str = (char*) xmlGetProp(_a, BAD_CAST "context_field");
313 osrfLogDebug(OSRF_LOG_MARK,
314 "Permacrud context_field list is %s", prop_str );
315 map = osrfStringArrayTokenize( prop_str, ' ' );
316 osrfHashSet( action_def_hash, map, "local_context");
318 osrfHash* foreign_context = osrfNewHash();
319 osrfHashSet( action_def_hash, foreign_context, "foreign_context");
321 xmlNodePtr _f = _a->children;
324 if ( strcmp( (char*)_f->name, "context" ) ) {
329 if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "link")) ) {
330 osrfLogDebug(OSRF_LOG_MARK,
331 "Permacrud context link definition is %s", prop_str );
333 osrfHash* _tmp_fcontext = osrfNewHash();
335 // Store pointers to elements already stored
336 // from the <link> aggregate
337 osrfHash* _flink = osrfHashGet( current_links_hash, prop_str );
338 osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "field"), "fkey" );
339 osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "key"), "field" );
341 if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "jump")) )
342 osrfHashSet( _tmp_fcontext, osrfStringArrayTokenize( prop_str, '.' ), "jump" );
344 // Tokenize field attribute into an osrfStringArray
345 const char * field_list = (char*) xmlGetProp(_f, BAD_CAST "field");
347 osrfLogDebug(OSRF_LOG_MARK,
348 "Permacrud foreign context field list is %s", field_list );
349 map = osrfStringArrayTokenize( field_list, ' ' );
350 osrfHashSet( _tmp_fcontext, map, "context");
352 // Insert the new hash into a hash attached to the parent node
353 osrfHashSet( foreign_context, _tmp_fcontext, osrfHashGet( _flink, "class" ) );
357 if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "field") )) {
358 char* map_list = strdup( prop_str );
359 osrfLogDebug(OSRF_LOG_MARK,
360 "Permacrud local context field list is %s", prop_str );
362 if (strlen( map_list ) > 0) {
364 char* _map_class = strtok_r(map_list, " ", &st_tmp);
366 osrfHashGet( action_def_hash, "local_context"), _map_class);
368 while ((_map_class = strtok_r(NULL, " ", &st_tmp))) {
370 osrfHashGet( action_def_hash, "local_context"), _map_class);
385 if (!strcmp( (char*)_cur->name, "source_definition" )) {
386 const char* content_str;
387 if( (content_str = (char*)xmlNodeGetContent(_cur)) ) {
388 osrfLogDebug(OSRF_LOG_MARK, "Using source definition '%s' for class %s",
389 content_str, current_class_name );
392 strdup( content_str ),
406 osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
411 osrfHash* oilsIDLFindPath( const char* path, ... ) {
412 if(!path || strlen(path) < 1) return NULL;
414 osrfHash* obj = idlHash;
416 VA_LIST_TO_STRING(path);
423 token = strtok_r(t, "/", &tt);
424 if(!token) return NULL;
427 obj = osrfHashGet(obj, token);
428 } while( (token = strtok_r(NULL, "/", &tt)) && obj);
433 static osrfHash* findClassDef( const char* classname ) {
434 if( !classname || !idlHash )
437 return osrfHashGet( idlHash, classname );
440 int oilsIDL_classIsFieldmapper ( const char* classname ) {
441 if( findClassDef( classname ) )
447 int oilsIDL_ntop (const char* classname, const char* fieldname) {
448 osrfHash* class_def_hash = findClassDef( classname );
449 if( !class_def_hash )
450 return -1; // No such class
452 osrfHash* fields_hash = osrfHashGet( class_def_hash, "fields" );
454 return -1; // No list of fields fo the class
456 osrfHash* field_def_hash = osrfHashGet( fields_hash, fieldname );
457 if( !field_def_hash )
458 return -1; // No such field
460 const char* pos_attr = osrfHashGet( field_def_hash, "array_position" );
462 return -1; // No array_position attribute
464 return atoi( pos_attr ); // Return position as int
467 char * oilsIDL_pton (const char* classname, int pos) {
468 osrfHash* class_def_hash = findClassDef( classname );
469 if( !class_def_hash )
470 return NULL; // No such class
472 osrfHash* fields_hash = osrfHashGet( class_def_hash, "fields" );
474 return NULL; // No list of fields fo the class
477 osrfHash* field_def_hash = NULL;
478 osrfHashIterator* iter = osrfNewHashIterator( fields_hash );
480 while ( ( field_def_hash = osrfHashIteratorNext( iter ) ) ) {
481 if ( atoi( osrfHashGet( field_def_hash, "array_position" ) ) == pos ) {
482 ret = strdup( osrfHashIteratorKey( iter ) );
487 osrfHashIteratorFree( iter );