blob: 4265c56ea5534957e6b018ccd406560dd8f01093 [file] [log] [blame]
mblighe8819cd2008-02-15 16:48:40 +00001
2"""
3 Copyright (c) 2007 Jan-Klaas Kollhof
4
5 This file is part of jsonrpc.
6
7 jsonrpc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 This software is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this software; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20"""
21
22import traceback
23
showarda5288b42009-07-28 20:06:08 +000024from autotest_lib.frontend.afe.simplejson import decoder, encoder
mblighe8819cd2008-02-15 16:48:40 +000025
26def customConvertJson(value):
27 """\
28 Recursively process JSON values and do type conversions.
29 -change floats to ints
30 -change unicodes to strs
31 """
32 if isinstance(value, float):
33 return int(value)
34 elif isinstance(value, unicode):
35 return str(value)
36 elif isinstance(value, list):
37 return [customConvertJson(item) for item in value]
38 elif isinstance(value, dict):
39 new_dict = {}
40 for key, val in value.iteritems():
41 new_key = customConvertJson(key)
42 new_val = customConvertJson(val)
43 new_dict[new_key] = new_val
44 return new_dict
45 else:
46 return value
47
48json_encoder = encoder.JSONEncoder()
49json_decoder = decoder.JSONDecoder()
50
51
52def ServiceMethod(fn):
53 fn.IsServiceMethod = True
54 return fn
55
56class ServiceException(Exception):
57 pass
58
59class ServiceRequestNotTranslatable(ServiceException):
60 pass
61
62class BadServiceRequest(ServiceException):
63 pass
64
65class ServiceMethodNotFound(ServiceException):
66 pass
67
showard3d6ae112009-05-02 00:45:48 +000068
mblighe8819cd2008-02-15 16:48:40 +000069class ServiceHandler(object):
70
71 def __init__(self, service):
72 self.service=service
jadmanski0afbb632008-06-06 21:10:57 +000073
showard3d6ae112009-05-02 00:45:48 +000074 def dispatchRequest(self, request):
showard02ed4bd2009-09-09 15:30:11 +000075 """
76 Invoke a json RPC call from a decoded json request.
77 @param request: a decoded json_request
78 @returns a dictionary with keys id, result, err and err_traceback
79 """
80 results = {}
81 results['id'] = None
82 results['result'] = None
83 results['err'] = None
84 results['err_traceback'] = None
85
showard3d6ae112009-05-02 00:45:48 +000086 try:
showard02ed4bd2009-09-09 15:30:11 +000087 results['id'] = self._getRequestId(request)
showard3d6ae112009-05-02 00:45:48 +000088 methName = request['method']
89 args = request['params']
90 except KeyError:
91 raise BadServiceRequest(request)
mblighe8819cd2008-02-15 16:48:40 +000092
showard02ed4bd2009-09-09 15:30:11 +000093 try:
94 meth = self.findServiceEndpoint(methName)
95 results['result'] = self.invokeServiceEndpoint(meth, args)
96 except Exception, err:
97 results['err_traceback'] = traceback.format_exc()
98 results['err'] = err
99
100 return results
101
showard3d6ae112009-05-02 00:45:48 +0000102
103 def _getRequestId(self, request):
104 try:
105 return request['id']
106 except KeyError:
107 raise BadServiceRequest(request)
108
showard02ed4bd2009-09-09 15:30:11 +0000109
showard3d6ae112009-05-02 00:45:48 +0000110 def handleRequest(self, jsonRequest):
showard3d6ae112009-05-02 00:45:48 +0000111 request = self.translateRequest(jsonRequest)
showard02ed4bd2009-09-09 15:30:11 +0000112 results = self.dispatchRequest(request)
113 return self.translateResult(results)
jadmanski0afbb632008-06-06 21:10:57 +0000114
mblighe8819cd2008-02-15 16:48:40 +0000115
showardef6fe022009-03-27 20:55:16 +0000116 @staticmethod
117 def translateRequest(data):
mblighe8819cd2008-02-15 16:48:40 +0000118 try:
119 req = json_decoder.decode(data)
120 except:
121 raise ServiceRequestNotTranslatable(data)
showard3d6ae112009-05-02 00:45:48 +0000122 req = customConvertJson(req)
mblighe8819cd2008-02-15 16:48:40 +0000123 return req
showard5da17d42008-04-28 18:07:58 +0000124
mblighe8819cd2008-02-15 16:48:40 +0000125 def findServiceEndpoint(self, name):
126 try:
127 meth = getattr(self.service, name)
mblighe8819cd2008-02-15 16:48:40 +0000128 return meth
mblighe8819cd2008-02-15 16:48:40 +0000129 except AttributeError:
130 raise ServiceMethodNotFound(name)
131
132 def invokeServiceEndpoint(self, meth, args):
133 return meth(*args)
134
showardef6fe022009-03-27 20:55:16 +0000135 @staticmethod
showard02ed4bd2009-09-09 15:30:11 +0000136 def translateResult(result_dict):
137 """
138 @param result_dict: a dictionary containing the result, error, traceback
139 and id.
140 @returns translated json result
141 """
142 if result_dict['err'] is not None:
143 error_name = result_dict['err'].__class__.__name__
144 result_dict['err'] = {'name': error_name,
145 'message': str(result_dict['err']),
146 'traceback': result_dict['err_traceback']}
147 result_dict['result'] = None
mblighe8819cd2008-02-15 16:48:40 +0000148
149 try:
showard02ed4bd2009-09-09 15:30:11 +0000150 json_dict = {'result': result_dict['result'],
151 'id': result_dict['id'],
152 'error': result_dict['err'] }
153 data = json_encoder.encode(json_dict)
mblighe8819cd2008-02-15 16:48:40 +0000154 except TypeError, e:
showard5da17d42008-04-28 18:07:58 +0000155 err_traceback = traceback.format_exc()
156 print err_traceback
157 err = {"name" : "JSONEncodeException",
158 "message" : "Result Object Not Serializable",
159 "traceback" : err_traceback}
showard02ed4bd2009-09-09 15:30:11 +0000160 data = json_encoder.encode({"result":None, "id":result_dict['id'],
161 "error":err})
showard5da17d42008-04-28 18:07:58 +0000162
mblighe8819cd2008-02-15 16:48:40 +0000163 return data