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"
23 int osrfAppChildInit();
24 int osrfAppInitialize();
26 int dispatchCRUDMethod ( osrfMethodContext* ctx );
27 jsonObject* doCreate ( osrfHash* metadata, jsonObject* params );
28 jsonObject* doRetrieve ( osrfHash* metadata, jsonObject* params );
29 jsonObject* doUpdate ( osrfHash* metadata, jsonObject* params );
30 jsonObject* doDelete ( osrfHash* metadata, jsonObject* params );
31 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta);
33 dbi_conn dbhandle; /* our db connection */
34 xmlDocPtr idlDoc = NULL; // parse and store the IDL here
36 /* handy NULL json object to have around */
37 static jsonObject* oilsNULL = NULL;
39 int osrfAppInitialize() {
40 osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server...");
41 osrfLogInfo(OSRF_LOG_MARK, "Finding XML file...");
43 char * idl_filename = osrf_settings_host_value("/apps/%s/app_settings/IDL", MODULENAME);
44 osrfLogInfo(OSRF_LOG_MARK, "Found file:");
45 osrfLogInfo(OSRF_LOG_MARK, idl_filename);
47 osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML...");
48 idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE );
51 osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!");
55 osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
57 osrfStringArray* global_methods = osrfNewStringArray(1);
59 //osrfStringArrayAdd( global_methods, "create" );
60 osrfStringArrayAdd( global_methods, "retrieve" );
61 //osrfStringArrayAdd( global_methods, "update" );
62 //osrfStringArrayAdd( global_methods, "delete" );
64 xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc);
65 xmlNodePtr kid = docRoot->children;
67 if (!strcmp( (char*)kid->name, "class" )) {
70 while ( (method_type = osrfStringArrayGetString(global_methods, i)) ) {
72 osrfHash * usrData = osrfNewHash();
73 osrfHashSet( usrData, xmlGetProp(kid, "id"), "classname");
74 osrfHashSet( usrData, xmlGetNsProp(kid, "tablename", "http://open-ils.org/spec/opensrf/IDL/persistance/v1"), "tablename");
75 osrfHashSet( usrData, xmlGetNsProp(kid, "fieldmapper", "http://open-ils.org/spec/opensrf/IDL/objects/v1"), "fieldmapper");
77 xmlNodePtr _cur = kid->children;
79 if (!strcmp( (char*)_cur->name, "fields" )) osrfHashSet( usrData, _cur, "fields");
80 if (!strcmp( (char*)_cur->name, "links" )) osrfHashSet( usrData, _cur, "links");
85 char* _fm = strdup( (char*)osrfHashGet(usrData, "fieldmapper") );
86 char* part = strtok(_fm, ":");
88 growing_buffer* method_name = buffer_init(64);
89 buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part);
91 while ((part = strtok(NULL, ":"))) {
92 buffer_fadd(method_name, ".%s", part);
94 buffer_fadd(method_name, ".%s", method_type);
96 char* method = buffer_data(method_name);
97 buffer_free(method_name);
99 osrfHashSet( usrData, method, "methodname" );
100 osrfHashSet( usrData, strdup(method_type), "methodtype" );
102 osrfAppRegisterExtendedMethod(
105 "dispatchCRUDMethod",
122 * Connects to the database
124 int osrfAppChildInit() {
126 dbi_initialize(NULL);
128 char* driver = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
129 char* user = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
130 char* host = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
131 char* port = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
132 char* db = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
133 char* pw = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
135 dbhandle = dbi_conn_new(driver);
138 osrfLogError(OSRF_LOG_MARK, "Error creating database driver %s", driver);
142 osrfLogInfo(OSRF_LOG_MARK, "oils_fetch connecting to database. host=%s, "
143 "port=%s, user=%s, pw=%s, db=%s", host, port, user, pw, db );
145 if(host) dbi_conn_set_option(dbhandle, "host", host );
146 if(port) dbi_conn_set_option_numeric( dbhandle, "port", atoi(port) );
147 if(user) dbi_conn_set_option(dbhandle, "username", user);
148 if(pw) dbi_conn_set_option(dbhandle, "password", pw );
149 if(db) dbi_conn_set_option(dbhandle, "dbname", db );
157 if (dbi_conn_connect(dbhandle) < 0) {
159 dbi_conn_error(dbhandle, &err);
160 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
164 osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
170 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
171 OSRF_METHOD_VERIFY_CONTEXT(ctx);
173 osrfHash* meta = (osrfHash*) ctx->method->userData;
175 jsonObject * obj = NULL;
176 if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create"))
177 obj = doCreate(meta, ctx->params);
179 if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve"))
180 obj = doRetrieve(meta, ctx->params);
182 if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update"))
183 obj = doUpdate(meta, ctx->params);
185 if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete"))
186 obj = doDelete(meta, ctx->params);
188 osrfAppRespondComplete( ctx, obj );
195 jsonObject* doCreate( osrfHash* meta, jsonObject* params ) { return NULL; }
197 jsonObject* doRetrieve( osrfHash* meta, jsonObject* params ) {
199 char* id = jsonObjectToSimpleString(jsonObjectGetIndex(params, 0));
203 "%s retrieving %s object with id %s",
205 osrfHashGet(meta, "fieldmapper"),
211 growing_buffer* sql_buf = buffer_init(128);
214 "SELECT * FROM %s WHERE %s = %d;",
215 osrfHashGet(meta, "tablename"),
216 xmlGetNsProp( (xmlNode*)osrfHashGet(meta, "fields"), "primary", "http://open-ils.org/spec/opensrf/IDL/persistance/v1" ),
220 char* sql = buffer_data(sql_buf);
221 buffer_free(sql_buf);
223 osrfLogDebug(OSRF_LOG_MARK, "%s SQL = %s", MODULENAME, sql);
225 dbi_result result = dbi_conn_query(dbhandle, sql);
227 jsonObject* obj = NULL;
230 /* there should be one row at the most */
231 if (!dbi_result_first_row(result)) {
232 osrfLogDebug(OSRF_LOG_MARK, "%s: Error retrieving %s with key %s", MODULENAME, osrfHashGet(meta, "fieldmapper"), id);
233 dbi_result_free(result);
237 /* JSONify the result */
238 obj = oilsMakeJSONFromResult( result, meta );
240 /* clean up the query */
241 dbi_result_free(result);
244 osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
253 jsonObject* doUpdate( osrfHash* meta, jsonObject* params ) { return NULL; }
255 jsonObject* doDelete( osrfHash* meta, jsonObject* params ) { return NULL; }
258 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
259 if(!(result && meta)) return NULL;
261 jsonObject* object = jsonParseString("[]");
262 jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
268 const char* columnName;
270 /* cycle through the column list */
271 while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
273 /* determine the field type and storage attributes */
274 type = dbi_result_get_field_type(result, columnName);
275 attr = dbi_result_get_field_attribs(result, columnName);
277 /* fetch the fieldmapper index */
278 if( (fmIndex = fm_ntop(object->classname, (char*) columnName)) < 0 ) continue;
282 case DBI_TYPE_INTEGER :
284 if( attr & DBI_INTEGER_SIZE8 )
285 jsonObjectSetIndex( object, fmIndex,
286 jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
288 jsonObjectSetIndex( object, fmIndex,
289 jsonNewNumberObject(dbi_result_get_long(result, columnName)));
293 case DBI_TYPE_DECIMAL :
294 jsonObjectSetIndex( object, fmIndex,
295 jsonNewNumberObject(dbi_result_get_double(result, columnName)));
298 case DBI_TYPE_STRING :
299 jsonObjectSetIndex( object, fmIndex,
300 jsonNewObject(dbi_result_get_string(result, columnName)));
303 case DBI_TYPE_DATETIME :
304 jsonObjectSetIndex( object, fmIndex,
305 jsonNewNumberObject(dbi_result_get_datetime(result, columnName)));
308 case DBI_TYPE_BINARY :
309 osrfLogError( OSRF_LOG_MARK,
310 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);