[open-ils-commits] r16270 - trunk/Open-ILS/src/c-apps (scottmk)
svn at svn.open-ils.org
svn at svn.open-ils.org
Mon Apr 19 08:48:02 EDT 2010
Author: scottmk
Date: 2010-04-19 08:48:01 -0400 (Mon, 19 Apr 2010)
New Revision: 16270
Added:
trunk/Open-ILS/src/c-apps/oils_qstore.c
Modified:
trunk/Open-ILS/src/c-apps/Makefile.am
Log:
Add a new service, open-ils.qstore. It is not yet useful except for testing
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
Modified: trunk/Open-ILS/src/c-apps/Makefile.am
===================================================================
--- trunk/Open-ILS/src/c-apps/Makefile.am 2010-04-19 12:47:12 UTC (rev 16269)
+++ trunk/Open-ILS/src/c-apps/Makefile.am 2010-04-19 12:48:01 UTC (rev 16270)
@@ -21,7 +21,7 @@
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_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
Added: trunk/Open-ILS/src/c-apps/oils_qstore.c
===================================================================
--- trunk/Open-ILS/src/c-apps/oils_qstore.c (rev 0)
+++ trunk/Open-ILS/src/c-apps/oils_qstore.c 2010-04-19 12:48:01 UTC (rev 16270)
@@ -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;
+}
More information about the open-ils-commits
mailing list