adding new open-ils.cstore app; moving new IDL generator to a better home; added...
authormiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 9 May 2006 05:30:57 +0000 (05:30 +0000)
committermiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 9 May 2006 05:30:57 +0000 (05:30 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@4172 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/apachemods/fieldmapper_IDL.pl [deleted file]
Open-ILS/src/c-apps/oils_cstore.c [new file with mode: 0644]
Open-ILS/src/extras/fieldmapper_IDL.pl [new file with mode: 0755]
OpenSRF/src/libstack/osrf_application.c
OpenSRF/src/libstack/osrf_application.h

diff --git a/Open-ILS/src/apachemods/fieldmapper_IDL.pl b/Open-ILS/src/apachemods/fieldmapper_IDL.pl
deleted file mode 100755 (executable)
index 887a569..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/perl
-use strict;
-use Data::Dumper;
-use lib '../perlmods/';
-
-{ package OpenILS::Application::Storage; sub register_method {}; }
-
-my $map = {};
-eval "
-       use lib '../perlmods/';
-       use lib '../../../OpenSRF/src/perlmods/';
-       use OpenILS::Utils::Fieldmapper;  
-       use OpenILS::Application::Storage::Driver::Pg::dbi;  
-";
-$map = $Fieldmapper::fieldmap unless ($@);
-
-die $@ if ($@);
-
-
-warn "Generating fieldmapper IDL xml...\n";
-
-print <<XML;
-<IDL xmlns="http://opensrf.org/spec/IDL/base/v1" xmlns:oils_persist="http://open-ils.org/spec/opensrf/IDL/persistance/v1" xmlns:oils_obj="http://open-ils.org/spec/opensrf/IDL/objects/v1">
-XML
-
-
-for my $object (keys %$map) {
-       next unless ($map->{$object}->{cdbi});
-
-       my $fm = $$map{$object}{cdbi};
-       my $short_name= $map->{$object}->{hint};
-       my ($primary) = $map->{$object}->{cdbi}->columns('Primary');
-       my $table = $map->{$object}->{cdbi}->table;
-
-       print <<"       XML";
-       <class id="$short_name" oils_obj:fieldmapper="$fm" oils_persist:tablename="$table">
-               <fields oils_persist:primary="$primary">
-       XML
-
-       for my $field (sort { $$map{$object}{fields}{$a}{position} <=> $$map{$object}{fields}{$b}{position}} keys %{$map->{$object}->{fields}}) {
-               my $position = $map->{$object}->{fields}->{$field}->{position};
-               my $virtual = $map->{$object}->{fields}->{$field}->{virtual} ? 'true' : 'false';
-               print <<"               XML";
-                       <field name="$field" oils_obj:array_position="$position" oils_persist:virtual="$virtual" />
-               XML
-       }
-
-       print <<"       XML";
-               </fields>
-               <links>
-       XML
-
-       my $meta = $$map{$object}{cdbi}->meta_info();
-       #warn Dumper($meta);
-
-       for my $reltype ( keys %$meta ) {
-               for my $colname ( keys %{ $$meta{$reltype} } ) {
-                       my $col = $$meta{$reltype}{$colname};
-                       
-                       my $f_class = $col->foreign_class;
-                       my $fm_link = "Fieldmapper::$f_class";
-                       next unless $$map{$fm_link}{cdbi};
-
-                       my $f_key = $col->args->{foreign_key} || ($f_class->columns('Primary'))[0];
-                       my $f_hint = $$map{$fm_link}{hint};
-
-                       print <<"                       XML";
-                       <link field="$colname" reltype="$reltype" key="$f_key" class="$f_hint"/>
-                       XML
-               }
-       }
-
-       print <<"       XML";
-               </links>
-       </class>
-       XML
-}
-
-print <<XML;
-</IDL>
-XML
-
-
diff --git a/Open-ILS/src/c-apps/oils_cstore.c b/Open-ILS/src/c-apps/oils_cstore.c
new file mode 100644 (file)
index 0000000..3c367dc
--- /dev/null
@@ -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 <dbi/dbi.h>
+
+#include <string.h>
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/debugXML.h>
+#include <libxml/xmlmemory.h>
+#include <openils/fieldmapper_lookup.h>
+
+#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/extras/fieldmapper_IDL.pl b/Open-ILS/src/extras/fieldmapper_IDL.pl
new file mode 100755 (executable)
index 0000000..ede167f
--- /dev/null
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+use strict;
+use Data::Dumper;
+use lib '../perlmods/';
+
+{ package OpenILS::Application::Storage; sub register_method {}; }
+
+my $map = {};
+eval "
+       use lib '../perlmods/';
+       use lib '../../../OpenSRF/src/perlmods/';
+       use OpenILS::Utils::Fieldmapper;  
+       use OpenILS::Application::Storage::Driver::Pg::dbi;  
+";
+$map = $Fieldmapper::fieldmap unless ($@);
+
+die $@ if ($@);
+
+
+warn "Generating fieldmapper IDL xml...\n";
+
+print <<XML;
+<IDL xmlns="http://opensrf.org/spec/IDL/base/v1" xmlns:oils_persist="http://open-ils.org/spec/opensrf/IDL/persistance/v1" xmlns:oils_obj="http://open-ils.org/spec/opensrf/IDL/objects/v1">
+XML
+
+
+for my $object (keys %$map) {
+       next unless ($map->{$object}->{cdbi});
+
+       my $fm = $$map{$object}{cdbi};
+       my $short_name= $map->{$object}->{hint};
+       my ($primary) = $map->{$object}->{cdbi}->columns('Primary');
+       my $table = $map->{$object}->{cdbi}->table;
+
+       print <<"       XML";
+       <class id="$short_name" oils_obj:fieldmapper="$fm" oils_persist:tablename="$table">
+               <fields oils_persist:primary="$primary">
+       XML
+
+       for my $field (sort { $$map{$object}{fields}{$a}{position} <=> $$map{$object}{fields}{$b}{position}} keys %{$map->{$object}->{fields}}) {
+               my $position = $map->{$object}->{fields}->{$field}->{position};
+               my $virtual = $map->{$object}->{fields}->{$field}->{virtual} ? 'true' : 'false';
+               print <<"               XML";
+                       <field name="$field" oils_obj:array_position="$position" oils_persist:virtual="$virtual" />
+               XML
+       }
+
+       print <<"       XML";
+               </fields>
+               <links>
+       XML
+
+       my $meta = $$map{$object}{cdbi}->meta_info();
+       #warn Dumper($meta);
+
+       for my $reltype ( keys %$meta ) {
+               for my $colname ( keys %{ $$meta{$reltype} } ) {
+                       my $col = $$meta{$reltype}{$colname};
+                       
+                       my $f_class = $col->foreign_class;
+                       my $fm_link = "Fieldmapper::$f_class";
+                       next unless $$map{$fm_link}{cdbi};
+
+                       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";
+                       <link field="$colname" reltype="$reltype" key="$f_key" map="$map" class="$f_hint"/>
+                       XML
+               }
+       }
+
+       print <<"       XML";
+               </links>
+       </class>
+       XML
+}
+
+print <<XML;
+</IDL>
+XML
+
+
index 713a19d..5722214 100644 (file)
@@ -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;
index dd5a958..c62aebb 100644 (file)
@@ -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