]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/python/osrf/app.py
LP#1409055 Support specific protocols for OpenSRF gateway requests
[OpenSRF.git] / src / python / osrf / app.py
1 # -----------------------------------------------------------------------
2 # Copyright (C) 2008  Equinox Software, Inc.
3 # Bill Erickson <erickson@esilibrary.com>
4 #
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.
9 #
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.
14 #
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  
18 # 02110-1301, USA
19 # -----------------------------------------------------------------------
20
21 import time
22 import osrf.log, osrf.ses, osrf.json
23
24
25 class Method(object):
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)
32
33     def get_func(self):
34         ''' Returns the function handler reference '''
35         return getattr(Application.application, self.handler)
36
37     def get_doc(self):
38         ''' Returns the function documentation '''
39         return self.get_func().func_doc
40         
41
42
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. '''
47
48     # global application handle
49     application = None
50     name = None
51     methods = {}
52
53     def __init__(self):
54         ''' Sets the application name and loads the application methods '''
55         self.name = None
56
57     def global_init(self):
58         ''' Override this method to run code at application startup '''
59         pass
60
61     def child_init(self):
62         ''' Override this method to run code at child startup.
63             This is useful for initializing database connections or
64             initializing other persistent resources '''
65         pass
66
67     def child_exit(self):
68         ''' Override this method to run code at process exit time.
69             This is useful for cleaning up resources like databaes 
70             handles, etc. '''
71         pass
72
73
74     @staticmethod
75     def load(name, module_name):
76         ''' Loads the provided application module '''
77         Application.name = name
78         try:
79             osrf.log.log_info("Loading application module %s" % module_name)
80             exec('import %s' % module_name)
81         except Exception, e:
82             osrf.log.log_error("Error importing application module %s:%s" % (
83                 module_name, unicode(e)))
84
85     @staticmethod
86     def register_app(app):
87         ''' Registers an application for use '''
88         app.name = Application.name
89         Application.application = app
90
91     @staticmethod
92     def register_method(**kwargs):
93         Application.methods[kwargs['api_name']] = Method(**kwargs)
94         if kwargs.get('stream'):
95             kwargs['atomic'] = 1 
96             kwargs['api_name'] +=  '.atomic'
97             Application.methods[kwargs['api_name']] = Method(**kwargs)
98
99
100     @staticmethod
101     def handle_request(session, osrf_msg):
102         ''' Find the handler, construct the server request, then run the method '''
103
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)
108
109         if method is None:
110             session.send_method_not_found(osrf_msg.threadTrace(), method_name)
111             return
112             
113         handler = method.get_func()
114
115         param_json = osrf.json.to_json(params)
116         param_json = param_json[1:len(param_json)-1]
117
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)
120
121         result = None
122         try:
123             result = handler(server_req, *params)
124         except Exception, e:
125             osrf.log.log_error("Error running method %s %s %s" % (method.name, param_json, unicode(e)))
126             session.send_status(
127                 osrf_msg.threadTrace(),
128                 osrf.net_obj.NetworkObject.osrfMethodException({   
129                     'status' : unicode(e),
130                     'statusCode': osrf.const.OSRF_STATUS_INTERNALSERVERERROR
131                 })
132             )
133             return
134
135         server_req.respond_complete(result)
136
137     @staticmethod
138     def register_sysmethods():
139         ''' Registers the global system methods '''
140
141         Application.register_method(
142             api_name = 'opensrf.system.time',
143             method = 'sysmethod_time',
144             argc = 0,
145         )
146         
147         Application.register_method(
148             api_name = 'opensrf.system.method',
149             method = 'sysmethod_introspect',
150             argc = 0,
151             stream = True
152         )
153
154         Application.register_method(
155             api_name = 'opensrf.system.method.all',
156             method = 'sysmethod_introspect',
157             argc = 0,
158             stream = True
159         )
160
161         Application.register_method(
162             api_name = 'opensrf.system.echo',
163             method = 'sysmethod_echo',
164             argc = 1,
165             stream = True
166         )
167
168     def sysmethod_time(self, request):
169         '''@return type:number The current epoch time '''
170         return time.time()
171
172     def sysmethod_echo(self, request, *args):
173         '''@return type:string The current epoch time '''
174         for a in args:
175             request.respond(a)
176
177     def sysmethod_introspect(self, request, prefix=None):
178         ''' Generates a list of methods with method metadata 
179             @param type:string The limiting method name prefix.  If defined,
180             only methods matching the given prefix will be returned.
181             @return type:array List of method information '''
182
183         for name, method in self.methods.iteritems():
184             if prefix is not None and prefix != name[:len(prefix)]:
185                 continue
186
187             request.respond({
188                 'api_name' : name,
189                 'method' : method.handler,
190                 'service' : self.name,
191                 'argc' : method.argc,
192                 'params' : [], # XXX parse me
193                 'desc' : method.get_doc() # XXX parse me
194             })
195
196