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 applicatoin 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()
106 method = Application.methods[req_method.method()]
107 handler = method.get_func()
109 param_json = osrf.json.to_json(params)
110 param_json = param_json[1:len(param_json)-1]
112 osrf.log.log_info("CALL: %s %s %s" % (session.service, method.name, param_json))
113 server_req = osrf.ses.ServerRequest(session, osrf_msg.threadTrace(), method, params)
117 result = handler(server_req, *params)
119 osrf.log.log_error("Error running method %s %s %s" % (method.name, param_json, unicode(e)))
121 osrf_msg.threadTrace(),
122 osrf.net_obj.NetworkObject.osrfMethodException({
123 'status' : unicode(e),
124 'statusCode': osrf.const.OSRF_STATUS_INTERNALSERVERERROR
129 server_req.respond_complete(result)
132 def register_sysmethods():
133 ''' Registers the global system methods '''
135 Application.register_method(
136 api_name = 'opensrf.system.time',
137 method = 'sysmethod_time',
141 Application.register_method(
142 api_name = 'opensrf.system.introspect',
143 method = 'sysmethod_introspect',
148 Application.register_method(
149 api_name = 'opensrf.system.echo',
150 method = 'sysmethod_echo',
155 def sysmethod_time(self, request):
156 '''@return type:number The current epoch time '''
159 def sysmethod_echo(self, request, *args):
160 '''@return type:string The current epoch time '''
164 def sysmethod_introspect(self, request, prefix=None):
165 ''' Generates a list of methods with method metadata
166 @param type:string The limiting method name prefix. If defined,
167 only methods matching the given prefix will be returned.
168 @return type:array List of method information '''
170 for name, method in self.methods.iteritems():
171 if prefix is not None and prefix != name[:len(prefix)]:
176 'method' : method.handler,
177 'service' : self.name,
178 'argc' : method.argc,
179 'params' : [], # XXX parse me
180 'desc' : method.get_doc() # XXX parse me