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"
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>
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"
26 int osrfAppChildInit();
27 int osrfAppInitialize();
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);
36 dbi_conn dbhandle; /* our db connection */
37 xmlDocPtr idlDoc = NULL; // parse and store the IDL here
39 /* handy NULL json object to have around */
40 static jsonObject* oilsNULL = NULL;
42 int osrfAppInitialize() {
43 osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server...");
44 osrfLogInfo(OSRF_LOG_MARK, "Finding XML file...");
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);
50 osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML...");
51 idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE );
54 osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!");
58 osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
60 osrfStringArray* global_methods = osrfNewStringArray(1);
62 //osrfStringArrayAdd( global_methods, "create" );
63 osrfStringArrayAdd( global_methods, "retrieve" );
64 //osrfStringArrayAdd( global_methods, "update" );
65 //osrfStringArrayAdd( global_methods, "delete" );
67 xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc);
68 xmlNodePtr kid = docRoot->children;
70 if (!strcmp( (char*)kid->name, "class" )) {
73 while ( (method_type = osrfStringArrayGetString(global_methods, i)) ) {
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");
80 osrfLogInfo(OSRF_LOG_MARK, "Generating class methods for %s", osrfHashGet(usrData, "fieldmapper") );
83 osrfHash* links = osrfNewHash();
84 osrfHash* fields = osrfNewHash();
86 osrfHashSet( usrData, fields, "fields" );
87 osrfHashSet( usrData, links, "links" );
89 xmlNodePtr _cur = kid->children;
92 char* string_tmp = NULL;
94 if (!strcmp( (char*)_cur->name, "fields" )) {
96 if( (string_tmp = (char*)xmlGetNsProp(_cur, "primary", PERSIST_NS)) ) {
105 xmlNodePtr _f = _cur->children;
108 if (strcmp( (char*)_f->name, "field" )) {
113 _tmp = osrfNewHash();
115 if( (string_tmp = (char*)xmlGetNsProp(_f, "array_position", OBJECT_NS)) ) {
118 strdup( string_tmp ),
124 if( (string_tmp = (char*)xmlGetNsProp(_f, "virtual", PERSIST_NS)) ) {
127 strdup( string_tmp ),
133 if( (string_tmp = (char*)xmlGetProp(_f, "name")) ) {
136 strdup( string_tmp ),
141 osrfLogInfo(OSRF_LOG_MARK, "Found field %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
152 if (!strcmp( (char*)_cur->name, "links" )) {
153 xmlNodePtr _l = _cur->children;
156 if (strcmp( (char*)_l->name, "link" )) {
161 _tmp = osrfNewHash();
163 if( (string_tmp = (char*)xmlGetProp(_l, "reltype")) ) {
166 strdup( string_tmp ),
170 osrfLogInfo(OSRF_LOG_MARK, "Adding link with reltype %s", string_tmp );
173 if( (string_tmp = (char*)xmlGetProp(_l, "key")) ) {
176 strdup( string_tmp ),
180 osrfLogInfo(OSRF_LOG_MARK, "Link fkey is %s", string_tmp );
183 if( (string_tmp = (char*)xmlGetProp(_l, "class")) ) {
186 strdup( string_tmp ),
190 osrfLogInfo(OSRF_LOG_MARK, "Link fclass is %s", string_tmp );
193 osrfStringArray* map = osrfNewStringArray(0);
195 if( (string_tmp = (char*)xmlGetProp(_l, "map") )) {
196 char* map_list = strdup( string_tmp );
197 osrfLogInfo(OSRF_LOG_MARK, "Link mapping list is %s", string_tmp );
199 if (strlen( map_list ) > 0) {
201 char* _map_class = strtok_r(map_list, " ", &st_tmp);
202 osrfStringArrayAdd(map, strdup(_map_class));
204 while ((_map_class = strtok_r(NULL, " ", &st_tmp))) {
205 osrfStringArrayAdd(map, strdup(_map_class));
209 osrfHashSet( _tmp, map, "map");
211 if( (string_tmp = (char*)xmlGetProp(_l, "field")) ) {
214 strdup( string_tmp ),
225 osrfLogInfo(OSRF_LOG_MARK, "Found link %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
237 if (!osrfHashGet(usrData, "fieldmapper")) continue;
239 _fm = strdup( (char*)osrfHashGet(usrData, "fieldmapper") );
240 char* part = strtok_r(_fm, ":", &st_tmp);
242 growing_buffer* method_name = buffer_init(64);
243 buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part);
245 while ((part = strtok_r(NULL, ":", &st_tmp))) {
246 buffer_fadd(method_name, ".%s", part);
248 buffer_fadd(method_name, ".%s", method_type);
250 char* method = buffer_data(method_name);
251 buffer_free(method_name);
253 osrfHashSet( usrData, method, "methodname" );
254 osrfHashSet( usrData, strdup(method_type), "methodtype" );
256 osrfAppRegisterExtendedMethod(
259 "dispatchCRUDMethod",
276 * Connects to the database
278 int osrfAppChildInit() {
280 osrfLogDebug(OSRF_LOG_MARK, "Attempting to initialize libdbi...");
281 dbi_initialize(NULL);
282 osrfLogDebug(OSRF_LOG_MARK, "... libdbi initialized.");
284 char* driver = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
285 char* user = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
286 char* host = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
287 char* port = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
288 char* db = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
289 char* pw = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
291 osrfLogDebug(OSRF_LOG_MARK, "Attempting to load the database driver [%s]...", driver);
292 dbhandle = dbi_conn_new(driver);
295 osrfLogError(OSRF_LOG_MARK, "Error loading database driver [%s]", driver);
298 osrfLogDebug(OSRF_LOG_MARK, "Database driver [%s] seems OK", driver);
300 osrfLogInfo(OSRF_LOG_MARK, "%s connecting to database. host=%s, "
301 "port=%s, user=%s, pw=%s, db=%s", MODULENAME, host, port, user, pw, db );
303 if(host) dbi_conn_set_option(dbhandle, "host", host );
304 if(port) dbi_conn_set_option_numeric( dbhandle, "port", atoi(port) );
305 if(user) dbi_conn_set_option(dbhandle, "username", user);
306 if(pw) dbi_conn_set_option(dbhandle, "password", pw );
307 if(db) dbi_conn_set_option(dbhandle, "dbname", db );
316 if (dbi_conn_connect(dbhandle) < 0) {
317 dbi_conn_error(dbhandle, &err);
318 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
322 osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
328 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
329 OSRF_METHOD_VERIFY_CONTEXT(ctx);
331 osrfHash* meta = (osrfHash*) ctx->method->userData;
333 jsonObject * obj = NULL;
334 if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create"))
335 obj = doCreate(meta, ctx->params);
337 if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve"))
338 obj = doRetrieve(meta, ctx->params);
340 if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update"))
341 obj = doUpdate(meta, ctx->params);
343 if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete"))
344 obj = doDelete(meta, ctx->params);
346 osrfAppRespondComplete( ctx, obj );
353 jsonObject* doCreate( osrfHash* meta, jsonObject* params ) { return NULL; }
355 jsonObject* doRetrieve( osrfHash* meta, jsonObject* params ) {
357 char* id = jsonObjectToSimpleString(jsonObjectGetIndex(params, 0));
361 "%s retrieving %s object with id %s",
363 osrfHashGet(meta, "fieldmapper"),
369 growing_buffer* sql_buf = buffer_init(128);
372 "SELECT * FROM %s WHERE %s = %d;",
373 osrfHashGet(meta, "tablename"),
374 osrfHashGet(meta, "primarykey"),
378 char* sql = buffer_data(sql_buf);
379 buffer_free(sql_buf);
381 osrfLogDebug(OSRF_LOG_MARK, "%s SQL = %s", MODULENAME, sql);
383 dbi_result result = dbi_conn_query(dbhandle, sql);
385 jsonObject* obj = NULL;
388 /* there should be one row at the most */
389 if (!dbi_result_first_row(result)) {
390 osrfLogDebug(OSRF_LOG_MARK, "%s: Error retrieving %s with key %s", MODULENAME, osrfHashGet(meta, "fieldmapper"), id);
391 dbi_result_free(result);
395 /* JSONify the result */
396 obj = oilsMakeJSONFromResult( result, meta );
398 /* clean up the query */
399 dbi_result_free(result);
402 osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
411 jsonObject* doUpdate( osrfHash* meta, jsonObject* params ) { return NULL; }
413 jsonObject* doDelete( osrfHash* meta, jsonObject* params ) { return NULL; }
416 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
417 if(!(result && meta)) return NULL;
419 jsonObject* object = jsonParseString("[]");
420 jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
422 osrfHash* fields = osrfHashGet(meta, "fields");
424 osrfLogDebug(OSRF_LOG_MARK, "Setting object class to %s ", object->classname);
431 const char* columnName;
433 /* cycle through the column list */
434 while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
436 osrfLogDebug(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
438 fmIndex = -1; // reset the position
440 /* determine the field type and storage attributes */
441 type = dbi_result_get_field_type(result, columnName);
442 attr = dbi_result_get_field_attribs(result, columnName);
444 /* fetch the fieldmapper index */
445 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
446 char* virt = (char*)osrfHashGet(_f, "virtual");
447 char* pos = (char*)osrfHashGet(_f, "array_position");
449 if ( !virt || !pos || !(strcmp( virt, "true" )) ) continue;
451 fmIndex = atoi( pos );
452 osrfLogDebug(OSRF_LOG_MARK, "... Found column at position [%s]...", pos);
457 case DBI_TYPE_INTEGER :
459 if( attr & DBI_INTEGER_SIZE8 )
460 jsonObjectSetIndex( object, fmIndex,
461 jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
463 jsonObjectSetIndex( object, fmIndex,
464 jsonNewNumberObject(dbi_result_get_long(result, columnName)));
468 case DBI_TYPE_DECIMAL :
469 jsonObjectSetIndex( object, fmIndex,
470 jsonNewNumberObject(dbi_result_get_double(result, columnName)));
473 case DBI_TYPE_STRING :
474 jsonObjectSetIndex( object, fmIndex,
475 jsonNewObject(dbi_result_get_string(result, columnName)));
478 case DBI_TYPE_DATETIME :
479 jsonObjectSetIndex( object, fmIndex,
480 jsonNewNumberObject(dbi_result_get_datetime(result, columnName)));
483 case DBI_TYPE_BINARY :
484 osrfLogError( OSRF_LOG_MARK,
485 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);