1 # -----------------------------------------------------------------------
2 # Copyright (C) 2008 Equinox Software, Inc.
3 # Bill Erickson <erickson@esilibrary.com>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # -----------------------------------------------------------------------
22 import osrf.log, osrf.ses, osrf.json
26 def __init__(self, **kwargs):
27 self.name = kwargs['api_name']
28 self.handler = kwargs['method']
29 self.stream = kwargs.get('stream', False)
30 self.argc = kwargs.get('argc', 0)
31 self.atomic = kwargs.get('atomic', False)
34 ''' Returns the function handler reference '''
35 return getattr(Application.application, self.handler)
38 ''' Returns the function documentation '''
39 return self.get_func().func_doc
43 class Application(object):
44 ''' Base class for OpenSRF applications. Provides static methods
45 for loading and registering applications as well as common
46 application methods. '''
48 # global application handle
54 ''' Sets the application name and loads the application methods '''
57 def global_init(self):
58 ''' Override this method to run code at application startup '''
62 ''' Override this method to run code at child startup.
63 This is useful for initializing database connections or
64 initializing other persistent resources '''
68 ''' Override this method to run code at process exit time.
69 This is useful for cleaning up resources like databaes
75 def load(name, module_name):
76 ''' Loads the provided application module '''
77 Application.name = name
79 osrf.log.log_info("Loading application module %s" % module_name)
80 exec('import %s' % module_name)
82 osrf.log.log_error("Error importing application module %s:%s" % (
83 module_name, unicode(e)))
86 def register_app(app):
87 ''' Registers an application for use '''
88 app.name = Application.name
89 Application.application = app
92 def register_method(**kwargs):
93 Application.methods[kwargs['api_name']] = Method(**kwargs)
94 if kwargs.get('stream'):
96 kwargs['api_name'] += '.atomic'
97 Application.methods[kwargs['api_name']] = Method(**kwargs)
101 def handle_request(session, osrf_msg):
102 ''' Find the handler, construct the server request, then run the method '''
104 req_method = osrf_msg.payload()
105 params = req_method.params() or []
106 method_name = req_method.method()
107 method = Application.methods.get(method_name)
110 session.send_method_not_found(osrf_msg.threadTrace(), method_name)
113 handler = method.get_func()
115 param_json = osrf.json.to_json(params)
116 param_json = param_json[1:len(param_json)-1]
118 osrf.log.log_info("CALL: %s %s %s" % (session.service, method.name, param_json))
119 server_req = osrf.ses.ServerRequest(session, osrf_msg.threadTrace(), method, params)
123 result = handler(server_req, *params)
125 osrf.log.log_error("Error running method %s %s %s" % (method.name, param_json, unicode(e)))
127 osrf_msg.threadTrace(),
128 osrf.net_obj.NetworkObject.osrfMethodException({
129 'status' : unicode(e),
130 'statusCode': osrf.const.OSRF_STATUS_INTERNALSERVERERROR
135 server_req.respond_complete(result)
138 def register_sysmethods():
139 ''' Registers the global system methods '''
141 Application.register_method(
142 api_name = 'opensrf.system.time',
143 method = 'sysmethod_time',
147 Application.register_method(
148 api_name = 'opensrf.system.introspect',
149 method = 'sysmethod_introspect',
154 Application.register_method(
155 api_name = 'opensrf.system.echo',
156 method = 'sysmethod_echo',
161 def sysmethod_time(self, request):
162 '''@return type:number The current epoch time '''
165 def sysmethod_echo(self, request, *args):
166 '''@return type:string The current epoch time '''
170 def sysmethod_introspect(self, request, prefix=None):
171 ''' Generates a list of methods with method metadata
172 @param type:string The limiting method name prefix. If defined,
173 only methods matching the given prefix will be returned.
174 @return type:array List of method information '''
176 for name, method in self.methods.iteritems():
177 if prefix is not None and prefix != name[:len(prefix)]:
182 'method' : method.handler,
183 'service' : self.name,
184 'argc' : method.argc,
185 'params' : [], # XXX parse me
186 'desc' : method.get_doc() # XXX parse me