1 #include "osrf_application.h"
3 #include "objson/object.h"
5 //osrfApplication* __osrfAppList = NULL;
7 osrfHash* __osrfAppHash = NULL;
10 int osrfAppRegisterApplication( char* appName, char* soFile ) {
11 if(!appName || ! soFile) return -1;
14 if(!__osrfAppHash) __osrfAppHash = osrfNewHash();
16 info_handler("Registering application %s with file %s", appName, soFile );
18 osrfApplication* app = safe_malloc(sizeof(osrfApplication));
19 app->handle = dlopen (soFile, RTLD_NOW);
22 warning_handler("Failed to dlopen library file %s: %s", soFile, dlerror() );
23 dlerror(); /* clear the error */
28 app->methods = osrfNewHash();
29 osrfHashSet( __osrfAppHash, app, appName );
31 /* see if we can run the initialize method */
33 *(void **) (&init) = dlsym(app->handle, "osrfAppInitialize");
35 if( (error = dlerror()) != NULL ) {
36 warning_handler("! Unable to locate method symbol [osrfAppInitialize] for app %s: %s", appName, error );
42 if( (ret = (*init)()) ) {
43 warning_handler("Application %s returned non-zero value from "
44 "'osrfAppInitialize', not registering...", appName );
45 //free(app->name); /* need a method to remove an application from the list */
51 __osrfAppRegisterSysMethods(appName);
53 info_handler("Application %s registered successfully", appName );
61 int osrfAppRegisterMethod( char* appName, char* methodName,
62 char* symbolName, char* notes, int argc, int options ) {
64 if( !appName || ! methodName ) return -1;
66 osrfApplication* app = _osrfAppFindApplication(appName);
67 if(!app) return warning_handler("Unable to locate application %s", appName );
69 debug_handler("Registering method %s for app %s", methodName, appName );
71 osrfMethod* method = _osrfAppBuildMethod(
72 methodName, symbolName, notes, argc, options );
73 method->options = options;
75 /* plug the method into the list of methods */
76 osrfHashSet( app->methods, method, method->name );
78 if( options & OSRF_METHOD_STREAMING ) { /* build the atomic counterpart */
79 int newops = options | OSRF_METHOD_ATOMIC;
80 osrfMethod* atomicMethod = _osrfAppBuildMethod(
81 methodName, symbolName, notes, argc, newops );
82 osrfHashSet( app->methods, atomicMethod, atomicMethod->name );
90 osrfMethod* _osrfAppBuildMethod( char* methodName,
91 char* symbolName, char* notes, int argc, int options ) {
93 osrfMethod* method = safe_malloc(sizeof(osrfMethod));
95 if(methodName) method->name = strdup(methodName);
96 if(symbolName) method->symbol = strdup(symbolName);
97 if(notes) method->notes = strdup(notes);
100 method->options = options;
102 if(options & OSRF_METHOD_ATOMIC) { /* add ".atomic" to the end of the name */
103 char mb[strlen(method->name) + 8];
104 sprintf(mb, "%s.atomic", method->name);
106 method->name = strdup(mb);
107 method->options |= OSRF_METHOD_STREAMING;
114 int __osrfAppRegisterSysMethods( char* app ) {
116 osrfAppRegisterMethod(
117 app, OSRF_SYSMETHOD_INTROSPECT, NULL,
118 "Return a list of methods whose names have the same initial "
119 "substring as that of the provided method name PARAMS( methodNameSubstring )",
120 1, OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
122 osrfAppRegisterMethod(
123 app, OSRF_SYSMETHOD_INTROSPECT_ALL, NULL,
124 "Returns a complete list of methods. PARAMS()", 0,
125 OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
127 osrfAppRegisterMethod(
128 app, OSRF_SYSMETHOD_ECHO, NULL,
129 "Echos all data sent to the server back to the client. PARAMS([a, b, ...])", 0,
130 OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
135 osrfApplication* _osrfAppFindApplication( char* name ) {
136 if(!name) return NULL;
137 return (osrfApplication*) osrfHashGet(__osrfAppHash, name);
140 osrfMethod* __osrfAppFindMethod( osrfApplication* app, char* methodName ) {
141 if(!app || ! methodName) return NULL;
142 return (osrfMethod*) osrfHashGet( app->methods, methodName );
145 osrfMethod* _osrfAppFindMethod( char* appName, char* methodName ) {
146 if(!appName || ! methodName) return NULL;
147 return __osrfAppFindMethod( _osrfAppFindApplication(appName), methodName );
151 int osrfAppRunMethod( char* appName, char* methodName,
152 osrfAppSession* ses, int reqId, jsonObject* params ) {
154 if( !(appName && methodName && ses) ) return -1;
157 osrfApplication* app;
159 osrfMethodContext context;
161 context.session = ses;
162 context.params = params;
163 context.request = reqId;
164 context.responses = NULL;
166 /* this is the method we're gonna run */
167 int (*meth) (osrfMethodContext*);
169 info_handler("Running method [%s] for app [%s] with request id %d and "
170 "thread trace %s", methodName, appName, reqId, ses->session_id );
172 if( !(app = _osrfAppFindApplication(appName)) )
173 return osrfAppRequestRespondException( ses,
174 reqId, "Application not found: %s", appName );
176 if( !(method = __osrfAppFindMethod( app, methodName )) )
177 return osrfAppRequestRespondException( ses, reqId,
178 "Method [%s] not found for service %s", methodName, appName );
180 context.method = method;
182 #ifdef OSRF_STRICT_PARAMS
183 if( method->argc > 0 ) {
184 if(!params || params->type != JSON_ARRAY || params->size < method->argc )
185 return osrfAppRequestRespondException( ses, reqId,
186 "Not enough params for method %s / service %s", methodName, appName );
192 if( method->options & OSRF_METHOD_SYSTEM ) {
193 retcode = __osrfAppRunSystemMethod(&context);
197 /* open and now run the method */
198 *(void **) (&meth) = dlsym(app->handle, method->symbol);
200 if( (error = dlerror()) != NULL ) {
201 return osrfAppRequestRespondException( ses, reqId,
202 "Unable to execute method [%s] for service %s", methodName, appName );
205 retcode = (*meth) (&context);
209 return osrfAppRequestRespondException(
210 ses, reqId, "An unknown server error occurred" );
212 return __osrfAppPostProcess( &context, retcode );
217 int osrfAppRespond( osrfMethodContext* ctx, jsonObject* data ) {
218 return _osrfAppRespond( ctx, data, 0 );
221 int osrfAppRespondComplete( osrfMethodContext* context, jsonObject* data ) {
222 return _osrfAppRespond( context, data, 1 );
225 int _osrfAppRespond( osrfMethodContext* ctx, jsonObject* data, int complete ) {
226 if(!(ctx && ctx->method)) return -1;
228 if( ctx->method->options & OSRF_METHOD_ATOMIC ) {
230 "Adding responses to stash for atomic method %s", ctx->method );
232 if( ctx->responses == NULL )
233 ctx->responses = jsonParseString("[]");
234 jsonObjectPush( ctx->responses, jsonObjectClone(data) );
238 if( !(ctx->method->options & OSRF_METHOD_ATOMIC) &&
239 !(ctx->method->options & OSRF_METHOD_CACHABLE) ) {
242 osrfAppRequestRespondComplete( ctx->session, ctx->request, data );
244 osrfAppRequestRespond( ctx->session, ctx->request, data );
254 int __osrfAppPostProcess( osrfMethodContext* ctx, int retcode ) {
255 if(!(ctx && ctx->method)) return -1;
257 osrfLog( OSRF_DEBUG, "Postprocessing method %s with retcode %d",
258 ctx->method->name, retcode );
260 if(ctx->responses) { /* we have cached responses to return (no responses have been sent) */
262 osrfAppRequestRespondComplete( ctx->session, ctx->request, ctx->responses );
263 jsonObjectFree(ctx->responses);
264 ctx->responses = NULL;
269 osrfAppSessionStatus( ctx->session, OSRF_STATUS_COMPLETE,
270 "osrfConnectStatus", ctx->request, "Request Complete" );
277 int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) {
280 VA_LIST_TO_STRING(msg);
281 osrfLog( OSRF_WARN, "Returning method exception with message: %s", VA_BUF );
282 osrfAppSessionStatus( ses, OSRF_STATUS_NOTFOUND, "osrfMethodException", request, VA_BUF );
287 static void __osrfAppSetIntrospectMethod( osrfMethodContext* ctx, osrfMethod* method, jsonObject* resp ) {
288 if(!(ctx && resp)) return;
290 jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name));
291 jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol));
292 jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service));
293 jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes));
294 jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc));
296 jsonObjectSetKey(resp, "sysmethod",
297 jsonNewNumberObject( (method->options & OSRF_METHOD_SYSTEM) ? 1 : 0 ));
298 jsonObjectSetKey(resp, "atomic",
299 jsonNewNumberObject( (method->options & OSRF_METHOD_ATOMIC) ? 1 : 0 ));
300 jsonObjectSetKey(resp, "cachable",
301 jsonNewNumberObject( (method->options & OSRF_METHOD_CACHABLE) ? 1 : 0 ));
303 jsonObjectSetClass(resp, "method");
308 int __osrfAppRunSystemMethod(osrfMethodContext* ctx) {
309 OSRF_METHOD_VERIFY_CONTEXT(ctx);
311 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL ) ||
312 !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC )) {
314 return osrfAppIntrospectAll(ctx);
318 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT ) ||
319 !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ATOMIC )) {
321 return osrfAppIntrospect(ctx);
324 osrfAppRequestRespondException( ctx->session,
325 ctx->request, "System method implementation not found");
331 int osrfAppIntrospect( osrfMethodContext* ctx ) {
333 jsonObject* resp = NULL;
334 char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
335 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
338 if(!methodSubstring) return 1; /* respond with no methods */
342 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
345 while( (method = osrfHashIteratorNext(itr)) ) {
346 if( (len = strlen(methodSubstring)) <= strlen(method->name) ) {
347 if( !strncmp( method->name, methodSubstring, len) ) {
348 resp = jsonNewObject(NULL);
349 __osrfAppSetIntrospectMethod( ctx, method, resp );
350 osrfAppRespond(ctx, resp);
351 jsonObjectFree(resp);
355 osrfHashIteratorFree(itr);
364 int osrfAppIntrospectAll( osrfMethodContext* ctx ) {
365 jsonObject* resp = NULL;
366 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
369 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
371 while( (method = osrfHashIteratorNext(itr)) ) {
372 resp = jsonNewObject(NULL);
373 __osrfAppSetIntrospectMethod( ctx, method, resp );
374 osrfAppRespond(ctx, resp);
375 jsonObjectFree(resp);
377 osrfHashIteratorFree(itr);