1 #include <opensrf/osrf_application.h>
3 osrfHash* __osrfAppHash = NULL;
5 int osrfAppRegisterApplication( char* appName, char* soFile ) {
6 if(!appName || ! soFile) return -1;
9 if(!__osrfAppHash) __osrfAppHash = osrfNewHash();
11 osrfLogInfo( OSRF_LOG_MARK, "Registering application %s with file %s", appName, soFile );
13 osrfApplication* app = safe_malloc(sizeof(osrfApplication));
14 app->handle = dlopen (soFile, RTLD_NOW);
18 osrfLogWarning( OSRF_LOG_MARK, "Failed to dlopen library file %s: %s", soFile, dlerror() );
19 dlerror(); /* clear the error */
24 app->methods = osrfNewHash();
25 osrfHashSet( __osrfAppHash, app, appName );
27 /* see if we can run the initialize method */
29 *(void **) (&init) = dlsym(app->handle, "osrfAppInitialize");
31 if( (error = dlerror()) != NULL ) {
32 osrfLogWarning( OSRF_LOG_MARK,
33 "! Unable to locate method symbol [osrfAppInitialize] for app %s: %s", appName, error );
39 if( (ret = (*init)()) ) {
40 osrfLogWarning( OSRF_LOG_MARK, "Application %s returned non-zero value from "
41 "'osrfAppInitialize', not registering...", appName );
42 //free(app->name); /* need a method to remove an application from the list */
48 __osrfAppRegisterSysMethods(appName);
50 osrfLogInfo( OSRF_LOG_MARK, "Application %s registered successfully", appName );
52 osrfLogSetAppname(appName);
54 osrfAppSetOnExit(app, appName);
60 void osrfAppSetOnExit(osrfApplication* app, char* appName) {
61 if(!(app && appName)) return;
63 /* see if we can run the initialize method */
65 void (*onExit) (void);
66 *(void **) (&onExit) = dlsym(app->handle, "osrfAppChildExit");
68 if( (error = dlerror()) != NULL ) {
69 osrfLogDebug(OSRF_LOG_MARK, "No exit handler defined for %s", appName);
73 osrfLogInfo(OSRF_LOG_MARK, "registering exit handler for %s", appName);
74 app->onExit = (*onExit);
75 //if( (ret = (*onExit)()) ) {
79 int osrfAppRunChildInit(char* appname) {
80 osrfApplication* app = _osrfAppFindApplication(appname);
85 int (*childInit) (void);
87 *(void**) (&childInit) = dlsym(app->handle, "osrfAppChildInit");
89 if( (error = dlerror()) != NULL ) {
90 osrfLogInfo( OSRF_LOG_MARK, "No child init defined for app %s : %s", appname, error);
94 if( (ret = (*childInit)()) ) {
95 osrfLogError(OSRF_LOG_MARK, "App %s child init failed", appname);
99 osrfLogInfo(OSRF_LOG_MARK, "%s child init succeeded", appname);
104 void osrfAppRunExitCode() {
105 osrfHashIterator* itr = osrfNewHashIterator(__osrfAppHash);
106 osrfApplication* app;
107 while( (app = osrfHashIteratorNext(itr)) ) {
109 osrfLogInfo(OSRF_LOG_MARK, "Running onExit handler for app %s", itr->current);
116 int osrfAppRegisterMethod( char* appName, char* methodName,
117 char* symbolName, char* notes, int argc, int options ) {
119 return osrfAppRegisterExtendedMethod(
131 int osrfAppRegisterExtendedMethod( char* appName, char* methodName,
132 char* symbolName, char* notes, int argc, int options, void * user_data ) {
134 if( !appName || ! methodName ) return -1;
136 osrfApplication* app = _osrfAppFindApplication(appName);
138 osrfLogWarning( OSRF_LOG_MARK, "Unable to locate application %s", appName );
142 osrfLogDebug( OSRF_LOG_MARK, "Registering method %s for app %s", methodName, appName );
144 osrfMethod* method = _osrfAppBuildMethod(
145 methodName, symbolName, notes, argc, options, user_data );
146 method->options = options;
148 /* plug the method into the list of methods */
149 osrfHashSet( app->methods, method, method->name );
151 if( options & OSRF_METHOD_STREAMING ) { /* build the atomic counterpart */
152 int newops = options | OSRF_METHOD_ATOMIC;
153 osrfMethod* atomicMethod = _osrfAppBuildMethod(
154 methodName, symbolName, notes, argc, newops, NULL );
155 osrfHashSet( app->methods, atomicMethod, atomicMethod->name );
156 atomicMethod->userData = method->userData;
164 osrfMethod* _osrfAppBuildMethod( char* methodName,
165 char* symbolName, char* notes, int argc, int options, void* user_data ) {
167 osrfMethod* method = safe_malloc(sizeof(osrfMethod));
169 if(methodName) method->name = strdup(methodName);
170 if(symbolName) method->symbol = strdup(symbolName);
171 if(notes) method->notes = strdup(notes);
172 if(user_data) method->userData = user_data;
175 method->options = options;
177 if(options & OSRF_METHOD_ATOMIC) { /* add ".atomic" to the end of the name */
178 char mb[strlen(method->name) + 8];
179 sprintf(mb, "%s.atomic", method->name);
181 method->name = strdup(mb);
182 method->options |= OSRF_METHOD_STREAMING;
189 int __osrfAppRegisterSysMethods( char* app ) {
191 osrfAppRegisterMethod(
192 app, OSRF_SYSMETHOD_INTROSPECT, NULL,
193 "Return a list of methods whose names have the same initial "
194 "substring as that of the provided method name PARAMS( methodNameSubstring )",
195 1, OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
197 osrfAppRegisterMethod(
198 app, OSRF_SYSMETHOD_INTROSPECT_ALL, NULL,
199 "Returns a complete list of methods. PARAMS()", 0,
200 OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
202 osrfAppRegisterMethod(
203 app, OSRF_SYSMETHOD_ECHO, NULL,
204 "Echos all data sent to the server back to the client. PARAMS([a, b, ...])", 0,
205 OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
210 osrfApplication* _osrfAppFindApplication( char* name ) {
211 if(!name) return NULL;
212 return (osrfApplication*) osrfHashGet(__osrfAppHash, name);
215 osrfMethod* __osrfAppFindMethod( osrfApplication* app, char* methodName ) {
216 if(!app || ! methodName) return NULL;
217 return (osrfMethod*) osrfHashGet( app->methods, methodName );
220 osrfMethod* _osrfAppFindMethod( char* appName, char* methodName ) {
221 if(!appName || ! methodName) return NULL;
222 return __osrfAppFindMethod( _osrfAppFindApplication(appName), methodName );
226 int osrfAppRunMethod( char* appName, char* methodName,
227 osrfAppSession* ses, int reqId, jsonObject* params ) {
229 if( !(appName && methodName && ses) ) return -1;
232 osrfApplication* app;
234 osrfMethodContext context;
236 context.session = ses;
237 context.params = params;
238 context.request = reqId;
239 context.responses = NULL;
241 /* this is the method we're gonna run */
242 int (*meth) (osrfMethodContext*);
244 if( !(app = _osrfAppFindApplication(appName)) )
245 return osrfAppRequestRespondException( ses,
246 reqId, "Application not found: %s", appName );
248 if( !(method = __osrfAppFindMethod( app, methodName )) )
249 return osrfAppRequestRespondException( ses, reqId,
250 "Method [%s] not found for service %s", methodName, appName );
252 context.method = method;
254 #ifdef OSRF_STRICT_PARAMS
255 if( method->argc > 0 ) {
256 if(!params || params->type != JSON_ARRAY || params->size < method->argc )
257 return osrfAppRequestRespondException( ses, reqId,
258 "Not enough params for method %s / service %s", methodName, appName );
264 if( method->options & OSRF_METHOD_SYSTEM ) {
265 retcode = __osrfAppRunSystemMethod(&context);
269 /* open and now run the method */
270 *(void **) (&meth) = dlsym(app->handle, method->symbol);
272 if( (error = dlerror()) != NULL ) {
273 return osrfAppRequestRespondException( ses, reqId,
274 "Unable to execute method [%s] for service %s", methodName, appName );
277 retcode = (*meth) (&context);
281 return osrfAppRequestRespondException(
282 ses, reqId, "An unknown server error occurred" );
284 return __osrfAppPostProcess( &context, retcode );
289 int osrfAppRespond( osrfMethodContext* ctx, jsonObject* data ) {
290 return _osrfAppRespond( ctx, data, 0 );
293 int osrfAppRespondComplete( osrfMethodContext* context, jsonObject* data ) {
294 return _osrfAppRespond( context, data, 1 );
297 int _osrfAppRespond( osrfMethodContext* ctx, jsonObject* data, int complete ) {
298 if(!(ctx && ctx->method)) return -1;
300 if( ctx->method->options & OSRF_METHOD_ATOMIC ) {
301 osrfLogDebug( OSRF_LOG_MARK,
302 "Adding responses to stash for atomic method %s", ctx->method->name );
304 if( ctx->responses == NULL )
305 ctx->responses = jsonParseString("[]");
308 jsonObjectPush( ctx->responses, jsonObjectClone(data) );
312 if( !(ctx->method->options & OSRF_METHOD_ATOMIC) &&
313 !(ctx->method->options & OSRF_METHOD_CACHABLE) ) {
316 osrfAppRequestRespondComplete( ctx->session, ctx->request, data );
318 osrfAppRequestRespond( ctx->session, ctx->request, data );
328 int __osrfAppPostProcess( osrfMethodContext* ctx, int retcode ) {
329 if(!(ctx && ctx->method)) return -1;
331 osrfLogDebug( OSRF_LOG_MARK, "Postprocessing method %s with retcode %d",
332 ctx->method->name, retcode );
334 if(ctx->responses) { /* we have cached responses to return (no responses have been sent) */
336 osrfAppRequestRespondComplete( ctx->session, ctx->request, ctx->responses );
337 jsonObjectFree(ctx->responses);
338 ctx->responses = NULL;
343 osrfAppSessionStatus( ctx->session, OSRF_STATUS_COMPLETE,
344 "osrfConnectStatus", ctx->request, "Request Complete" );
350 int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) {
353 VA_LIST_TO_STRING(msg);
354 osrfLogWarning( OSRF_LOG_MARK, "Returning method exception with message: %s", VA_BUF );
355 osrfAppSessionStatus( ses, OSRF_STATUS_NOTFOUND, "osrfMethodException", request, VA_BUF );
360 static void __osrfAppSetIntrospectMethod( osrfMethodContext* ctx, osrfMethod* method, jsonObject* resp ) {
361 if(!(ctx && resp)) return;
363 jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name));
364 jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol));
365 jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service));
366 jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes));
367 jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc));
369 jsonObjectSetKey(resp, "sysmethod",
370 jsonNewNumberObject( (method->options & OSRF_METHOD_SYSTEM) ? 1 : 0 ));
371 jsonObjectSetKey(resp, "atomic",
372 jsonNewNumberObject( (method->options & OSRF_METHOD_ATOMIC) ? 1 : 0 ));
373 jsonObjectSetKey(resp, "cachable",
374 jsonNewNumberObject( (method->options & OSRF_METHOD_CACHABLE) ? 1 : 0 ));
376 jsonObjectSetClass(resp, "method");
381 int __osrfAppRunSystemMethod(osrfMethodContext* ctx) {
382 OSRF_METHOD_VERIFY_CONTEXT(ctx);
384 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL ) ||
385 !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC )) {
387 return osrfAppIntrospectAll(ctx);
391 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT ) ||
392 !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ATOMIC )) {
394 return osrfAppIntrospect(ctx);
397 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_ECHO ) ||
398 !strcmp(ctx->method->name, OSRF_SYSMETHOD_ECHO_ATOMIC )) {
400 return osrfAppEcho(ctx);
404 osrfAppRequestRespondException( ctx->session,
405 ctx->request, "System method implementation not found");
411 int osrfAppIntrospect( osrfMethodContext* ctx ) {
413 jsonObject* resp = NULL;
414 char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
415 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
418 if(!methodSubstring) return 1; /* respond with no methods */
422 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
425 while( (method = osrfHashIteratorNext(itr)) ) {
426 if( (len = strlen(methodSubstring)) <= strlen(method->name) ) {
427 if( !strncmp( method->name, methodSubstring, len) ) {
428 resp = jsonNewObject(NULL);
429 __osrfAppSetIntrospectMethod( ctx, method, resp );
430 osrfAppRespond(ctx, resp);
431 jsonObjectFree(resp);
435 osrfHashIteratorFree(itr);
444 int osrfAppIntrospectAll( osrfMethodContext* ctx ) {
445 jsonObject* resp = NULL;
446 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
449 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
451 while( (method = osrfHashIteratorNext(itr)) ) {
452 resp = jsonNewObject(NULL);
453 __osrfAppSetIntrospectMethod( ctx, method, resp );
454 osrfAppRespond(ctx, resp);
455 jsonObjectFree(resp);
457 osrfHashIteratorFree(itr);
464 int osrfAppEcho( osrfMethodContext* ctx ) {
465 OSRF_METHOD_VERIFY_CONTEXT(ctx);
467 for( i = 0; i < ctx->params->size; i++ ) {
468 jsonObject* str = jsonObjectGetIndex(ctx->params,i);
469 osrfAppRespond(ctx, str);