]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_idl-core.c
1. Eliminated several strdups that were leaking memory,
[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* string_tmp = NULL;
32
33         idlHash = osrfNewHash();
34         osrfHash* usrData = 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                         usrData = osrfNewHash();
52                         osrfHashSet( usrData, xmlGetProp(kid, BAD_CAST "id"), "classname");
53                         osrfHashSet( usrData, xmlGetNsProp(kid, BAD_CAST "fieldmapper", BAD_CAST OBJECT_NS), "fieldmapper");
54                         osrfHashSet( usrData, xmlGetNsProp(kid, BAD_CAST "readonly", BAD_CAST PERSIST_NS), "readonly");
55
56                         osrfHashSet( idlHash, usrData, (char*)osrfHashGet(usrData, "classname") );
57
58                         string_tmp = NULL;
59                         if ((string_tmp = (char*)xmlGetNsProp(kid, BAD_CAST "tablename", BAD_CAST PERSIST_NS))) {
60                                 osrfLogDebug(OSRF_LOG_MARK, "Using table '%s' for class %s", string_tmp, osrfHashGet(usrData, "classname") );
61                                 osrfHashSet(
62                                         usrData,
63                                         strdup( string_tmp ),
64                                         "tablename"
65                                 );
66                         }
67
68                         string_tmp = NULL;
69                         if ((string_tmp = (char*)xmlGetNsProp(kid, BAD_CAST "virtual", BAD_CAST PERSIST_NS))) {
70                                 osrfHashSet(
71                                         usrData,
72                                         strdup( string_tmp ),
73                                         "virtual"
74                                 );
75                         }
76
77                         // Tokenize controller attribute into an osrfStringArray
78                         string_tmp = (char*) xmlGetProp(kid, BAD_CAST "controller");
79                         if( string_tmp )
80                                 osrfLogDebug(OSRF_LOG_MARK, "Controller list is %s", string_tmp );
81                         osrfStringArray* controller = osrfStringArrayTokenize( string_tmp, ' ' );
82                         osrfHashSet( usrData, controller, "controller");
83
84                         osrfHash* _tmp;
85                         osrfHash* links = osrfNewHash();
86                         osrfHash* fields = osrfNewHash();
87                         osrfHash* pcrud = osrfNewHash();
88
89                         osrfHashSet( usrData, fields, "fields" );
90                         osrfHashSet( usrData, links, "links" );
91
92                         xmlNodePtr _cur = kid->children;
93
94                         while (_cur) {
95
96                                 if (!strcmp( (char*)_cur->name, "fields" )) {
97
98                                         string_tmp = NULL;
99                                         if( (string_tmp = (char*)xmlGetNsProp(_cur, BAD_CAST "primary", BAD_CAST PERSIST_NS)) ) {
100                                                 osrfHashSet(
101                                                         usrData,
102                                                         strdup( string_tmp ),
103                                                         "primarykey"
104                                                 );
105                                         }
106
107                                         string_tmp = NULL;
108                                         if( (string_tmp = (char*)xmlGetNsProp(_cur, BAD_CAST "sequence", BAD_CAST PERSIST_NS)) ) {
109                                                 osrfHashSet(
110                                                         usrData,
111                                                         strdup( string_tmp ),
112                                                         "sequence"
113                                                 );
114                                         }
115
116                                         xmlNodePtr _f = _cur->children;
117
118                                         while(_f) {
119                                                 if (strcmp( (char*)_f->name, "field" )) {
120                                                         _f = _f->next;
121                                                         continue;
122                                                 }
123
124                                                 _tmp = osrfNewHash();
125
126                                                 string_tmp = NULL;
127                                                 if( (string_tmp = (char*)xmlGetNsProp(_f, BAD_CAST "array_position", BAD_CAST OBJECT_NS)) ) {
128                                                         osrfHashSet(
129                                                                 _tmp,
130                                                                 strdup( string_tmp ),
131                                                                 "array_position"
132                                                         );
133                                                 }
134
135                                                 string_tmp = NULL;
136                                                 if( (string_tmp = (char*)xmlGetNsProp(_f, BAD_CAST "i18n", BAD_CAST PERSIST_NS)) ) {
137                                                         osrfHashSet(
138                                                                 _tmp,
139                                                                 strdup( string_tmp ),
140                                                                 "i18n"
141                                                         );
142                                                 }
143
144                                                 string_tmp = NULL;
145                                                 if( (string_tmp = (char*)xmlGetNsProp(_f, BAD_CAST "virtual", BAD_CAST PERSIST_NS)) ) {
146                                                         osrfHashSet(
147                                                                 _tmp,
148                                                                 strdup( string_tmp ),
149                                                                 "virtual"
150                                                         );
151                                                 }
152
153                                                 string_tmp = NULL;
154                                                 if( (string_tmp = (char*)xmlGetNsProp(_f, BAD_CAST "primitive", BAD_CAST PERSIST_NS)) ) {
155                                                         osrfHashSet(
156                                                                 _tmp,
157                                                                 strdup( string_tmp ),
158                                                                 "primitive"
159                                                         );
160                                                 }
161
162                                                 string_tmp = NULL;
163                                                 if( (string_tmp = (char*)xmlGetProp(_f, BAD_CAST "name")) ) {
164                                                         osrfHashSet(
165                                                                 _tmp,
166                                                                 strdup( string_tmp ),
167                                                                 "name"
168                                                         );
169                                                 }
170
171                                                 osrfLogDebug(OSRF_LOG_MARK, "Found field %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
172
173                                                 osrfHashSet(
174                                                         fields,
175                                                         _tmp,
176                                                         strdup( string_tmp )
177                                                 );
178                                                 _f = _f->next;
179                                         }
180                                 }
181
182                                 if (!strcmp( (char*)_cur->name, "links" )) {
183                                         xmlNodePtr _l = _cur->children;
184
185                                         while(_l) {
186                                                 if (strcmp( (char*)_l->name, "link" )) {
187                                                         _l = _l->next;
188                                                         continue;
189                                                 }
190
191                                                 _tmp = osrfNewHash();
192
193                                                 string_tmp = NULL;
194                                                 if( (string_tmp = (char*)xmlGetProp(_l, BAD_CAST "reltype")) ) {
195                                                         osrfHashSet(
196                                                                 _tmp,
197                                                                 strdup( string_tmp ),
198                                                                 "reltype"
199                                                         );
200                                                 }
201                                                 osrfLogDebug(OSRF_LOG_MARK, "Adding link with reltype %s", string_tmp );
202
203                                                 string_tmp = NULL;
204                                                 if( (string_tmp = (char*)xmlGetProp(_l, BAD_CAST "key")) ) {
205                                                         osrfHashSet(
206                                                                 _tmp,
207                                                                 strdup( string_tmp ),
208                                                                 "key"
209                                                         );
210                                                 }
211                                                 osrfLogDebug(OSRF_LOG_MARK, "Link fkey is %s", string_tmp );
212
213                                                 string_tmp = NULL;
214                                                 if( (string_tmp = (char*)xmlGetProp(_l, BAD_CAST "class")) ) {
215                                                         osrfHashSet(
216                                                                 _tmp,
217                                                                 strdup( string_tmp ),
218                                                                 "class"
219                                                         );
220                                                 }
221                                                 osrfLogDebug(OSRF_LOG_MARK, "Link fclass is %s", string_tmp );
222
223                                                 // Tokenize map attribute into an osrfStringArray
224                                                 string_tmp = (char*) xmlGetProp(_l, BAD_CAST "map");
225                                                 if( string_tmp )
226                                                         osrfLogDebug(OSRF_LOG_MARK, "Link mapping list is %s", string_tmp );
227                                                 osrfStringArray* map = osrfStringArrayTokenize( string_tmp, ' ' );
228                                                 osrfHashSet( _tmp, map, "map");
229
230                                                 string_tmp = NULL;
231                                                 if( (string_tmp = (char*)xmlGetProp(_l, BAD_CAST "field")) ) {
232                                                         osrfHashSet(
233                                                                 _tmp,
234                                                                 strdup( string_tmp ),
235                                                                 "field"
236                                                         );
237                                                 }
238
239                                                 osrfHashSet(
240                                                         links,
241                                                         _tmp,
242                                                         strdup( string_tmp )
243                                                 );
244
245                                                 osrfLogDebug(OSRF_LOG_MARK, "Found link %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
246
247                                                 _l = _l->next;
248                                         }
249                                 }
250 /**** Structure of permacrud in memory ****
251
252 { create :
253     { permission : [ x, y, z ],
254       global_required : "true", -- anything else, or missing, is false
255       local_context : [ f1, f2 ],
256       foreign_context : { class1 : { fkey : local_class_key, field : class1_field, context : [ a, b, c ] }, ...}
257     },
258   retrieve : null, -- no perm check, or structure similar to the others
259   update : -- like create
260     ...
261   delete : -- like create
262     ...
263 }   
264
265 **** Structure of permacrud in memory ****/
266
267                                 if (!strcmp( (char*)_cur->name, "permacrud" )) {
268                                         osrfHashSet( usrData, pcrud, "permacrud" );
269                                         xmlNodePtr _l = _cur->children;
270
271                                         while(_l) {
272                                                 if (strcmp( (char*)_l->name, "actions" )) {
273                                                         _l = _l->next;
274                                                         continue;
275                                                 }
276
277                                                 xmlNodePtr _a = _l->children;
278
279                                                 while(_a) {
280                                                         if (
281                                                                 strcmp( (char*)_a->name, "create" ) &&
282                                                                 strcmp( (char*)_a->name, "retrieve" ) &&
283                                                                 strcmp( (char*)_a->name, "update" ) &&
284                                                                 strcmp( (char*)_a->name, "delete" )
285                                                         ) {
286                                                                 _a = _a->next;
287                                                                 continue;
288                                                         }
289
290                                                         string_tmp = (char*) _a->name;
291                                                         osrfLogDebug(OSRF_LOG_MARK, "Found Permacrud action %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
292
293                                                         _tmp = osrfNewHash();
294                                                         osrfHashSet( pcrud, _tmp, string_tmp );
295
296                                                         // Tokenize permission attribute into an osrfStringArray
297                                                         string_tmp = (char*) xmlGetProp(_a, BAD_CAST "permission");
298                                                         if( string_tmp )
299                                                                 osrfLogDebug(OSRF_LOG_MARK,
300                                                                         "Permacrud permission list is %s", string_tmp );
301                                                         osrfStringArray* map = osrfStringArrayTokenize( string_tmp, ' ' );
302                                                         osrfHashSet( _tmp, map, "permission");
303
304                                                 osrfHashSet( _tmp, (char*)xmlGetNoNsProp(_a, BAD_CAST "global_required"), "global_required");
305
306                                                         // Tokenize context_field attribute into an osrfStringArray
307                                                         string_tmp = (char*) xmlGetProp(_a, BAD_CAST "context_field");
308                                                         if( string_tmp )
309                                                                 osrfLogDebug(OSRF_LOG_MARK,
310                                                                         "Permacrud context_field list is %s", string_tmp );
311                                                         map = osrfStringArrayTokenize( string_tmp, ' ' );
312                                                         osrfHashSet( _tmp, map, "local_context");
313
314                                                         osrfHash* foreign_context = osrfNewHash();
315                                                         osrfHashSet( _tmp, foreign_context, "foreign_context");
316
317                                                         xmlNodePtr _f = _a->children;
318
319                                                         while(_f) {
320                                                                 if ( strcmp( (char*)_f->name, "context" ) ) {
321                                                                         _f = _f->next;
322                                                                         continue;
323                                                                 }
324
325                                                                 string_tmp = NULL;
326                                                                 if( (string_tmp = (char*)xmlGetNoNsProp(_f, BAD_CAST "link")) ) {
327                                                                         osrfLogDebug(OSRF_LOG_MARK, "Permacrud context link definition is %s", string_tmp );
328
329                                                                         osrfHash* _flink = oilsIDLFindPath("/%s/links/%s", osrfHashGet(usrData, "classname"), string_tmp);
330
331                                                                         osrfHashSet( foreign_context, osrfNewHash(), osrfHashGet(_flink, "class") );
332                                                                         osrfHash* _tmp_fcontext = osrfHashGet( foreign_context, osrfHashGet(_flink, "class") );
333
334                                                                         osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "field"), "fkey" );
335                                                                         osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "key"), "field" );
336
337                                                                         // Tokenize field attribute into an osrfStringArray
338                                                                         string_tmp = (char*) xmlGetProp(_f, BAD_CAST "field");
339                                                                         if( string_tmp )
340                                                                                 osrfLogDebug(OSRF_LOG_MARK,
341                                                                                         "Permacrud foreign context field list is %s", string_tmp );
342                                                                         map = osrfStringArrayTokenize( string_tmp, ' ' );
343                                                                         osrfHashSet( _tmp_fcontext, map, "context");
344
345                                                                 } else {
346
347                                                                         if( (string_tmp = (char*)xmlGetNoNsProp(_f, BAD_CAST "field") )) {
348                                                                                 char* map_list = strdup( string_tmp );
349                                                                                 osrfLogDebug(OSRF_LOG_MARK, "Permacrud foreign context field list is %s", string_tmp );
350                         
351                                                                                 if (strlen( map_list ) > 0) {
352                                                                                         char* st_tmp = NULL;
353                                                                                         char* _map_class = strtok_r(map_list, " ", &st_tmp);
354                                                                                         osrfStringArrayAdd(osrfHashGet( _tmp, "local_context"), _map_class);
355                                                                         
356                                                                                         while ((_map_class = strtok_r(NULL, " ", &st_tmp))) {
357                                                                                                 osrfStringArrayAdd(osrfHashGet( _tmp, "local_context"), _map_class);
358                                                                                         }
359                                                                                 }
360                                                                                 free(map_list);
361                                                                         }
362
363                                                                 }
364                                                                 _f = _f->next;
365                                                         }
366                                                         _a = _a->next;
367                                                 }
368                                                 _l = _l->next;
369                                         }
370                                 }
371
372                                 if (!strcmp( (char*)_cur->name, "source_definition" )) {
373                                         string_tmp = NULL;
374                                         if( (string_tmp = (char*)xmlNodeGetContent(_cur)) ) {
375                                                 osrfLogDebug(OSRF_LOG_MARK, "Using source definition '%s' for class %s", string_tmp, osrfHashGet(usrData, "classname") );
376                                                 osrfHashSet(
377                                                         usrData,
378                                                         strdup( string_tmp ),
379                                                         "source_definition"
380                                                 );
381                                         }
382
383                                 }
384
385                                 _cur = _cur->next;
386                         } // end while
387                 }
388
389                 kid = kid->next;
390         } // end while
391
392         osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
393
394         return idlHash;
395 }
396
397 osrfHash* oilsIDLFindPath( const char* path, ... ) {
398         if(!path || strlen(path) < 1) return NULL;
399
400         osrfHash* obj = idlHash;
401
402         VA_LIST_TO_STRING(path);
403         char* buf = VA_BUF;
404
405         char* token = NULL;
406         char* t = buf;
407         char* tt;
408
409         token = strtok_r(t, "/", &tt);
410         if(!token) return NULL;
411
412         do {
413                 obj = osrfHashGet(obj, token);
414         } while( (token = strtok_r(NULL, "/", &tt)) && obj);
415
416         return obj;
417 }
418
419 int oilsIDL_classIsFieldmapper ( const char* classname ) {
420         if (!classname) return 0;
421         if(oilsIDLFindPath( "/%s", classname )) return 1;
422         return 0;
423 }
424
425 int oilsIDL_ntop (const char* classname, const char* fieldname) {
426         osrfHash* _pos = NULL;
427
428         if (!oilsIDL_classIsFieldmapper(classname)) return -1;
429         _pos = oilsIDLFindPath( "/%s/fields/%s", classname, fieldname );
430         if (_pos) return atoi( osrfHashGet(_pos, "array_position") );
431         return -1;
432 }
433
434 char * oilsIDL_pton (const char* classname, int pos) {
435         char* ret = NULL;
436         osrfHash* f = NULL;
437         osrfHash* fields = NULL;
438         osrfHashIterator* itr = NULL;
439
440         if (!oilsIDL_classIsFieldmapper(classname)) return NULL;
441
442         fields = oilsIDLFindPath( "/%s/fields", classname );
443         itr = osrfNewHashIterator( fields );
444
445         while ( (f = osrfHashIteratorNext( itr )) ) {
446                 if ( atoi(osrfHashGet(f, "array_position")) == pos ) {
447                         ret = strdup(osrfHashIteratorKey(itr));
448                         break;
449                 }
450         }
451
452         osrfHashIteratorFree( itr );
453
454         return ret;
455 }
456