blob: b0d9e84d95edb7c29a4396f42065c7e92e31e6c4 [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
Alex Miller4f341702013-03-25 12:39:12 -070024from json import decoder, encoder
Michael Liangda8c60a2014-06-03 13:24:51 -070025from autotest_lib.client.common_lib.cros.graphite import stats
mblighe8819cd2008-02-15 16:48:40 +000026
27def customConvertJson(value):
28 """\
29 Recursively process JSON values and do type conversions.
30 -change floats to ints
31 -change unicodes to strs
32 """
33 if isinstance(value, float):
34 return int(value)
35 elif isinstance(value, unicode):
36 return str(value)
37 elif isinstance(value, list):
38 return [customConvertJson(item) for item in value]
39 elif isinstance(value, dict):
40 new_dict = {}
41 for key, val in value.iteritems():
42 new_key = customConvertJson(key)
43 new_val = customConvertJson(val)
44 new_dict[new_key] = new_val
45 return new_dict
46 else:
47 return value
48
49json_encoder = encoder.JSONEncoder()
50json_decoder = decoder.JSONDecoder()
51
52
53def ServiceMethod(fn):
54 fn.IsServiceMethod = True
55 return fn
56
57class ServiceException(Exception):
58 pass
59
60class ServiceRequestNotTranslatable(ServiceException):
61 pass
62
63class BadServiceRequest(ServiceException):
64 pass
65
66class ServiceMethodNotFound(ServiceException):
67 pass
68
showard3d6ae112009-05-02 00:45:48 +000069
mblighe8819cd2008-02-15 16:48:40 +000070class ServiceHandler(object):
71
72 def __init__(self, service):
73 self.service=service
jadmanski0afbb632008-06-06 21:10:57 +000074
showard2df3c692009-09-11 18:41:07 +000075
76 @classmethod
77 def blank_result_dict(cls):
78 return {'id': None, 'result': None, 'err': None, 'err_traceback': None}
79
showard3d6ae112009-05-02 00:45:48 +000080 def dispatchRequest(self, request):
showard02ed4bd2009-09-09 15:30:11 +000081 """
82 Invoke a json RPC call from a decoded json request.
83 @param request: a decoded json_request
84 @returns a dictionary with keys id, result, err and err_traceback
85 """
showard2df3c692009-09-11 18:41:07 +000086 results = self.blank_result_dict()
showard02ed4bd2009-09-09 15:30:11 +000087
showard3d6ae112009-05-02 00:45:48 +000088 try:
showard02ed4bd2009-09-09 15:30:11 +000089 results['id'] = self._getRequestId(request)
showard3d6ae112009-05-02 00:45:48 +000090 methName = request['method']
91 args = request['params']
92 except KeyError:
93 raise BadServiceRequest(request)
mblighe8819cd2008-02-15 16:48:40 +000094
Alex Miller1b249312013-11-12 15:45:37 -080095 stats.Counter('rpc').increment(methName)
Jiaxi Luo0f5f0442014-05-23 11:36:54 -070096 timer = stats.Timer('rpc')
Alex Miller1b249312013-11-12 15:45:37 -080097
showard02ed4bd2009-09-09 15:30:11 +000098 try:
Jiaxi Luo0f5f0442014-05-23 11:36:54 -070099 timer.start()
Dan Shicd0a01d2014-06-11 20:53:35 -0700100 meth = self.findServiceEndpoint(methName)
showard02ed4bd2009-09-09 15:30:11 +0000101 results['result'] = self.invokeServiceEndpoint(meth, args)
102 except Exception, err:
103 results['err_traceback'] = traceback.format_exc()
104 results['err'] = err
Jiaxi Luo0f5f0442014-05-23 11:36:54 -0700105 finally:
106 timer.stop(methName)
showard02ed4bd2009-09-09 15:30:11 +0000107
108 return results
109
showard3d6ae112009-05-02 00:45:48 +0000110
111 def _getRequestId(self, request):
112 try:
113 return request['id']
114 except KeyError:
115 raise BadServiceRequest(request)
116
showard02ed4bd2009-09-09 15:30:11 +0000117
showard3d6ae112009-05-02 00:45:48 +0000118 def handleRequest(self, jsonRequest):
showard3d6ae112009-05-02 00:45:48 +0000119 request = self.translateRequest(jsonRequest)
showard02ed4bd2009-09-09 15:30:11 +0000120 results = self.dispatchRequest(request)
121 return self.translateResult(results)
jadmanski0afbb632008-06-06 21:10:57 +0000122
mblighe8819cd2008-02-15 16:48:40 +0000123
showardef6fe022009-03-27 20:55:16 +0000124 @staticmethod
125 def translateRequest(data):
mblighe8819cd2008-02-15 16:48:40 +0000126 try:
127 req = json_decoder.decode(data)
128 except:
129 raise ServiceRequestNotTranslatable(data)
showard3d6ae112009-05-02 00:45:48 +0000130 req = customConvertJson(req)
mblighe8819cd2008-02-15 16:48:40 +0000131 return req
showard5da17d42008-04-28 18:07:58 +0000132
mblighe8819cd2008-02-15 16:48:40 +0000133 def findServiceEndpoint(self, name):
134 try:
135 meth = getattr(self.service, name)
mblighe8819cd2008-02-15 16:48:40 +0000136 return meth
mblighe8819cd2008-02-15 16:48:40 +0000137 except AttributeError:
138 raise ServiceMethodNotFound(name)
139
140 def invokeServiceEndpoint(self, meth, args):
141 return meth(*args)
142
showardef6fe022009-03-27 20:55:16 +0000143 @staticmethod
showard02ed4bd2009-09-09 15:30:11 +0000144 def translateResult(result_dict):
145 """
146 @param result_dict: a dictionary containing the result, error, traceback
147 and id.
148 @returns translated json result
149 """
150 if result_dict['err'] is not None:
151 error_name = result_dict['err'].__class__.__name__
152 result_dict['err'] = {'name': error_name,
153 'message': str(result_dict['err']),
154 'traceback': result_dict['err_traceback']}
155 result_dict['result'] = None
mblighe8819cd2008-02-15 16:48:40 +0000156
157 try:
showard02ed4bd2009-09-09 15:30:11 +0000158 json_dict = {'result': result_dict['result'],
159 'id': result_dict['id'],
160 'error': result_dict['err'] }
161 data = json_encoder.encode(json_dict)
mblighe8819cd2008-02-15 16:48:40 +0000162 except TypeError, e:
showard5da17d42008-04-28 18:07:58 +0000163 err_traceback = traceback.format_exc()
164 print err_traceback
165 err = {"name" : "JSONEncodeException",
166 "message" : "Result Object Not Serializable",
167 "traceback" : err_traceback}
showard02ed4bd2009-09-09 15:30:11 +0000168 data = json_encoder.encode({"result":None, "id":result_dict['id'],
169 "error":err})
showard5da17d42008-04-28 18:07:58 +0000170
mblighe8819cd2008-02-15 16:48:40 +0000171 return data