]> git.evergreen-ils.org Git - Evergreen.git/blob - OpenSRF/src/libstack/osrf_application.c
format fix
[Evergreen.git] / OpenSRF / src / libstack / osrf_application.c
1 #include "osrf_application.h"
2 #include "objson/object.h"
3
4 //osrfApplication* __osrfAppList = NULL; 
5
6 osrfHash* __osrfAppHash = NULL;
7
8
9 int osrfAppRegisterApplication( char* appName, char* soFile ) {
10         if(!appName || ! soFile) return -1;
11         char* error;
12
13         if(!__osrfAppHash) __osrfAppHash = osrfNewHash();
14
15         osrfLogInfo( OSRF_LOG_MARK, "Registering application %s with file %s", appName, soFile );
16
17         osrfApplication* app = safe_malloc(sizeof(osrfApplication));
18         app->handle = dlopen (soFile, RTLD_NOW);
19
20         if(!app->handle) {
21                 osrfLogWarning( OSRF_LOG_MARK, "Failed to dlopen library file %s: %s", soFile, dlerror() );
22                 dlerror(); /* clear the error */
23                 free(app);
24                 return -1;
25         }
26
27         app->methods = osrfNewHash();
28         osrfHashSet( __osrfAppHash, app, appName );
29
30         /* see if we can run the initialize method */
31         int (*init) (void);
32         *(void **) (&init) = dlsym(app->handle, "osrfAppInitialize");
33
34         if( (error = dlerror()) != NULL ) {
35                 osrfLogWarning( OSRF_LOG_MARK, 
36                         "! 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                         osrfLogWarning( OSRF_LOG_MARK, "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         osrfLogInfo( OSRF_LOG_MARK, "Application %s registered successfully", appName );
54
55         osrfLogSetAppname(appName);
56
57         return 0;
58 }
59
60
61 int osrfAppRegisterMethod( char* appName, char* methodName, 
62                 char* symbolName, char* notes, int argc, int options ) {
63
64         if( !appName || ! methodName  ) return -1;
65
66         osrfApplication* app = _osrfAppFindApplication(appName);
67         if(!app) {
68                 osrfLogWarning( OSRF_LOG_MARK, "Unable to locate application %s", appName );
69                 return -1;
70         }
71
72         osrfLogDebug( OSRF_LOG_MARK, "Registering method %s for app %s", methodName, appName );
73
74         osrfMethod* method = _osrfAppBuildMethod(
75                 methodName, symbolName, notes, argc, options );         
76         method->options = options;
77
78         /* plug the method into the list of methods */
79         osrfHashSet( app->methods, method, method->name );
80
81         if( options & OSRF_METHOD_STREAMING ) { /* build the atomic counterpart */
82                 int newops = options | OSRF_METHOD_ATOMIC;
83                 osrfMethod* atomicMethod = _osrfAppBuildMethod(
84                         methodName, symbolName, notes, argc, newops );          
85                 osrfHashSet( app->methods, atomicMethod, atomicMethod->name );
86         }
87
88         return 0;
89 }
90
91
92
93 osrfMethod* _osrfAppBuildMethod( char* methodName, 
94         char* symbolName, char* notes, int argc, int options ) {
95
96         osrfMethod* method                                      = safe_malloc(sizeof(osrfMethod));
97
98         if(methodName) method->name             = strdup(methodName);
99         if(symbolName) method->symbol           = strdup(symbolName);
100         if(notes) method->notes                         = strdup(notes);
101
102         method->argc                                                    = argc;
103         method->options                                         = options;
104
105         if(options & OSRF_METHOD_ATOMIC) { /* add ".atomic" to the end of the name */
106                 char mb[strlen(method->name) + 8];
107                 sprintf(mb, "%s.atomic", method->name);
108                 free(method->name);
109                 method->name = strdup(mb);
110                 method->options |= OSRF_METHOD_STREAMING;
111         }
112
113         return method;
114 }
115
116
117 int __osrfAppRegisterSysMethods( char* app ) {
118
119         osrfAppRegisterMethod( 
120                         app, OSRF_SYSMETHOD_INTROSPECT, NULL, 
121                         "Return a list of methods whose names have the same initial "
122                         "substring as that of the provided method name PARAMS( methodNameSubstring )", 
123                         1, OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
124
125         osrfAppRegisterMethod( 
126                         app, OSRF_SYSMETHOD_INTROSPECT_ALL, NULL, 
127                         "Returns a complete list of methods. PARAMS()", 0, 
128                         OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
129
130         osrfAppRegisterMethod( 
131                         app, OSRF_SYSMETHOD_ECHO, NULL, 
132                         "Echos all data sent to the server back to the client. PARAMS([a, b, ...])", 0, 
133                         OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
134
135         return 0;
136 }
137
138 osrfApplication* _osrfAppFindApplication( char* name ) {
139         if(!name) return NULL;
140         return (osrfApplication*) osrfHashGet(__osrfAppHash, name);
141 }
142
143 osrfMethod* __osrfAppFindMethod( osrfApplication* app, char* methodName ) {
144         if(!app || ! methodName) return NULL;
145         return (osrfMethod*) osrfHashGet( app->methods, methodName );
146 }
147
148 osrfMethod* _osrfAppFindMethod( char* appName, char* methodName ) {
149         if(!appName || ! methodName) return NULL;
150         return __osrfAppFindMethod( _osrfAppFindApplication(appName), methodName );
151 }
152
153
154 int osrfAppRunMethod( char* appName, char* methodName, 
155                 osrfAppSession* ses, int reqId, jsonObject* params ) {
156
157         if( !(appName && methodName && ses) ) return -1;
158
159         char* error;
160         osrfApplication* app;
161         osrfMethod* method;
162         osrfMethodContext context;
163
164         context.session = ses;
165         context.params = params;
166         context.request = reqId;
167         context.responses = NULL;
168
169         /* this is the method we're gonna run */
170         int (*meth) (osrfMethodContext*);       
171
172         osrfLogInfo( OSRF_LOG_MARK, "Running method [%s] for app [%s] with request id %d and "
173                         "thread trace %s", methodName, appName, reqId, ses->session_id );
174
175         if( !(app = _osrfAppFindApplication(appName)) )
176                 return osrfAppRequestRespondException( ses, 
177                                 reqId, "Application not found: %s", appName );
178         
179         if( !(method = __osrfAppFindMethod( app, methodName )) ) 
180                 return osrfAppRequestRespondException( ses, reqId, 
181                                 "Method [%s] not found for service %s", methodName, appName );
182
183         context.method = method;
184
185         #ifdef OSRF_STRICT_PARAMS
186         if( method->argc > 0 ) {
187                 if(!params || params->type != JSON_ARRAY || params->size < method->argc )
188                         return osrfAppRequestRespondException( ses, reqId, 
189                                 "Not enough params for method %s / service %s", methodName, appName );
190         }
191         #endif
192
193         int retcode = 0;
194
195         if( method->options & OSRF_METHOD_SYSTEM ) {
196                 retcode = __osrfAppRunSystemMethod(&context);
197
198         } else {
199
200                 /* open and now run the method */
201                 *(void **) (&meth) = dlsym(app->handle, method->symbol);
202
203                 if( (error = dlerror()) != NULL ) {
204                         return osrfAppRequestRespondException( ses, reqId, 
205                                 "Unable to execute method [%s]  for service %s", methodName, appName );
206                 }
207
208                 retcode = (*meth) (&context);
209         }
210
211         if(retcode < 0) 
212                 return osrfAppRequestRespondException( 
213                                 ses, reqId, "An unknown server error occurred" );
214
215         return __osrfAppPostProcess( &context, retcode );
216
217 }
218
219
220 int osrfAppRespond( osrfMethodContext* ctx, jsonObject* data ) {
221         return _osrfAppRespond( ctx, data, 0 );
222 }
223
224 int osrfAppRespondComplete( osrfMethodContext* context, jsonObject* data ) {
225         return _osrfAppRespond( context, data, 1 );
226 }
227
228 int _osrfAppRespond( osrfMethodContext* ctx, jsonObject* data, int complete ) {
229         if(!(ctx && ctx->method)) return -1;
230
231         if( ctx->method->options & OSRF_METHOD_ATOMIC ) {
232                 osrfLogDebug( OSRF_LOG_MARK,   
233                         "Adding responses to stash for atomic method %s", ctx->method );
234
235                 if( ctx->responses == NULL )                                                                                            
236                         ctx->responses = jsonParseString("[]");                                                 
237                 jsonObjectPush( ctx->responses, jsonObjectClone(data) );        
238         }
239
240
241         if(     !(ctx->method->options & OSRF_METHOD_ATOMIC) && 
242                         !(ctx->method->options & OSRF_METHOD_CACHABLE) ) {
243
244                 if(complete) 
245                         osrfAppRequestRespondComplete( ctx->session, ctx->request, data );
246                 else
247                         osrfAppRequestRespond( ctx->session, ctx->request, data );
248                 return 0;
249         }
250
251         return 0;
252 }
253
254
255
256
257 int __osrfAppPostProcess( osrfMethodContext* ctx, int retcode ) {
258         if(!(ctx && ctx->method)) return -1;
259
260         osrfLogDebug( OSRF_LOG_MARK,  "Postprocessing method %s with retcode %d",
261                         ctx->method->name, retcode );
262
263         if(ctx->responses) { /* we have cached responses to return (no responses have been sent) */
264
265                 osrfAppRequestRespondComplete( ctx->session, ctx->request, ctx->responses );
266                 jsonObjectFree(ctx->responses);
267                 ctx->responses = NULL;
268
269         } else {
270
271                 if( retcode > 0 ) 
272                         osrfAppSessionStatus( ctx->session, OSRF_STATUS_COMPLETE,  
273                                         "osrfConnectStatus", ctx->request, "Request Complete" );
274         }
275
276         return 0;
277
278 }
279
280 int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) {
281         if(!ses) return -1;
282         if(!msg) msg = "";
283         VA_LIST_TO_STRING(msg);
284         osrfLogWarning( OSRF_LOG_MARK,  "Returning method exception with message: %s", VA_BUF );
285         osrfAppSessionStatus( ses, OSRF_STATUS_NOTFOUND, "osrfMethodException", request,  VA_BUF );
286         return 0;
287 }
288
289
290 static void __osrfAppSetIntrospectMethod( osrfMethodContext* ctx, osrfMethod* method, jsonObject* resp ) {
291         if(!(ctx && resp)) return;
292
293         jsonObjectSetKey(resp, "api_name",      jsonNewObject(method->name));
294         jsonObjectSetKey(resp, "method",                jsonNewObject(method->symbol));
295         jsonObjectSetKey(resp, "service",       jsonNewObject(ctx->session->remote_service));
296         jsonObjectSetKey(resp, "notes",         jsonNewObject(method->notes));
297         jsonObjectSetKey(resp, "argc",          jsonNewNumberObject(method->argc));
298
299         jsonObjectSetKey(resp, "sysmethod", 
300                         jsonNewNumberObject( (method->options & OSRF_METHOD_SYSTEM) ? 1 : 0 ));
301         jsonObjectSetKey(resp, "atomic",                
302                         jsonNewNumberObject( (method->options & OSRF_METHOD_ATOMIC) ? 1 : 0 ));
303         jsonObjectSetKey(resp, "cachable",      
304                         jsonNewNumberObject( (method->options & OSRF_METHOD_CACHABLE) ? 1 : 0 ));
305
306         jsonObjectSetClass(resp, "method");
307 }
308
309
310
311 int __osrfAppRunSystemMethod(osrfMethodContext* ctx) {
312         OSRF_METHOD_VERIFY_CONTEXT(ctx);
313
314         if(     !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL ) || 
315                         !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC )) {
316
317                 return osrfAppIntrospectAll(ctx);
318         }
319
320
321         if(     !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT ) ||
322                         !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ATOMIC )) {
323
324                 return osrfAppIntrospect(ctx);
325         }
326
327         osrfAppRequestRespondException( ctx->session, 
328                         ctx->request, "System method implementation not found");
329
330         return 0;
331 }
332
333
334 int osrfAppIntrospect( osrfMethodContext* ctx ) {
335
336         jsonObject* resp = NULL;
337         char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
338         osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
339         int len = 0;
340
341         if(!methodSubstring) return 1; /* respond with no methods */
342
343         if(app) {
344
345                 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
346                 osrfMethod* method;
347
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);
355                                 }
356                         }
357                 }
358                 osrfHashIteratorFree(itr);
359                 return 1;
360         }
361
362         return -1;
363
364 }
365
366
367 int osrfAppIntrospectAll( osrfMethodContext* ctx ) {
368         jsonObject* resp = NULL;
369         osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
370
371         if(app) {
372                 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
373                 osrfMethod* method;
374                 while( (method = osrfHashIteratorNext(itr)) ) {
375                         resp = jsonNewObject(NULL);
376                         __osrfAppSetIntrospectMethod( ctx, method, resp );
377                         osrfAppRespond(ctx, resp);
378                         jsonObjectFree(resp);
379                 }
380                 osrfHashIteratorFree(itr);
381                 return 1;
382         }
383
384         return -1;
385 }
386
387