e91920869d7f52ede8c60c467876e3f0be3bc23d
[working/Evergreen.git] / OpenSRF / src / libstack / osrf_application.c
1 #include "osrf_application.h"
2 #include "osrf_log.h"
3 #include "objson/object.h"
4
5 osrfApplication* __osrfAppList = NULL; 
6
7
8 int osrfAppRegisterApplication( char* appName, char* soFile ) {
9         if(!appName || ! soFile) return -1;
10         char* error;
11
12         info_handler("Registering application %s with file %s", appName, soFile );
13
14         osrfApplication* app = safe_malloc(sizeof(osrfApplication));
15         app->handle = dlopen (soFile, RTLD_NOW);
16
17         if(!app->handle) {
18                 warning_handler("Failed to dlopen library file %s: %s", soFile, dlerror() );
19                 dlerror(); /* clear the error */
20                 free(app);
21                 return -1;
22         }
23
24         app->name = strdup(appName);
25
26         /* this has to be done before initting the application */
27         app->next = __osrfAppList;
28         __osrfAppList = app;
29
30
31         /* see if we can run the initialize method */
32         int (*init) (void);
33         *(void **) (&init) = dlsym(app->handle, "osrfAppInitialize");
34
35         if( (error = dlerror()) != NULL ) {
36                 warning_handler("! Unable to locate method symbol [osrfAppInitialize] for app %s: %s", appName, error );
37
38         } else {
39
40                 /* run the method */
41                 int ret;
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 */
46                         //free(app);
47                         return ret;
48                 }
49         }
50
51         __osrfAppRegisterSysMethods(appName);
52
53         info_handler("Application %s registered successfully", appName );
54
55
56         return 0;
57 }
58
59 int osrfAppRegisterMethod( char* appName, 
60                 char* methodName, char* symbolName, char* notes, char* params, int argc ) {
61
62         if( !appName || ! methodName || ! symbolName ) return -1;
63
64         osrfApplication* app = _osrfAppFindApplication(appName);
65         if(!app) return warning_handler("Unable to locate application %s", appName );
66
67         debug_handler("Registering method %s for app %s", methodName, appName );
68
69         osrfMethod* method = _osrfAppBuildMethod(
70                 methodName, symbolName, notes, params, argc, 0 );               
71
72         /* plug the method into the list of methods */
73         method->next = app->methods;
74         app->methods = method;
75         return 0;
76 }
77
78
79 osrfMethod* _osrfAppBuildMethod( char* methodName, 
80         char* symbolName, char* notes, char* params, int argc, int sysmethod ) {
81
82         osrfMethod* method                                      = safe_malloc(sizeof(osrfMethod));
83         if(methodName) method->name             = strdup(methodName);
84         if(symbolName) method->symbol           = strdup(symbolName);
85         if(notes) method->notes                         = strdup(notes);
86         if(params) method->paramNotes           = strdup(params);
87         method->argc                                                    = argc;
88         method->sysmethod                                               = sysmethod;
89         return method;
90 }
91
92
93 int _osrfAppRegisterSystemMethod( char* appName, char* methodName, 
94                 char* notes, char* params, int argc ) {
95         if(!(appName && methodName)) return -1;
96         osrfApplication* app = _osrfAppFindApplication(appName);
97         if(!app) return warning_handler("Unable to locate application %s", appName );
98         debug_handler("Registering system method %s for app %s", methodName, appName );
99         osrfMethod* method = _osrfAppBuildMethod(
100                 methodName, NULL, notes, params, argc, 1 );             
101
102         /* plug the method into the list of methods */
103         method->next = app->methods;
104         app->methods = method;
105         return 0;
106
107 }
108
109 int __osrfAppRegisterSysMethods( char* app ) {
110
111         _osrfAppRegisterSystemMethod( 
112                         app, OSRF_SYSMETHOD_INTROSPECT, 
113                         "Return a list of methods whose names have the same initial "
114                         "substring as that of the provided method name",
115                         "( methodNameSubstring )", 1 );
116
117         _osrfAppRegisterSystemMethod( 
118                         app, OSRF_SYSMETHOD_INTROSPECT_ALL, 
119                         "Returns a complete list of methods", "()", 0 ); 
120
121         return 0;
122 }
123
124 osrfApplication* _osrfAppFindApplication( char* name ) {
125         if(!name) return NULL;
126         osrfApplication* app = __osrfAppList;
127         while(app) {
128                 if(!strcmp(app->name, name))
129                         return app;
130                 app = app->next;
131         }
132         return NULL;
133 }
134
135 osrfMethod* __osrfAppFindMethod( osrfApplication* app, char* methodName ) {
136         if(!app || ! methodName) return NULL;
137         osrfMethod* method = app->methods;
138         while(method) {
139                 if(!strcmp(method->name, methodName))
140                         return method;
141                 method = method->next;
142         }
143         return NULL;
144 }
145
146 osrfMethod* _osrfAppFindMethod( char* appName, char* methodName ) {
147         if(!appName || ! methodName) return NULL;
148         return __osrfAppFindMethod( _osrfAppFindApplication(appName), methodName );
149 }
150
151
152 int osrfAppRunMethod( char* appName, char* methodName, 
153                 osrfAppSession* ses, int reqId, jsonObject* params ) {
154
155         if( !(appName && methodName && ses) ) return -1;
156
157         char* error;
158         osrfApplication* app;
159         osrfMethod* method;
160         osrfMethodContext context;
161
162         context.session = ses;
163         context.params = params;
164         context.request = reqId;
165
166         /* this is the method we're gonna run */
167         int (*meth) (osrfMethodContext*);       
168
169         info_handler("Running method [%s] for app [%s] with request id %d and "
170                         "thread trace %s", methodName, appName, reqId, ses->session_id );
171
172         if( !(app = _osrfAppFindApplication(appName)) )
173                 return osrfAppRequestRespondException( ses, 
174                                 reqId, "Application not found: %s", appName );
175         
176         if( !(method = __osrfAppFindMethod( app, methodName )) ) 
177                 return osrfAppRequestRespondException( ses, reqId, 
178                                 "Method [%s] not found for service %s", methodName, appName );
179
180         context.method = method;
181
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 );
187         }
188         #endif
189
190         if( method->sysmethod ) {
191
192                 int sysres = __osrfAppRunSystemMethod(&context);
193                 if(sysres == 0) return 0;
194
195                 if(sysres > 0) 
196                         return osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE,  
197                                         "osrfConnectStatus", reqId, "Request Complete" );
198
199                 if(sysres < 0) 
200                         return osrfAppRequestRespondException( 
201                                 ses, reqId, "An unknown server error occurred" );
202         }
203
204
205         /* open the method */
206         *(void **) (&meth) = dlsym(app->handle, method->symbol);
207
208         if( (error = dlerror()) != NULL ) {
209                 return osrfAppRequestRespondException( ses, reqId, 
210                                 "Unable to execute method [%s]  for service %s", methodName, appName );
211         }
212
213         /* run the method */
214         int ret;
215         if( (ret = (*meth) (&context)) < 0 )
216                 return osrfAppRequestRespondException( 
217                                 ses, reqId, "An unknown server error occurred" );
218
219         if( ret > 0 ) 
220                 osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE,  
221                                 "osrfConnectStatus", reqId, "Request Complete" );
222
223         return 0;
224 }
225
226 int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) {
227         if(!ses) return -1;
228         if(!msg) msg = "";
229         VA_LIST_TO_STRING(msg);
230         osrfLog( OSRF_WARN, "Returning method exception with message: %s", VA_BUF );
231         osrfAppSessionStatus( ses, OSRF_STATUS_NOTFOUND, "osrfMethodException", request,  VA_BUF );
232         return 0;
233 }
234
235
236 static void __osrfAppSetIntrospectMethod( osrfMethodContext* ctx, osrfMethod* method, jsonObject* resp ) {
237         if(!(ctx && resp)) return;
238         jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name));
239         jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol));
240         jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service));
241         jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes));
242         jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc));
243         jsonObjectSetKey(resp, "params", jsonNewObject(method->paramNotes) );
244         jsonObjectSetKey(resp, "sysmethod", jsonNewNumberObject(method->sysmethod) );
245         jsonObjectSetClass(resp, "method");
246 }
247
248
249
250 int __osrfAppRunSystemMethod(osrfMethodContext* ctx) {
251         OSRF_METHOD_VERIFY_CONTEXT(ctx);
252
253         if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL )) {
254
255                 jsonObject* resp = NULL;
256                 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
257                 if(app) {
258                         osrfMethod* method = app->methods;
259                         while(method) {
260                                 resp = jsonNewObject(NULL);
261                                 __osrfAppSetIntrospectMethod( ctx, method, resp );
262                                 osrfAppRequestRespond(ctx->session, ctx->request, resp);
263                                 jsonObjectFree(resp);
264                                 method = method->next;
265                         }
266                         return 1;
267                 }
268
269                 return -1;
270         }
271
272
273         if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT )) {
274
275                 jsonObject* resp = NULL;
276                 char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
277                 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
278                 int len = 0;
279
280                 if(!methodSubstring) return 1; /* respond with no methods */
281
282                 if(app) {
283                         osrfMethod* method = app->methods;
284                         while(method) {
285                                 if( (len = strlen(methodSubstring)) <= strlen(method->name) ) {
286                                         if( !strncmp( method->name, methodSubstring, len) ) {
287                                                 resp = jsonNewObject(NULL);
288                                                 __osrfAppSetIntrospectMethod( ctx, method, resp );
289                                                 osrfAppRequestRespond(ctx->session, ctx->request, resp);
290                                                 jsonObjectFree(resp);
291                                         }
292                                 }
293                                 method = method->next;
294                         }
295                         return 1;
296                 }
297
298                 return -1;
299         }
300
301         return -1;
302 }
303
304
305
306