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, char* params, int argc, int streaming ) {
64 return _osrfAppRegisterMethod(appName, methodName,
65 symbolName, notes, params, argc, streaming, 0 );
68 int _osrfAppRegisterMethod( char* appName, char* methodName,
69 char* symbolName, char* notes, char* params, int argc, int streaming, int system ) {
71 if( !appName || ! methodName ) return -1;
73 osrfApplication* app = _osrfAppFindApplication(appName);
74 if(!app) return warning_handler("Unable to locate application %s", appName );
76 debug_handler("Registering method %s for app %s", methodName, appName );
78 osrfMethod* method = _osrfAppBuildMethod(
79 methodName, symbolName, notes, params, argc, system, 0 );
80 method->streaming = streaming;
82 /* plug the method into the list of methods */
83 osrfHashSet( app->methods, method, method->name );
85 if( streaming ) { /* build the atomic counterpart */
86 osrfMethod* atomicMethod = _osrfAppBuildMethod(
87 methodName, symbolName, notes, params, argc, system, 1 );
88 osrfHashSet( app->methods, atomicMethod, atomicMethod->name );
96 osrfMethod* _osrfAppBuildMethod( char* methodName,
97 char* symbolName, char* notes, char* params, int argc, int sysmethod, int atomic ) {
99 osrfMethod* method = safe_malloc(sizeof(osrfMethod));
101 if(methodName) method->name = strdup(methodName);
102 if(symbolName) method->symbol = strdup(symbolName);
103 if(notes) method->notes = strdup(notes);
104 if(params) method->paramNotes = strdup(params);
107 method->sysmethod = sysmethod;
108 method->atomic = atomic;
109 method->cachable = 0;
111 if(atomic) { /* add ".atomic" to the end of the name */
112 char mb[strlen(method->name) + 8];
113 sprintf(mb, "%s.atomic", method->name);
115 method->name = strdup(mb);
116 method->streaming = 1;
119 debug_handler("Built method %s", method->name );
125 int __osrfAppRegisterSysMethods( char* app ) {
127 _osrfAppRegisterMethod(
128 app, OSRF_SYSMETHOD_INTROSPECT, NULL,
129 "Return a list of methods whose names have the same initial "
130 "substring as that of the provided method name",
131 "( methodNameSubstring )", 1, 1 , 1);
133 _osrfAppRegisterMethod(
134 app, OSRF_SYSMETHOD_INTROSPECT_ALL, NULL,
135 "Returns a complete list of methods", "()", 0, 1, 1 );
137 _osrfAppRegisterMethod(
138 app, OSRF_SYSMETHOD_ECHO, NULL,
139 "Echos all data sent to the server back to the client",
140 "([a, b, ...])", 0, 1, 1);
145 osrfApplication* _osrfAppFindApplication( char* name ) {
146 if(!name) return NULL;
147 return (osrfApplication*) osrfHashGet(__osrfAppHash, name);
150 osrfMethod* __osrfAppFindMethod( osrfApplication* app, char* methodName ) {
151 if(!app || ! methodName) return NULL;
152 return (osrfMethod*) osrfHashGet( app->methods, methodName );
155 osrfMethod* _osrfAppFindMethod( char* appName, char* methodName ) {
156 if(!appName || ! methodName) return NULL;
157 return __osrfAppFindMethod( _osrfAppFindApplication(appName), methodName );
161 int osrfAppRunMethod( char* appName, char* methodName,
162 osrfAppSession* ses, int reqId, jsonObject* params ) {
164 if( !(appName && methodName && ses) ) return -1;
167 osrfApplication* app;
169 osrfMethodContext context;
171 context.session = ses;
172 context.params = params;
173 context.request = reqId;
174 context.responses = NULL;
176 /* this is the method we're gonna run */
177 int (*meth) (osrfMethodContext*);
179 info_handler("Running method [%s] for app [%s] with request id %d and "
180 "thread trace %s", methodName, appName, reqId, ses->session_id );
182 if( !(app = _osrfAppFindApplication(appName)) )
183 return osrfAppRequestRespondException( ses,
184 reqId, "Application not found: %s", appName );
186 if( !(method = __osrfAppFindMethod( app, methodName )) )
187 return osrfAppRequestRespondException( ses, reqId,
188 "Method [%s] not found for service %s", methodName, appName );
190 context.method = method;
192 #ifdef OSRF_STRICT_PARAMS
193 if( method->argc > 0 ) {
194 if(!params || params->type != JSON_ARRAY || params->size < method->argc )
195 return osrfAppRequestRespondException( ses, reqId,
196 "Not enough params for method %s / service %s", methodName, appName );
202 if( method->sysmethod ) {
203 retcode = __osrfAppRunSystemMethod(&context);
207 /* open and now run the method */
208 *(void **) (&meth) = dlsym(app->handle, method->symbol);
210 if( (error = dlerror()) != NULL ) {
211 return osrfAppRequestRespondException( ses, reqId,
212 "Unable to execute method [%s] for service %s", methodName, appName );
215 retcode = (*meth) (&context);
219 return osrfAppRequestRespondException(
220 ses, reqId, "An unknown server error occurred" );
222 return __osrfAppPostProcess( &context, retcode );
227 int osrfAppRespond( osrfMethodContext* ctx, jsonObject* data ) {
228 return _osrfAppRespond( ctx, data, 0 );
231 int osrfAppRespondComplete( osrfMethodContext* context, jsonObject* data ) {
232 return _osrfAppRespond( context, data, 1 );
235 int _osrfAppRespond( osrfMethodContext* ctx, jsonObject* data, int complete ) {
236 if(!(ctx && ctx->method)) return -1;
238 if( ctx->method->atomic ) {
240 "Adding responses to stash for atomic method %s", ctx->method );
242 if( ctx->responses == NULL )
243 ctx->responses = jsonParseString("[]");
244 jsonObjectPush( ctx->responses, jsonObjectClone(data) );
248 if( !ctx->method->atomic && ! ctx->method->cachable ) {
250 osrfAppRequestRespondComplete( ctx->session, ctx->request, data );
252 osrfAppRequestRespond( ctx->session, ctx->request, data );
262 int __osrfAppPostProcess( osrfMethodContext* ctx, int retcode ) {
263 if(!(ctx && ctx->method)) return -1;
265 osrfLog( OSRF_DEBUG, "Postprocessing method %s with retcode %d",
266 ctx->method->name, retcode );
268 if(ctx->responses) { /* we have cached responses to return */
270 osrfAppRequestRespondComplete( ctx->session, ctx->request, ctx->responses );
271 jsonObjectFree(ctx->responses);
272 ctx->responses = NULL;
277 osrfAppSessionStatus( ctx->session, OSRF_STATUS_COMPLETE,
278 "osrfConnectStatus", ctx->request, "Request Complete" );
285 int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) {
288 VA_LIST_TO_STRING(msg);
289 osrfLog( OSRF_WARN, "Returning method exception with message: %s", VA_BUF );
290 osrfAppSessionStatus( ses, OSRF_STATUS_NOTFOUND, "osrfMethodException", request, VA_BUF );
295 static void __osrfAppSetIntrospectMethod( osrfMethodContext* ctx, osrfMethod* method, jsonObject* resp ) {
296 if(!(ctx && resp)) return;
297 jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name));
298 jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol));
299 jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service));
300 jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes));
301 jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc));
302 jsonObjectSetKey(resp, "params", jsonNewObject(method->paramNotes) );
303 jsonObjectSetKey(resp, "sysmethod", jsonNewNumberObject(method->sysmethod) );
304 jsonObjectSetKey(resp, "atomic", jsonNewNumberObject(method->atomic) );
305 jsonObjectSetKey(resp, "cachable", jsonNewNumberObject(method->cachable) );
306 jsonObjectSetClass(resp, "method");
311 int __osrfAppRunSystemMethod(osrfMethodContext* ctx) {
312 OSRF_METHOD_VERIFY_CONTEXT(ctx);
314 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL ) ||
315 !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC )) {
317 return osrfAppIntrospectAll(ctx);
321 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT ) ||
322 !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ATOMIC )) {
324 return osrfAppIntrospect(ctx);
327 osrfAppRequestRespondException( ctx->session,
328 ctx->request, "System method implementation not found");
334 int osrfAppIntrospect( osrfMethodContext* ctx ) {
336 jsonObject* resp = NULL;
337 char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
338 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
341 if(!methodSubstring) return 1; /* respond with no methods */
345 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
348 while( (method = osrfHashIteratorNext(itr)) ) {
349 if( (len = strlen(methodSubstring)) <= strlen(method->name) ) {
350 if( !strncmp( method->name, methodSubstring, len) ) {
351 resp = jsonNewObject(NULL);
352 __osrfAppSetIntrospectMethod( ctx, method, resp );
353 osrfAppRespond(ctx, resp);
354 jsonObjectFree(resp);
358 osrfHashIteratorFree(itr);
367 int osrfAppIntrospectAll( osrfMethodContext* ctx ) {
368 jsonObject* resp = NULL;
369 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
372 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
374 while( (method = osrfHashIteratorNext(itr)) ) {
375 resp = jsonNewObject(NULL);
376 __osrfAppSetIntrospectMethod( ctx, method, resp );
377 osrfAppRespond(ctx, resp);
378 jsonObjectFree(resp);
380 osrfHashIteratorFree(itr);