Add a new service, open-ils.qstore. It is not yet useful except for testing
authorscottmk <scottmk@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 19 Apr 2010 12:48:01 +0000 (12:48 +0000)
committerscottmk <scottmk@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 19 Apr 2010 12:48:01 +0000 (12:48 +0000)
connectivity, because the methods are stubbed out.  It will require changes to
opensrf.core before a client can access it.

A    Open-ILS/src/c-apps/oils_qstore.c
M    Open-ILS/src/c-apps/Makefile.am

git-svn-id: svn://svn.open-ils.org/ILS/trunk@16270 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/c-apps/Makefile.am
Open-ILS/src/c-apps/oils_qstore.c [new file with mode: 0644]

index 2892fd6..e63904c 100644 (file)
@@ -21,7 +21,7 @@ test_json_query_CFLAGS = $(AM_CFLAGS)
 test_json_query_LDFLAGS = $(AM_LDFLAGS) -loils_idl -loils_utils
 test_json_query_DEPENDENCIES = liboils_idl.la liboils_utils.la
 
-lib_LTLIBRARIES = liboils_idl.la liboils_utils.la oils_cstore.la oils_rstore.la oils_pcrud.la oils_auth.la
+lib_LTLIBRARIES = liboils_idl.la liboils_utils.la oils_cstore.la oils_qstore.la oils_rstore.la oils_pcrud.la oils_auth.la
 
 liboils_idl_la_SOURCES = oils_idl-core.c
 
@@ -31,6 +31,10 @@ oils_cstore_la_SOURCES = oils_cstore.c oils_sql.c
 oils_cstore_la_LDFLAGS = $(AM_LDFLAGS) -loils_idl -ldbi -ldbdpgsql -loils_utils -module
 oils_cstore_la_DEPENDENCIES = liboils_idl.la liboils_idl.la
 
+oils_qstore_la_SOURCES = oils_qstore.c oils_sql.c
+oils_qstore_la_LDFLAGS = $(AM_LDFLAGS) -loils_idl -ldbi -ldbdpgsql -loils_utils -module
+oils_qstore_la_DEPENDENCIES = liboils_idl.la liboils_idl.la
+
 oils_rstore_la_SOURCES = oils_rstore.c oils_sql.c
 oils_rstore_la_LDFLAGS = $(AM_LDFLAGS) -loils_idl -ldbi -ldbdpgsql -loils_utils -module
 oils_rstore_la_DEPENDENCIES = liboils_idl.la liboils_idl.la
diff --git a/Open-ILS/src/c-apps/oils_qstore.c b/Open-ILS/src/c-apps/oils_qstore.c
new file mode 100644 (file)
index 0000000..e22e5d4
--- /dev/null
@@ -0,0 +1,233 @@
+/**
+       @file oils_qstore.c
+       @brief As a server, perform database queries as defined in the database itself.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <dbi/dbi.h>
+#include "opensrf/utils.h"
+#include "opensrf/log.h"
+#include "opensrf/osrf_json.h"
+#include "opensrf/osrf_application.h"
+#include "openils/oils_utils.h"
+#include "openils/oils_sql.h"
+
+static dbi_conn dbhandle; /* our db connection */
+
+static const char modulename[] = "open-ils.qstore";
+
+int doPrepare( osrfMethodContext* ctx );
+int doExecute( osrfMethodContext* ctx );
+int doSql( osrfMethodContext* ctx );
+
+/**
+       @brief Disconnect from the database.
+
+       This function is called when the server drone is about to terminate.
+*/
+void osrfAppChildExit() {
+       osrfLogDebug( OSRF_LOG_MARK, "Child is exiting, disconnecting from database..." );
+
+       if ( dbhandle ) {
+               dbi_conn_query( dbhandle, "ROLLBACK;" );
+               dbi_conn_close( dbhandle );
+               dbhandle = NULL;
+       }
+}
+
+/**
+       @brief Initialize the application.
+       @return Zero if successful, or non-zero if not.
+
+       Load the IDL file into an internal data structure for future reference.  Each non-virtual
+       class in the IDL corresponds to a table or view in the database, or to a subquery defined
+       in the IDL.  Ignore all virtual tables and virtual fields.
+
+       Register the functions for remote procedure calls.
+
+       This function is called when the registering the application, and is executed by the
+       listener before spawning the drones.
+*/
+int osrfAppInitialize() {
+
+       osrfLogInfo( OSRF_LOG_MARK, "Initializing the QStore Server..." );
+       osrfLogInfo( OSRF_LOG_MARK, "Finding XML file..." );
+
+       if ( !oilsIDLInit( osrf_settings_host_value( "/IDL" )))
+               return 1; /* return non-zero to indicate error */
+
+       growing_buffer* method_name = buffer_init( 64 );
+
+       OSRF_BUFFER_ADD( method_name, modulename );
+       OSRF_BUFFER_ADD( method_name, ".prepare" );
+       osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
+                       "doBuild", "", 1, 0 );
+
+       buffer_reset( method_name );
+       OSRF_BUFFER_ADD( method_name, modulename );
+       OSRF_BUFFER_ADD( method_name, ".execute" );
+       osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
+                       "doExecute", "", 1, OSRF_METHOD_STREAMING );
+
+       buffer_reset( method_name );
+       OSRF_BUFFER_ADD( method_name, modulename );
+       OSRF_BUFFER_ADD( method_name, ".sql" );
+       osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
+                       "doSql", "", 1, OSRF_METHOD_STREAMING );
+
+       return 0;
+}
+
+/**
+       @brief Initialize a server drone.
+       @return Zero if successful, -1 if not.
+
+       Connect to the database.  For each non-virtual class in the IDL, execute a dummy "SELECT * "
+       query to get the datatype of each column.  Record the datatypes in the loaded IDL.
+
+       This function is called by a server drone shortly after it is spawned by the listener.
+*/
+int osrfAppChildInit() {
+
+       osrfLogDebug( OSRF_LOG_MARK, "Attempting to initialize libdbi..." );
+       dbi_initialize( NULL );
+       osrfLogDebug( OSRF_LOG_MARK, "... libdbi initialized." );
+
+       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 );
+
+       osrfLogDebug( OSRF_LOG_MARK, "Attempting to load the database driver [%s]...", driver );
+       dbhandle = dbi_conn_new( driver );
+
+       if( !dbhandle ) {
+               osrfLogError( OSRF_LOG_MARK, "Error loading database driver [%s]", driver );
+               return -1;
+       }
+       osrfLogDebug( OSRF_LOG_MARK, "Database driver [%s] seems OK", driver );
+
+       osrfLogInfo(OSRF_LOG_MARK, "%s connecting to database.  host=%s, "
+                       "port=%s, user=%s, db=%s", modulename, host, port, user, 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 );
+
+       const char* err;
+       if( dbi_conn_connect( dbhandle ) < 0 ) {
+               sleep( 1 );
+               if( dbi_conn_connect( dbhandle ) < 0 ) {
+                       dbi_conn_error( dbhandle, &err );
+                       osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err );
+                       return -1;
+               }
+       }
+
+       oilsSetDBConnection( dbhandle );
+       osrfLogInfo( OSRF_LOG_MARK, "%s successfully connected to the database", modulename );
+
+       // Add datatypes from database to the fields in the IDL
+       if( oilsExtendIDL() ) {
+               osrfLogError( OSRF_LOG_MARK, "Error extending the IDL" );
+               return -1;
+       }
+       else
+               return 0;
+}
+
+int doPrepare( osrfMethodContext* ctx ) {
+       if(osrfMethodVerifyContext( ctx )) {
+               osrfLogError( OSRF_LOG_MARK,  "Invalid method context" );
+               return -1;
+       }
+
+       // Get the query id from a method parameter
+       const jsonObject* query_id_obj = jsonObjectGetIndex( ctx->params, 0 );
+       if( query_id_obj->type != JSON_NUMBER ) {
+               osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+                       ctx->request, "Invalid parameter; query id must be a number" );
+               return -1;
+       }
+       int query_id = atoi( jsonObjectGetString( query_id_obj ));
+       if( query_id <= 0 ) {
+               osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+                       ctx->request, "Invalid parameter: query id must be greater than zero" );
+               return -1;
+       }
+
+       osrfLogInfo( OSRF_LOG_MARK, "Building query for id # %d", query_id );
+
+       osrfAppRespondComplete( ctx, jsonNewObject( "build method not yet implemented" ));
+       return 0;
+}
+
+int doExecute( osrfMethodContext* ctx ) {
+       if(osrfMethodVerifyContext( ctx )) {
+               osrfLogError( OSRF_LOG_MARK,  "Invalid method context" );
+               return -1;
+       }
+
+       // Get the query token
+       const jsonObject* token_obj = jsonObjectGetIndex( ctx->params, 0 );
+       if( token_obj->type != JSON_STRING ) {
+               osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+                       ctx->request, "Invalid parameter; query id must be a string" );
+               return -1;
+       }
+       const char* token = jsonObjectGetString( token_obj );
+
+       // Get the list of bind variables, if there is one
+       jsonObject* bind_map = jsonObjectGetIndex( ctx->params, 1 );
+       if( bind_map && bind_map->type != JSON_HASH ) {
+               osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+                       ctx->request, "Invalid parameter; bind map must be a JSON object" );
+               return -1;
+       }
+
+       osrfLogInfo( OSRF_LOG_MARK, "Executing query for token \"%s\"", token );
+
+       osrfAppRespondComplete( ctx, jsonNewObject( "execute method not yet implemented" ));
+       return 0;
+}
+
+int doSql( osrfMethodContext* ctx ) {
+       if(osrfMethodVerifyContext( ctx )) {
+               osrfLogError( OSRF_LOG_MARK,  "Invalid method context" );
+               return -1;
+       }
+
+       // Get the query token
+       const jsonObject* token_obj = jsonObjectGetIndex( ctx->params, 0 );
+       if( token_obj->type != JSON_STRING ) {
+               osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+                       ctx->request, "Invalid parameter; query id must be a string" );
+               return -1;
+       }
+       const char* token = jsonObjectGetString( token_obj );
+
+       // Get the list of bind variables, if there is one
+       jsonObject* bind_map = jsonObjectGetIndex( ctx->params, 1 );
+       if( bind_map && bind_map->type != JSON_HASH ) {
+               osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+                       ctx->request, "Invalid parameter; bind map must be a JSON object" );
+               return -1;
+       }
+
+       osrfLogInfo( OSRF_LOG_MARK, "Returning SQL for token \"%s\"", token );
+
+       osrfAppRespondComplete( ctx, jsonNewObject( "sql method not yet implemented" ));
+       return 0;
+}