From 63de8b5dec6b639706ba6a79e3c269e7173471e8 Mon Sep 17 00:00:00 2001 From: erickson Date: Thu, 15 Sep 2005 22:57:18 +0000 Subject: [PATCH] some api changes tested the cache stuff better added #define for enforcing argc on methods system methods are registered through the same facility as regular methods git-svn-id: svn://svn.open-ils.org/ILS/trunk@1831 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- OpenSRF/src/c-apps/osrf_dbmath.c | 38 ++++- OpenSRF/src/c-apps/osrf_math.c | 38 ++++- OpenSRF/src/c-apps/osrf_version.c | 7 +- OpenSRF/src/libstack/Makefile | 5 +- OpenSRF/src/libstack/osrf_application.c | 185 ++++++++++++++++++------ OpenSRF/src/libstack/osrf_application.h | 102 ++++++++++--- OpenSRF/src/libstack/osrf_cache.c | 5 +- OpenSRF/src/libstack/osrf_message.c | 14 +- 8 files changed, 304 insertions(+), 90 deletions(-) diff --git a/OpenSRF/src/c-apps/osrf_dbmath.c b/OpenSRF/src/c-apps/osrf_dbmath.c index 07cf0f653d..0acecafdea 100644 --- a/OpenSRF/src/c-apps/osrf_dbmath.c +++ b/OpenSRF/src/c-apps/osrf_dbmath.c @@ -3,17 +3,45 @@ #include "objson/object.h" #include "opensrf/osrf_log.h" +#define MODULENAME "opensrf.dbmath" + int osrfAppInitialize(); int osrfAppChildInit(); int osrfMathRun( osrfMethodContext* ); int osrfAppInitialize() { - osrfLogInit("opensrf.dbmath"); - osrfAppRegisterMethod( "opensrf.dbmath", "add", "osrfMathRun", "send 2 numbers and I'll add them", 2 ); - osrfAppRegisterMethod( "opensrf.dbmath", "sub", "osrfMathRun", "send 2 numbers and I'll divide them", 2 ); - osrfAppRegisterMethod( "opensrf.dbmath", "mult", "osrfMathRun", "send 2 numbers and I'll multiply them", 2 ); - osrfAppRegisterMethod( "opensrf.dbmath", "div", "osrfMathRun", "send 2 numbers and I'll subtract them", 2 ); + + osrfLogInit(MODULENAME); + + osrfAppRegisterMethod( + MODULENAME, + "add", + "osrfMathRun", + "Addss two numbers", + "[ num1, num2 ]", 2 ); + + osrfAppRegisterMethod( + MODULENAME, + "sub", + "osrfMathRun", + "Subtracts two numbers", + "[ num1, num2 ]", 2 ); + + osrfAppRegisterMethod( + MODULENAME, + "mult", + "osrfMathRun", + "Multiplies two numbers", + "[ num1, num2 ]", 2 ); + + osrfAppRegisterMethod( + MODULENAME, + "div", + "osrfMathRun", + "Divides two numbers", + "[ num1, num2 ]", 2 ); + return 0; } diff --git a/OpenSRF/src/c-apps/osrf_math.c b/OpenSRF/src/c-apps/osrf_math.c index 9cb22aa640..78a9ddc256 100644 --- a/OpenSRF/src/c-apps/osrf_math.c +++ b/OpenSRF/src/c-apps/osrf_math.c @@ -3,18 +3,44 @@ #include "objson/object.h" #include "opensrf/osrf_log.h" +#define MODULENAME "opensrf.math" + int osrfAppInitialize(); int osrfAppChildInit(); int osrfMathRun( osrfMethodContext* ); int osrfAppInitialize() { - osrfLogInit("opensrf.math"); - /* tell the server about the methods we handle */ - osrfAppRegisterMethod( "opensrf.math", "add", "osrfMathRun", "send 2 numbers and I'll add them", 2 ); - osrfAppRegisterMethod( "opensrf.math", "sub", "osrfMathRun", "send 2 numbers and I'll divide them", 2 ); - osrfAppRegisterMethod( "opensrf.math", "mult", "osrfMathRun", "send 2 numbers and I'll multiply them", 2 ); - osrfAppRegisterMethod( "opensrf.math", "div", "osrfMathRun", "send 2 numbers and I'll subtract them", 2 ); + osrfLogInit(MODULENAME); + + osrfAppRegisterMethod( + MODULENAME, + "add", + "osrfMathRun", + "Addss two numbers", + "( num1, num2 )", 2 ); + + osrfAppRegisterMethod( + MODULENAME, + "sub", + "osrfMathRun", + "Subtracts two numbers", + "( num1, num2 )", 2 ); + + osrfAppRegisterMethod( + MODULENAME, + "mult", + "osrfMathRun", + "Multiplies two numbers", + "( num1, num2 )", 2 ); + + osrfAppRegisterMethod( + MODULENAME, + "div", + "osrfMathRun", + "Divides two numbers", + "( num1, num2 )", 2 ); + return 0; } diff --git a/OpenSRF/src/c-apps/osrf_version.c b/OpenSRF/src/c-apps/osrf_version.c index 6785315be2..2936607bee 100644 --- a/OpenSRF/src/c-apps/osrf_version.c +++ b/OpenSRF/src/c-apps/osrf_version.c @@ -13,14 +13,15 @@ int osrfVersion( osrfMethodContext* ); int osrfAppInitialize() { osrfLogInit("opensrf.version"); + osrfAppRegisterMethod( "opensrf.version", "opensrf.version.verify", "osrfVersion", - "Send the service, method, and params as paramters to this method " - "The data for this service/method/params combination will be retrieved " + "The data for a service/method/params combination will be retrieved " "from the necessary server and the MD5 sum of the total values received " - "will be returned", 2 ); + "will be returned", + "( serviceName, methodName, [param1, ...] )", 2 ); return 0; } diff --git a/OpenSRF/src/libstack/Makefile b/OpenSRF/src/libstack/Makefile index 1ff362a3c9..b6b76de993 100644 --- a/OpenSRF/src/libstack/Makefile +++ b/OpenSRF/src/libstack/Makefile @@ -1,5 +1,8 @@ +# OSRF_LOG_PARAMS log all incoming method params at OSRF_INFO log level. +# OSRF_STRICT_PARAMS instructs the app handler to return an error if the number of method arguments +# provided to any method is not at least as large as the 'argc' setting for the method -CFLAGS += -DASSUME_STATELESS -DOSRF_LOG_PARAMS -rdynamic -fno-strict-aliasing +CFLAGS += -DASSUME_STATELESS -DOSRF_LOG_PARAMS -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing LDLIBS += -lxml2 -lobjson -ldl -lmemcache TARGETS = osrf_message.o \ diff --git a/OpenSRF/src/libstack/osrf_application.c b/OpenSRF/src/libstack/osrf_application.c index 4aa3369361..e91920869d 100644 --- a/OpenSRF/src/libstack/osrf_application.c +++ b/OpenSRF/src/libstack/osrf_application.c @@ -48,6 +48,7 @@ int osrfAppRegisterApplication( char* appName, char* soFile ) { } } + __osrfAppRegisterSysMethods(appName); info_handler("Application %s registered successfully", appName ); @@ -55,21 +56,18 @@ int osrfAppRegisterApplication( char* appName, char* soFile ) { return 0; } - int osrfAppRegisterMethod( char* appName, - char* methodName, char* symbolName, char* notes, int argc ) { + char* methodName, char* symbolName, char* notes, char* params, int argc ) { + if( !appName || ! methodName || ! symbolName ) return -1; osrfApplication* app = _osrfAppFindApplication(appName); if(!app) return warning_handler("Unable to locate application %s", appName ); - debug_handler("Registering method %s for app %s", appName, methodName ); + debug_handler("Registering method %s for app %s", methodName, appName ); - osrfMethod* method = safe_malloc(sizeof(osrfMethod)); - method->name = strdup(methodName); - method->symbol = strdup(symbolName); - if(notes) method->notes = strdup(notes); - method->argc = argc; + osrfMethod* method = _osrfAppBuildMethod( + methodName, symbolName, notes, params, argc, 0 ); /* plug the method into the list of methods */ method->next = app->methods; @@ -77,6 +75,52 @@ int osrfAppRegisterMethod( char* appName, return 0; } + +osrfMethod* _osrfAppBuildMethod( char* methodName, + char* symbolName, char* notes, char* params, int argc, int sysmethod ) { + + 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(params) method->paramNotes = strdup(params); + method->argc = argc; + method->sysmethod = sysmethod; + return method; +} + + +int _osrfAppRegisterSystemMethod( char* appName, char* methodName, + char* notes, char* params, int argc ) { + if(!(appName && methodName)) return -1; + osrfApplication* app = _osrfAppFindApplication(appName); + if(!app) return warning_handler("Unable to locate application %s", appName ); + debug_handler("Registering system method %s for app %s", methodName, appName ); + osrfMethod* method = _osrfAppBuildMethod( + methodName, NULL, notes, params, argc, 1 ); + + /* plug the method into the list of methods */ + method->next = app->methods; + app->methods = method; + return 0; + +} + +int __osrfAppRegisterSysMethods( char* app ) { + + _osrfAppRegisterSystemMethod( + app, OSRF_SYSMETHOD_INTROSPECT, + "Return a list of methods whose names have the same initial " + "substring as that of the provided method name", + "( methodNameSubstring )", 1 ); + + _osrfAppRegisterSystemMethod( + app, OSRF_SYSMETHOD_INTROSPECT_ALL, + "Returns a complete list of methods", "()", 0 ); + + return 0; +} + osrfApplication* _osrfAppFindApplication( char* name ) { if(!name) return NULL; osrfApplication* app = __osrfAppList; @@ -105,9 +149,9 @@ osrfMethod* _osrfAppFindMethod( char* appName, char* methodName ) { } +int osrfAppRunMethod( char* appName, char* methodName, + osrfAppSession* ses, int reqId, jsonObject* params ) { - -int osrfAppRunMethod( char* appName, char* methodName, osrfAppSession* ses, int reqId, jsonObject* params ) { if( !(appName && methodName && ses) ) return -1; char* error; @@ -126,53 +170,82 @@ int osrfAppRunMethod( char* appName, char* methodName, osrfAppSession* ses, int "thread trace %s", methodName, appName, reqId, ses->session_id ); if( !(app = _osrfAppFindApplication(appName)) ) - return warning_handler( "Application not found: %s", appName ); - + return osrfAppRequestRespondException( ses, + reqId, "Application not found: %s", appName ); - if( !(method = __osrfAppFindMethod( app, methodName )) ) { - /* see if the unfound method is a system method */ - info_handler("Method %s not found, checking to see if it's a system method...", methodName ); - osrfMethod meth; - meth.name = methodName; - context.method = &meth; + if( !(method = __osrfAppFindMethod( app, methodName )) ) + return osrfAppRequestRespondException( ses, reqId, + "Method [%s] not found for service %s", methodName, appName ); + + context.method = method; + + #ifdef OSRF_STRICT_PARAMS + if( method->argc > 0 ) { + if(!params || params->type != JSON_ARRAY || params->size < method->argc ) + return osrfAppRequestRespondException( ses, reqId, + "Not enough params for method %s / service %s", methodName, appName ); + } + #endif + + if( method->sysmethod ) { + int sysres = __osrfAppRunSystemMethod(&context); if(sysres == 0) return 0; - if(sysres > 0) { - osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE, "osrfConnectStatus", reqId, "Request Complete" ); - return 0; - } - return warning_handler( "NOT FOUND: app %s / method %s", appName, methodName ); + + if(sysres > 0) + return osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE, + "osrfConnectStatus", reqId, "Request Complete" ); + + if(sysres < 0) + return osrfAppRequestRespondException( + ses, reqId, "An unknown server error occurred" ); } - context.method = method; - /* open the method */ *(void **) (&meth) = dlsym(app->handle, method->symbol); if( (error = dlerror()) != NULL ) { - return warning_handler("Unable to locate method symbol [%s] " - "for method %s and app %s", method->symbol, method->name, app->name ); + return osrfAppRequestRespondException( ses, reqId, + "Unable to execute method [%s] for service %s", methodName, appName ); } /* run the method */ - int ret = (*meth) (&context); - - debug_handler("method returned %d", ret ); - - if(ret == -1) { - osrfAppSessionStatus( ses, OSRF_STATUS_INTERNALSERVERERROR, - "Server Error", reqId, "An unknown server error occurred" ); - return -1; - } + int ret; + if( (ret = (*meth) (&context)) < 0 ) + return osrfAppRequestRespondException( + ses, reqId, "An unknown server error occurred" ); if( ret > 0 ) - osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE, "osrfConnectStatus", reqId, "Request Complete" ); + osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE, + "osrfConnectStatus", reqId, "Request Complete" ); + + return 0; +} +int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) { + if(!ses) return -1; + if(!msg) msg = ""; + VA_LIST_TO_STRING(msg); + osrfLog( OSRF_WARN, "Returning method exception with message: %s", VA_BUF ); + osrfAppSessionStatus( ses, OSRF_STATUS_NOTFOUND, "osrfMethodException", request, VA_BUF ); return 0; } +static void __osrfAppSetIntrospectMethod( osrfMethodContext* ctx, osrfMethod* method, jsonObject* resp ) { + if(!(ctx && resp)) return; + jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name)); + jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol)); + jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service)); + jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes)); + jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc)); + jsonObjectSetKey(resp, "params", jsonNewObject(method->paramNotes) ); + jsonObjectSetKey(resp, "sysmethod", jsonNewNumberObject(method->sysmethod) ); + jsonObjectSetClass(resp, "method"); +} + + int __osrfAppRunSystemMethod(osrfMethodContext* ctx) { OSRF_METHOD_VERIFY_CONTEXT(ctx); @@ -185,15 +258,39 @@ int __osrfAppRunSystemMethod(osrfMethodContext* ctx) { osrfMethod* method = app->methods; while(method) { resp = jsonNewObject(NULL); - jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name)); - jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol)); - jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service)); - jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes)); - jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc)); + __osrfAppSetIntrospectMethod( ctx, method, resp ); osrfAppRequestRespond(ctx->session, ctx->request, resp); - method = method->next; - jsonObjectSetClass(resp, "method"); jsonObjectFree(resp); + method = method->next; + } + return 1; + } + + return -1; + } + + + if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT )) { + + jsonObject* resp = NULL; + char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) ); + osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service ); + int len = 0; + + if(!methodSubstring) return 1; /* respond with no methods */ + + if(app) { + osrfMethod* method = app->methods; + while(method) { + if( (len = strlen(methodSubstring)) <= strlen(method->name) ) { + if( !strncmp( method->name, methodSubstring, len) ) { + resp = jsonNewObject(NULL); + __osrfAppSetIntrospectMethod( ctx, method, resp ); + osrfAppRequestRespond(ctx->session, ctx->request, resp); + jsonObjectFree(resp); + } + } + method = method->next; } return 1; } diff --git a/OpenSRF/src/libstack/osrf_application.h b/OpenSRF/src/libstack/osrf_application.h index 23e5a301bb..451450b146 100644 --- a/OpenSRF/src/libstack/osrf_application.h +++ b/OpenSRF/src/libstack/osrf_application.h @@ -1,4 +1,3 @@ - #include #include #include "opensrf/utils.h" @@ -7,10 +6,21 @@ #include "osrf_app_session.h" -/** - This macro verifies methods receive the correct parameters +/** + All OpenSRF methods take the signature + int methodName( osrfMethodContext* ); + If a negative number is returned, it means an unknown error occured and an exception + will be returned to the client automatically. + If a positive number is returned, it means that libopensrf should send a 'Request Complete' + message following any messages sent by the method. + If 0 is returned, it tells libopensrf that the method completed successfully and + there is no need to send any further data to the client. */ + + +/** + This macro verifies methods receive the correct parameters */ #define _OSRF_METHOD_VERIFY_CONTEXT(d) \ if(!d) return -1; \ if(!d->session) { osrfLog( OSRF_ERROR, "Session is NULL in app reqeust" ); return -1; }\ @@ -21,7 +31,6 @@ return -1; }\ if( !d->method->name ) { osrfLog(OSRF_ERROR, "Method name is NULL"); return -1; } - #ifdef OSRF_LOG_PARAMS #define OSRF_METHOD_VERIFY_CONTEXT(d) \ _OSRF_METHOD_VERIFY_CONTEXT(d); \ @@ -37,42 +46,54 @@ -#define OSRF_SYSMETHOD_INTROSPECT "opensrf.system.method" -#define OSRF_SYSMETHOD_INTROSPECT_ALL "opensrf.system.method.all" +/* used internally to make sure the method description provided is OK */ +#define OSRF_METHOD_VERIFY_DESCRIPTION(app, d) \ + if(!app) return -1; \ + if(!d) return -1;\ + if(!d->name) { osrfLog( OSRF_ERROR, "No method name provided in description" ), return -1; } \ + if(!d->symbol) { osrfLog( OSRF_ERROR, "No method symbol provided in description" ), return -1; } \ + if(!d->notes) d->notes = ""; \ + if(!d->paramNotes) d->paramNotes = "";\ + if(!d->returnNotes) d->returnNotes = ""; - + +/* Some well known parameters */ +#define OSRF_SYSMETHOD_INTROSPECT "opensrf.system.method" +#define OSRF_SYSMETHOD_INTROSPECT_ALL "opensrf.system.method.all" struct _osrfApplicationStruct { - char* name; /* the name of our application */ - void* handle; /* the lib handle */ - struct _osrfMethodStruct* methods; /* list of methods */ - struct _osrfApplicationStruct* next; /* next application */ + char* name; /* the name of our application */ + void* handle; /* the lib handle */ + struct _osrfMethodStruct* methods; /* list of methods */ + struct _osrfApplicationStruct* next; /* next application */ }; typedef struct _osrfApplicationStruct osrfApplication; struct _osrfMethodStruct { - char* name; /* the method name */ - char* symbol; /* the symbol name (function) */ - char* notes; /* public method documentation */ - int argc; /* how many args this method expects */ - void* methodHandle; /* cached version of the method handle */ - struct _osrfMethodStruct* next; + char* name; /* the method name */ + char* symbol; /* the symbol name (function) */ + char* notes; /* public method documentation */ + int argc; /* how many args this method expects */ + char* paramNotes; /* Description of the params expected for this method */ + struct _osrfMethodStruct* next; /* nest method in the list */ + int sysmethod; /* true if this is a system method */ }; typedef struct _osrfMethodStruct osrfMethod; struct _osrfMethodContextStruct { - osrfAppSession* session; - osrfMethod* method; - jsonObject* params; - int request; + osrfAppSession* session; /* the current session */ + osrfMethod* method; /* the requested method */ + jsonObject* params; /* the params to the method */ + int request; /* request id */ }; typedef struct _osrfMethodContextStruct osrfMethodContext; + /** Register an application @param appName The name of the application @@ -87,11 +108,28 @@ int osrfAppRegisterApplication( char* appName, char* soFile ); @param methodName The fully qualified name of the method @param symbolName The symbol name (function) that implements the method @param notes Public documentation for this method. + @params params String description description of the params expected @params argc The number of arguments this method expects @return 0 on success, -1 on error */ int osrfAppRegisterMethod( char* appName, - char* methodName, char* symbolName, char* notes, int argc ); + char* methodName, char* symbolName, char* notes, char* params, int argc ); + +int _osrfAppRegisterSystemMethod( char* appName, char* methodName, + char* notes, char* params, int argc ); + +osrfMethod* _osrfAppBuildMethod( char* methodName, + char* symbolName, char* notes, char* params, int argc, int sysmethod ); + +/** + Registher a method + @param appName The name of the application that implements the method + @params desc The method description + @return 0 on success, -1 on error + */ +/* +int osrfAppRegisterMethod( char* appName, osrfMethodDescription* desc ); +*/ /** Finds the given app in the list of apps @@ -136,9 +174,27 @@ int osrfAppRunMethod( char* appName, char* methodName, A system method is a well known method that all servers implement. @param context The current method context - @return 0 if the method is run, -1 otherwise + @return 0 if the method is run successfully, return < 0 means + the method was not run, return > 0 means the method was run + and the application code now needs to send a 'request complete' + message */ int __osrfAppRunSystemMethod(osrfMethodContext* context); +/** + Registers all of the system methods for this app so that they may be + treated the same as other methods */ +int __osrfAppRegisterSysMethods( char* app ); + + + +/** + Responds to the client with a method exception + @param ses The current session + @param request The request id + @param msg The debug message to send to the client + @return 0 on successfully sending of the message, -1 otherwise + */ +int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ); diff --git a/OpenSRF/src/libstack/osrf_cache.c b/OpenSRF/src/libstack/osrf_cache.c index f67641992e..df5199a3d0 100644 --- a/OpenSRF/src/libstack/osrf_cache.c +++ b/OpenSRF/src/libstack/osrf_cache.c @@ -35,7 +35,8 @@ int osrfCachePutObject( char* key, const jsonObject* obj, time_t seconds ) { if( !(key && obj) ) return -1; char* s = jsonObjectToJSON( obj ); if( seconds < 0 ) seconds = __osrfCacheMaxSeconds; - mc_add(__osrfCache, key, strlen(key), s, strlen(s), seconds, 0); + + mc_set(__osrfCache, key, strlen(key), s, strlen(s), seconds, 0); free(s); return 0; } @@ -43,7 +44,7 @@ int osrfCachePutObject( char* key, const jsonObject* obj, time_t seconds ) { int osrfCachePutString( char* key, const char* value, time_t seconds ) { if( !(key && value) ) return -1; if( seconds < 0 ) seconds = __osrfCacheMaxSeconds; - mc_add(__osrfCache, key, strlen(key), value, strlen(value), seconds, 0 ); + mc_set(__osrfCache, key, strlen(key), value, strlen(value), seconds, 0); return 0; } diff --git a/OpenSRF/src/libstack/osrf_message.c b/OpenSRF/src/libstack/osrf_message.c index 603f5a7c48..371bd7d1ed 100644 --- a/OpenSRF/src/libstack/osrf_message.c +++ b/OpenSRF/src/libstack/osrf_message.c @@ -33,16 +33,18 @@ void osrf_message_add_object_param( osrf_message* msg, jsonObject* o ) { void osrf_message_set_params( osrf_message* msg, jsonObject* o ) { if(!msg || !o) return; - if(!o->type == JSON_ARRAY) { - warning_handler("passing non-array to osrf_message_set_params()"); + if(o->type != JSON_ARRAY) { + warning_handler("passing non-array to osrf_message_set_params(), fixing..."); + jsonObject* clone = jsonObjectClone(o); + o = jsonNewObject(NULL); + jsonObjectPush(o, clone); + if(msg->_params) jsonObjectFree(msg->_params); + msg->_params = o; return; } if(msg->_params) jsonObjectFree(msg->_params); - - char* j = jsonObjectToJSON(o); - msg->_params = jsonParseString(j); - free(j); + msg->_params = jsonObjectClone(o); } -- 2.43.2