]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_cstore.c
debuging
[Evergreen.git] / Open-ILS / src / c-apps / oils_cstore.c
1 #include "opensrf/osrf_application.h"
2 #include "opensrf/osrf_settings.h"
3 #include "opensrf/utils.h"
4 #include "objson/object.h"
5 #include "opensrf/log.h"
6 #include "oils_utils.h"
7 #include "oils_constants.h"
8 #include "oils_event.h"
9 #include <dbi/dbi.h>
10
11 #include <string.h>
12 #include <libxml/globals.h>
13 #include <libxml/xmlerror.h>
14 #include <libxml/parser.h>
15 #include <libxml/tree.h>
16 #include <libxml/debugXML.h>
17 #include <libxml/xmlmemory.h>
18 //#include <openils/fieldmapper_lookup.h>
19
20 #define OILS_AUTH_CACHE_PRFX "oils_cstore_"
21 #define MODULENAME "open-ils.cstore"
22 #define PERSIST_NS "http://open-ils.org/spec/opensrf/IDL/persistance/v1"
23 #define OBJECT_NS "http://open-ils.org/spec/opensrf/IDL/objects/v1"
24 #define BASE_NS "http://opensrf.org/spec/IDL/base/v1"
25
26 int osrfAppChildInit();
27 int osrfAppInitialize();
28
29 int dispatchCRUDMethod ( osrfMethodContext* ctx );
30 jsonObject* doCreate ( osrfHash* metadata, jsonObject* params );
31 jsonObject* doRetrieve ( osrfHash* metadata, jsonObject* params );
32 jsonObject* doUpdate ( osrfHash* metadata, jsonObject* params );
33 jsonObject* doDelete ( osrfHash* metadata, jsonObject* params );
34 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta);
35
36 dbi_conn dbhandle; /* our db connection */
37 xmlDocPtr idlDoc = NULL; // parse and store the IDL here
38
39 /* handy NULL json object to have around */
40 static jsonObject* oilsNULL = NULL;
41
42 int osrfAppInitialize() {
43         osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server...");
44         osrfLogInfo(OSRF_LOG_MARK, "Finding XML file...");
45
46         char * idl_filename = osrf_settings_host_value("/apps/%s/app_settings/IDL", MODULENAME);
47         osrfLogInfo(OSRF_LOG_MARK, "Found file:");
48         osrfLogInfo(OSRF_LOG_MARK, idl_filename);
49
50         osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML...");
51         idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE );
52         
53         if (!idlDoc) {
54                 osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!");
55                 exit(1);
56         }
57
58         osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
59
60         osrfStringArray* global_methods = osrfNewStringArray(1);
61
62         //osrfStringArrayAdd( global_methods, "create" );
63         osrfStringArrayAdd( global_methods, "retrieve" );
64         //osrfStringArrayAdd( global_methods, "update" );
65         //osrfStringArrayAdd( global_methods, "delete" );
66
67         xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc);
68         xmlNodePtr kid = docRoot->children;
69         while (kid) {
70                 if (!strcmp( (char*)kid->name, "class" )) {
71                         int i = 0; 
72                         char* method_type;
73                         while ( (method_type = osrfStringArrayGetString(global_methods, i)) ) {
74
75                                 osrfHash * usrData = osrfNewHash();
76                                 osrfHashSet( usrData, xmlGetProp(kid, "id"), "classname");
77                                 osrfHashSet( usrData, xmlGetNsProp(kid, "tablename", PERSIST_NS), "tablename");
78                                 osrfHashSet( usrData, xmlGetNsProp(kid, "fieldmapper", OBJECT_NS), "fieldmapper");
79
80                                 osrfLogInfo(OSRF_LOG_MARK, "Generating class methods for %s", osrfHashGet(usrData, "fieldmapper") );
81
82                                 osrfHash* _tmp;
83                                 osrfHash* links = osrfNewHash();
84                                 osrfHash* fields = osrfNewHash();
85                                 xmlNodePtr _cur = kid->children;
86
87                                 while (_cur) {
88                                         char* string_tmp = NULL;
89
90                                         if (!strcmp( (char*)_cur->name, "fields" )) {
91
92                                                 if( (string_tmp = (char*)xmlGetNsProp(_cur, "primary", PERSIST_NS)) ) {
93                                                         osrfHashSet(
94                                                                 usrData,
95                                                                 strdup( string_tmp ),
96                                                                 "primarykey"
97                                                         );
98                                                 }
99                                                 string_tmp = NULL;
100
101                                                 xmlNodePtr _f = _cur->children;
102
103                                                 while(_f) {
104                                                         if (strcmp( (char*)_f->name, "field" )) {
105                                                                 _f = _f->next;
106                                                                 continue;
107                                                         }
108
109                                                         _tmp = osrfNewHash();
110
111                                                         if( (string_tmp = (char*)xmlGetNsProp(_f, "array_position", OBJECT_NS)) ) {
112                                                                 osrfHashSet(
113                                                                         _tmp,
114                                                                         strdup( string_tmp ),
115                                                                         "array_position"
116                                                                 );
117                                                         }
118                                                         string_tmp = NULL;
119
120                                                         if( (string_tmp = (char*)xmlGetNsProp(_f, "virtual", PERSIST_NS)) ) {
121                                                                 osrfHashSet(
122                                                                         _tmp,
123                                                                         strdup( string_tmp ),
124                                                                         "virtual"
125                                                                 );
126                                                         }
127                                                         string_tmp = NULL;
128
129                                                         if( (string_tmp = (char*)xmlGetProp(_f, "name")) ) {
130                                                                 osrfHashSet(
131                                                                         _tmp,
132                                                                         strdup( string_tmp ),
133                                                                         "name"
134                                                                 );
135                                                         }
136
137                                                         osrfLogInfo(OSRF_LOG_MARK, "Found field %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
138
139                                                         osrfHashSet(
140                                                                 fields,
141                                                                 _tmp,
142                                                                 strdup( string_tmp )
143                                                         );
144                                                         _f = _f->next;
145                                                 }
146                                         }
147
148                                         if (!strcmp( (char*)_cur->name, "links" )) {
149                                                 xmlNodePtr _l = _cur->children;
150
151                                                 while(_l) {
152                                                         if (strcmp( (char*)_l->name, "link" )) {
153                                                                 _l = _l->next;
154                                                                 continue;
155                                                         }
156
157                                                         _tmp = osrfNewHash();
158
159                                                         if( (string_tmp = (char*)xmlGetProp(_l, "reltype")) ) {
160                                                                 osrfHashSet(
161                                                                         _tmp,
162                                                                         strdup( string_tmp ),
163                                                                         "reltype"
164                                                                 );
165                                                         }
166                                                         osrfLogInfo(OSRF_LOG_MARK, "Adding link with reltype %s", string_tmp );
167                                                         string_tmp = NULL;
168
169                                                         if( (string_tmp = (char*)xmlGetProp(_l, "key")) ) {
170                                                                 osrfHashSet(
171                                                                         _tmp,
172                                                                         strdup( string_tmp ),
173                                                                         "key"
174                                                                 );
175                                                         }
176                                                         osrfLogInfo(OSRF_LOG_MARK, "Link fkey is %s", string_tmp );
177                                                         string_tmp = NULL;
178
179                                                         if( (string_tmp = (char*)xmlGetProp(_l, "class")) ) {
180                                                                 osrfHashSet(
181                                                                         _tmp,
182                                                                         strdup( string_tmp ),
183                                                                         "class"
184                                                                 );
185                                                         }
186                                                         osrfLogInfo(OSRF_LOG_MARK, "Link fclass is %s", string_tmp );
187                                                         string_tmp = NULL;
188
189                                                         osrfStringArray* map = osrfNewStringArray(0);
190
191                                                         if( (string_tmp = (char*)xmlGetProp(_l, "map") )) {
192                                                                 char* map_list = strdup( string_tmp );
193                                                                 osrfLogInfo(OSRF_LOG_MARK, "Link mapping list is %s", string_tmp );
194
195                                                                 if (strlen( map_list ) > 0) {
196                                                                         char* st_tmp;
197                                                                         char* _map_class = strtok_r(map_list, " ", &st_tmp);
198                                                                         osrfStringArrayAdd(map, strdup(_map_class));
199                                                         
200                                                                         while ((_map_class = strtok_r(NULL, " ", &st_tmp))) {
201                                                                                 osrfStringArrayAdd(map, strdup(_map_class));
202                                                                         }
203                                                                 }
204                                                         }
205                                                         osrfHashSet( _tmp, map, "map");
206
207                                                         if( (string_tmp = (char*)xmlGetProp(_l, "field")) ) {
208                                                                 osrfHashSet(
209                                                                         _tmp,
210                                                                         strdup( string_tmp ),
211                                                                         "field"
212                                                                 );
213                                                         }
214
215                                                         osrfHashSet(
216                                                                 links,
217                                                                 _tmp,
218                                                                 strdup( string_tmp )
219                                                         );
220
221                                                         osrfLogInfo(OSRF_LOG_MARK, "Found link %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
222
223                                                         _l = _l->next;
224                                                 }
225                                         }
226
227                                         _cur = _cur->next;
228                                 }
229
230
231                                 char* st_tmp;
232                                 char* _fm;
233                                 if (!osrfHashGet(usrData, "fieldmapper")) continue;
234
235                                 _fm = strdup( (char*)osrfHashGet(usrData, "fieldmapper") );
236                                 char* part = strtok_r(_fm, ":", &st_tmp);
237
238                                 growing_buffer* method_name =  buffer_init(64);
239                                 buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part);
240
241                                 while ((part = strtok_r(NULL, ":", &st_tmp))) {
242                                         buffer_fadd(method_name, ".%s", part);
243                                 }
244                                 buffer_fadd(method_name, ".%s", method_type);
245
246                                 char* method = buffer_data(method_name);
247                                 buffer_free(method_name);
248
249                                 osrfHashSet( usrData, method, "methodname" );
250                                 osrfHashSet( usrData, strdup(method_type), "methodtype" );
251
252                                 osrfAppRegisterExtendedMethod(
253                                         MODULENAME,
254                                         method,
255                                         "dispatchCRUDMethod",
256                                         "",
257                                         1,
258                                         0,
259                                         (void*)usrData
260                                 );
261
262                                 i++;
263                         }
264                 }
265                 kid = kid->next;
266         }
267
268         return 0;
269 }
270
271 /**
272  * Connects to the database 
273  */
274 int osrfAppChildInit() {
275
276         osrfLogDebug(OSRF_LOG_MARK, "Attempting to initialize libdbi...");
277         dbi_initialize(NULL);
278         osrfLogDebug(OSRF_LOG_MARK, "... libdbi initialized.");
279
280         char* driver    = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
281         char* user      = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
282         char* host      = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
283         char* port      = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
284         char* db        = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
285         char* pw        = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
286
287         osrfLogDebug(OSRF_LOG_MARK, "Attempting to load the database driver [%s]...", driver);
288         dbhandle = dbi_conn_new(driver);
289
290         if(!dbhandle) {
291                 osrfLogError(OSRF_LOG_MARK, "Error loading database driver [%s]", driver);
292                 return -1;
293         }
294         osrfLogDebug(OSRF_LOG_MARK, "Database driver [%s] seems OK", driver);
295
296         osrfLogInfo(OSRF_LOG_MARK, "%s connecting to database.  host=%s, "
297                 "port=%s, user=%s, pw=%s, db=%s", MODULENAME, host, port, user, pw, db );
298
299         if(host) dbi_conn_set_option(dbhandle, "host", host );
300         if(port) dbi_conn_set_option_numeric( dbhandle, "port", atoi(port) );
301         if(user) dbi_conn_set_option(dbhandle, "username", user);
302         if(pw) dbi_conn_set_option(dbhandle, "password", pw );
303         if(db) dbi_conn_set_option(dbhandle, "dbname", db );
304
305         free(user);
306         free(host);
307         free(port);
308         free(db);
309         free(pw);
310
311         const char* err;
312         if (dbi_conn_connect(dbhandle) < 0) {
313                 dbi_conn_error(dbhandle, &err);
314                 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
315                 return -1;
316         }
317
318         osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
319
320         return 0;
321 }
322
323
324 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
325         OSRF_METHOD_VERIFY_CONTEXT(ctx);
326
327         osrfHash* meta = (osrfHash*) ctx->method->userData;
328
329         jsonObject * obj = NULL;
330         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create"))
331                 obj = doCreate(meta, ctx->params);
332
333         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve"))
334                 obj = doRetrieve(meta, ctx->params);
335
336         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update"))
337                 obj = doUpdate(meta, ctx->params);
338
339         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete"))
340                 obj = doDelete(meta, ctx->params);
341
342         osrfAppRespondComplete( ctx, obj );
343
344         jsonObjectFree(obj);
345
346         return 0;
347 }
348
349 jsonObject* doCreate( osrfHash* meta, jsonObject* params ) { return NULL; }
350
351 jsonObject* doRetrieve( osrfHash* meta, jsonObject* params ) {
352
353         char* id        = jsonObjectToSimpleString(jsonObjectGetIndex(params, 0));
354
355         osrfLogDebug(
356                 OSRF_LOG_MARK,
357                 "%s retrieving %s object with id %s",
358                 MODULENAME,
359                 osrfHashGet(meta, "fieldmapper"),
360                 id
361         );
362
363
364
365         growing_buffer* sql_buf = buffer_init(128);
366         buffer_fadd(
367                 sql_buf,
368                 "SELECT * FROM %s WHERE %s = %d;",
369                 osrfHashGet(meta, "tablename"),
370                 osrfHashGet(meta, "primarykey"),
371                 atoi(id)
372         );
373
374         char* sql = buffer_data(sql_buf);
375         buffer_free(sql_buf);
376         
377         osrfLogDebug(OSRF_LOG_MARK, "%s SQL =  %s", MODULENAME, sql);
378
379         dbi_result result = dbi_conn_query(dbhandle, sql);
380
381         jsonObject* obj = NULL;
382         if(result) {
383
384                 /* there should be one row at the most  */
385                 if (!dbi_result_first_row(result)) {
386                         osrfLogDebug(OSRF_LOG_MARK, "%s: Error retrieving %s with key %s", MODULENAME, osrfHashGet(meta, "fieldmapper"), id);
387                         dbi_result_free(result); 
388                         return oilsNULL;
389                 }
390
391                 /* JSONify the result */
392                 obj = oilsMakeJSONFromResult( result, meta );
393
394                 /* clean up the query */
395                 dbi_result_free(result); 
396
397         } else {
398                 osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
399         }
400
401         free(id);
402
403         return obj;
404 }
405
406
407 jsonObject* doUpdate( osrfHash* meta, jsonObject* params ) { return NULL; }
408
409 jsonObject* doDelete( osrfHash* meta, jsonObject* params ) { return NULL; }
410
411
412 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
413         if(!(result && meta)) return NULL;
414
415         jsonObject* object = jsonParseString("[]");
416         jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
417
418         osrfHash* fields = osrfHashGet(meta, "fields");
419
420         osrfLogDebug(OSRF_LOG_MARK, "Setting object class to %s ", object->classname);
421
422         osrfHash* _f;
423         int attr;
424         int fmIndex;
425         int columnIndex = 1;
426         unsigned short type;
427         const char* columnName;
428
429         /* cycle through the column list */
430         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
431
432                 osrfLogDebug(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
433
434                 fmIndex = -1; // reset the position
435                 
436                 /* determine the field type and storage attributes */
437                 type = dbi_result_get_field_type(result, columnName);
438                 attr = dbi_result_get_field_attribs(result, columnName);
439
440                 /* fetch the fieldmapper index */
441                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
442                         char* virt = (char*)osrfHashGet(_f, "virtual");
443                         char* pos = (char*)osrfHashGet(_f, "array_position");
444
445                         if ( !virt || !pos || !(strcmp( virt, "true" )) ) continue;
446
447                         fmIndex = atoi( pos );
448                         osrfLogDebug(OSRF_LOG_MARK, "... Found column at position [%s]...", pos);
449                 }
450
451                 switch( type ) {
452
453                         case DBI_TYPE_INTEGER :
454
455                                 if( attr & DBI_INTEGER_SIZE8 ) 
456                                         jsonObjectSetIndex( object, fmIndex, 
457                                                 jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
458                                 else 
459                                         jsonObjectSetIndex( object, fmIndex, 
460                                                 jsonNewNumberObject(dbi_result_get_long(result, columnName)));
461
462                                 break;
463
464                         case DBI_TYPE_DECIMAL :
465                                 jsonObjectSetIndex( object, fmIndex, 
466                                                 jsonNewNumberObject(dbi_result_get_double(result, columnName)));
467                                 break;
468
469                         case DBI_TYPE_STRING :
470                                 jsonObjectSetIndex( object, fmIndex, 
471                                         jsonNewObject(dbi_result_get_string(result, columnName)));
472                                 break;
473
474                         case DBI_TYPE_DATETIME :
475                                 jsonObjectSetIndex( object, fmIndex, 
476                                         jsonNewNumberObject(dbi_result_get_datetime(result, columnName)));
477                                 break;
478
479                         case DBI_TYPE_BINARY :
480                                 osrfLogError( OSRF_LOG_MARK, 
481                                         "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
482                 }
483         }
484
485         return object;
486 }
487
488
489
490