From b5291003a0d949ad57d43ef8d3f62eed14727137 Mon Sep 17 00:00:00 2001 From: miker Date: Tue, 9 May 2006 05:30:57 +0000 Subject: [PATCH] adding new open-ils.cstore app; moving new IDL generator to a better home; added userData support to method context git-svn-id: svn://svn.open-ils.org/ILS/trunk@4172 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/src/c-apps/oils_cstore.c | 319 ++++++++++++++++++ .../{apachemods => extras}/fieldmapper_IDL.pl | 3 +- OpenSRF/src/libstack/osrf_application.c | 22 +- OpenSRF/src/libstack/osrf_application.h | 6 +- 4 files changed, 345 insertions(+), 5 deletions(-) create mode 100644 Open-ILS/src/c-apps/oils_cstore.c rename Open-ILS/src/{apachemods => extras}/fieldmapper_IDL.pl (92%) diff --git a/Open-ILS/src/c-apps/oils_cstore.c b/Open-ILS/src/c-apps/oils_cstore.c new file mode 100644 index 0000000000..3c367dcfbe --- /dev/null +++ b/Open-ILS/src/c-apps/oils_cstore.c @@ -0,0 +1,319 @@ +#include "opensrf/osrf_application.h" +#include "opensrf/osrf_settings.h" +#include "opensrf/utils.h" +#include "objson/object.h" +#include "opensrf/log.h" +#include "oils_utils.h" +#include "oils_constants.h" +#include "oils_event.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define OILS_AUTH_CACHE_PRFX "oils_cstore_" +#define MODULENAME "open-ils.cstore" + +int osrfAppChildInit(); +int osrfAppInitialize(); + +int dispatchCRUDMethod ( osrfMethodContext* ctx ); +jsonObject* doCreate ( osrfHash* metadata, jsonObject* params ); +jsonObject* doRetrieve ( osrfHash* metadata, jsonObject* params ); +jsonObject* doUpdate ( osrfHash* metadata, jsonObject* params ); +jsonObject* doDelete ( osrfHash* metadata, jsonObject* params ); +jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta); + +dbi_conn dbhandle; /* our db connection */ +xmlDocPtr idlDoc = NULL; // parse and store the IDL here + +/* handy NULL json object to have around */ +static jsonObject* oilsNULL = NULL; + +int osrfAppInitialize() { + osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server..."); + osrfLogInfo(OSRF_LOG_MARK, "Finding XML file..."); + + char * idl_filename = osrf_settings_host_value("/apps/%s/app_settings/IDL", MODULENAME); + osrfLogInfo(OSRF_LOG_MARK, "Found file:"); + osrfLogInfo(OSRF_LOG_MARK, idl_filename); + + osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML..."); + idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE ); + + if (!idlDoc) { + osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!"); + exit(1); + } + + osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed"); + + osrfStringArray* global_methods = osrfNewStringArray(1); + + //osrfStringArrayAdd( global_methods, "create" ); + osrfStringArrayAdd( global_methods, "retrieve" ); + //osrfStringArrayAdd( global_methods, "update" ); + //osrfStringArrayAdd( global_methods, "delete" ); + + xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc); + xmlNodePtr kid = docRoot->children; + while (kid) { + if (!strcmp( (char*)kid->name, "class" )) { + int i = 0; + char* method_type; + while ( (method_type = osrfStringArrayGetString(global_methods, i)) ) { + + osrfHash * usrData = osrfNewHash(); + osrfHashSet( usrData, xmlGetProp(kid, "id"), "classname"); + osrfHashSet( usrData, xmlGetNsProp(kid, "tablename", "http://open-ils.org/spec/opensrf/IDL/persistance/v1"), "tablename"); + osrfHashSet( usrData, xmlGetNsProp(kid, "fieldmapper", "http://open-ils.org/spec/opensrf/IDL/objects/v1"), "fieldmapper"); + + xmlNodePtr _cur = kid->children; + while (_cur) { + if (!strcmp( (char*)_cur->name, "fields" )) osrfHashSet( usrData, _cur, "fields"); + if (!strcmp( (char*)_cur->name, "links" )) osrfHashSet( usrData, _cur, "links"); + _cur = _cur->next; + } + + + char* _fm = strdup( (char*)osrfHashGet(usrData, "fieldmapper") ); + char* part = strtok(_fm, ":"); + + growing_buffer* method_name = buffer_init(64); + buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part); + + while ((part = strtok(NULL, ":"))) { + buffer_fadd(method_name, ".%s", part); + } + buffer_fadd(method_name, ".%s", method_type); + + char* method = buffer_data(method_name); + buffer_free(method_name); + + osrfHashSet( usrData, method, "methodname" ); + osrfHashSet( usrData, strdup(method_type), "methodtype" ); + + osrfAppRegisterExtendedMethod( + MODULENAME, + method, + "dispatchCRUDMethod", + "", + 1, + 0, + (void*)usrData + ); + + i++; + } + } + kid = kid->next; + } + + return 0; +} + +/** + * Connects to the database + */ +int osrfAppChildInit() { + + dbi_initialize(NULL); + + char* driver = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME); + char* user = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME); + char* host = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME); + char* port = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME); + char* db = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME); + char* pw = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME); + + dbhandle = dbi_conn_new(driver); + + if(!dbhandle) { + osrfLogError(OSRF_LOG_MARK, "Error creating database driver %s", driver); + return -1; + } + + osrfLogInfo(OSRF_LOG_MARK, "oils_fetch connecting to database. host=%s, " + "port=%s, user=%s, pw=%s, db=%s", host, port, user, pw, db ); + + if(host) dbi_conn_set_option(dbhandle, "host", host ); + if(port) dbi_conn_set_option_numeric( dbhandle, "port", atoi(port) ); + if(user) dbi_conn_set_option(dbhandle, "username", user); + if(pw) dbi_conn_set_option(dbhandle, "password", pw ); + if(db) dbi_conn_set_option(dbhandle, "dbname", db ); + + free(user); + free(host); + free(port); + free(db); + free(pw); + + if (dbi_conn_connect(dbhandle) < 0) { + const char* err; + dbi_conn_error(dbhandle, &err); + osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err); + return -1; + } + + osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME); + + return 0; +} + + +int dispatchCRUDMethod ( osrfMethodContext* ctx ) { + OSRF_METHOD_VERIFY_CONTEXT(ctx); + + osrfHash* meta = (osrfHash*) ctx->method->userData; + + jsonObject * obj = NULL; + if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create")) + obj = doCreate(meta, ctx->params); + + if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve")) + obj = doRetrieve(meta, ctx->params); + + if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update")) + obj = doUpdate(meta, ctx->params); + + if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete")) + obj = doDelete(meta, ctx->params); + + osrfAppRespondComplete( ctx, obj ); + + jsonObjectFree(obj); + + return 0; +} + +jsonObject* doCreate( osrfHash* meta, jsonObject* params ) { return NULL; } + +jsonObject* doRetrieve( osrfHash* meta, jsonObject* params ) { + + char* id = jsonObjectToSimpleString(jsonObjectGetIndex(params, 0)); + + osrfLogDebug( + OSRF_LOG_MARK, + "%s retrieving %s object with id %s", + MODULENAME, + osrfHashGet(meta, "fieldmapper"), + id + ); + + + + growing_buffer* sql_buf = buffer_init(128); + buffer_fadd( + sql_buf, + "SELECT * FROM %s WHERE %s = %d;", + osrfHashGet(meta, "tablename"), + xmlGetNsProp( (xmlNode*)osrfHashGet(meta, "fields"), "primary", "http://open-ils.org/spec/opensrf/IDL/persistance/v1" ), + atoi(id) + ); + + char* sql = buffer_data(sql_buf); + buffer_free(sql_buf); + + osrfLogDebug(OSRF_LOG_MARK, "%s SQL = %s", MODULENAME, sql); + + dbi_result result = dbi_conn_query(dbhandle, sql); + + jsonObject* obj = NULL; + if(result) { + + /* there should be one row at the most */ + if (!dbi_result_first_row(result)) { + osrfLogDebug(OSRF_LOG_MARK, "%s: Error retrieving %s with key %s", MODULENAME, osrfHashGet(meta, "fieldmapper"), id); + dbi_result_free(result); + return oilsNULL; + } + + /* JSONify the result */ + obj = oilsMakeJSONFromResult( result, meta ); + + /* clean up the query */ + dbi_result_free(result); + + } else { + osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql); + } + + free(id); + + return obj; +} + + +jsonObject* doUpdate( osrfHash* meta, jsonObject* params ) { return NULL; } + +jsonObject* doDelete( osrfHash* meta, jsonObject* params ) { return NULL; } + + +jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) { + if(!(result && meta)) return NULL; + + jsonObject* object = jsonParseString("[]"); + jsonObjectSetClass(object, osrfHashGet(meta, "classname")); + + int attr; + int fmIndex; + int columnIndex = 1; + unsigned short type; + const char* columnName; + + /* cycle through the column list */ + while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) { + + /* determine the field type and storage attributes */ + type = dbi_result_get_field_type(result, columnName); + attr = dbi_result_get_field_attribs(result, columnName); + + /* fetch the fieldmapper index */ + if( (fmIndex = fm_ntop(object->classname, (char*) columnName)) < 0 ) continue; + + switch( type ) { + + case DBI_TYPE_INTEGER : + + if( attr & DBI_INTEGER_SIZE8 ) + jsonObjectSetIndex( object, fmIndex, + jsonNewNumberObject(dbi_result_get_longlong(result, columnName))); + else + jsonObjectSetIndex( object, fmIndex, + jsonNewNumberObject(dbi_result_get_long(result, columnName))); + + break; + + case DBI_TYPE_DECIMAL : + jsonObjectSetIndex( object, fmIndex, + jsonNewNumberObject(dbi_result_get_double(result, columnName))); + break; + + case DBI_TYPE_STRING : + jsonObjectSetIndex( object, fmIndex, + jsonNewObject(dbi_result_get_string(result, columnName))); + break; + + case DBI_TYPE_DATETIME : + jsonObjectSetIndex( object, fmIndex, + jsonNewNumberObject(dbi_result_get_datetime(result, columnName))); + break; + + case DBI_TYPE_BINARY : + osrfLogError( OSRF_LOG_MARK, + "Can't do binary at column %s : index %d", columnName, columnIndex - 1); + } + } + + return object; +} + + + + diff --git a/Open-ILS/src/apachemods/fieldmapper_IDL.pl b/Open-ILS/src/extras/fieldmapper_IDL.pl similarity index 92% rename from Open-ILS/src/apachemods/fieldmapper_IDL.pl rename to Open-ILS/src/extras/fieldmapper_IDL.pl index 887a569ad7..ede167f8e7 100755 --- a/Open-ILS/src/apachemods/fieldmapper_IDL.pl +++ b/Open-ILS/src/extras/fieldmapper_IDL.pl @@ -63,9 +63,10 @@ for my $object (keys %$map) { my $f_key = $col->args->{foreign_key} || ($f_class->columns('Primary'))[0]; my $f_hint = $$map{$fm_link}{hint}; + my $map = join ' ', @{ $col->args->{mapping} } if ( $col->args->{mapping} ); print <<" XML"; - + XML } } diff --git a/OpenSRF/src/libstack/osrf_application.c b/OpenSRF/src/libstack/osrf_application.c index 713a19d9f7..572221469a 100644 --- a/OpenSRF/src/libstack/osrf_application.c +++ b/OpenSRF/src/libstack/osrf_application.c @@ -85,6 +85,21 @@ int osrfAppRunChildInit(char* appname) { int osrfAppRegisterMethod( char* appName, char* methodName, char* symbolName, char* notes, int argc, int options ) { + return osrfAppRegisterExtendedMethod( + appName, + methodName, + symbolName, + notes, + argc, + options, + NULL + ); + +} + +int osrfAppRegisterExtendedMethod( char* appName, char* methodName, + char* symbolName, char* notes, int argc, int options, void * user_data ) { + if( !appName || ! methodName ) return -1; osrfApplication* app = _osrfAppFindApplication(appName); @@ -96,7 +111,7 @@ int osrfAppRegisterMethod( char* appName, char* methodName, osrfLogDebug( OSRF_LOG_MARK, "Registering method %s for app %s", methodName, appName ); osrfMethod* method = _osrfAppBuildMethod( - methodName, symbolName, notes, argc, options ); + methodName, symbolName, notes, argc, options, user_data ); method->options = options; /* plug the method into the list of methods */ @@ -105,7 +120,7 @@ int osrfAppRegisterMethod( char* appName, char* methodName, if( options & OSRF_METHOD_STREAMING ) { /* build the atomic counterpart */ int newops = options | OSRF_METHOD_ATOMIC; osrfMethod* atomicMethod = _osrfAppBuildMethod( - methodName, symbolName, notes, argc, newops ); + methodName, symbolName, notes, argc, newops, NULL ); osrfHashSet( app->methods, atomicMethod, atomicMethod->name ); } @@ -115,13 +130,14 @@ int osrfAppRegisterMethod( char* appName, char* methodName, osrfMethod* _osrfAppBuildMethod( char* methodName, - char* symbolName, char* notes, int argc, int options ) { + char* symbolName, char* notes, int argc, int options, void* user_data ) { osrfMethod* method = safe_malloc(sizeof(osrfMethod)); if(methodName) method->name = strdup(methodName); if(symbolName) method->symbol = strdup(symbolName); if(notes) method->notes = strdup(notes); + if(user_data) method->userData = user_data; method->argc = argc; method->options = options; diff --git a/OpenSRF/src/libstack/osrf_application.h b/OpenSRF/src/libstack/osrf_application.h index dd5a958cc7..c62aebb19b 100644 --- a/OpenSRF/src/libstack/osrf_application.h +++ b/OpenSRF/src/libstack/osrf_application.h @@ -88,6 +88,7 @@ struct _osrfMethodStruct { int argc; /* how many args this method expects */ //char* paramNotes; /* Description of the params expected for this method */ int options; /* describes the various options for this method */ + void* userData; /* You can put your weeeeeeed in it ... */ /* int sysmethod; @@ -133,8 +134,11 @@ int osrfAppRegisterMethod( char* appName, char* methodName, char* symbolName, char* notes, int argc, int options ); +int osrfAppRegisterExtendedMethod( char* appName, char* methodName, + char* symbolName, char* notes, int argc, int options, void* ); + osrfMethod* _osrfAppBuildMethod( char* methodName, - char* symbolName, char* notes, int argc, int options ); + char* symbolName, char* notes, int argc, int options, void* ); /** Finds the given app in the list of apps -- 2.43.2