blob: 50ea45f99be119662b5c7d414dfb884c902f3361 [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
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
showard2df3c692009-09-11 18:41:07 +000074
75 @classmethod
76 def blank_result_dict(cls):
77 return {'id': None, 'result': None, 'err': None, 'err_traceback': None}
78
showard3d6ae112009-05-02 00:45:48 +000079 def dispatchRequest(self, request):
showard02ed4bd2009-09-09 15:30:11 +000080 """
81 Invoke a json RPC call from a decoded json request.
82 @param request: a decoded json_request
83 @returns a dictionary with keys id, result, err and err_traceback
84 """
showard2df3c692009-09-11 18:41:07 +000085 results = self.blank_result_dict()
showard02ed4bd2009-09-09 15:30:11 +000086
showard3d6ae112009-05-02 00:45:48 +000087 try:
showard02ed4bd2009-09-09 15:30:11 +000088 results['id'] = self._getRequestId(request)
showard3d6ae112009-05-02 00:45:48 +000089 methName = request['method']
90 args = request['params']
91 except KeyError:
92 raise BadServiceRequest(request)
mblighe8819cd2008-02-15 16:48:40 +000093
showard02ed4bd2009-09-09 15:30:11 +000094 try:
95 meth = self.findServiceEndpoint(methName)
96 results['result'] = self.invokeServiceEndpoint(meth, args)
97 except Exception, err:
98 results['err_traceback'] = traceback.format_exc()
99 results['err'] = err
100
101 return results
102
showard3d6ae112009-05-02 00:45:48 +0000103
104 def _getRequestId(self, request):
105 try:
106 return request['id']
107 except KeyError:
108 raise BadServiceRequest(request)
109
showard02ed4bd2009-09-09 15:30:11 +0000110
showard3d6ae112009-05-02 00:45:48 +0000111 def handleRequest(self, jsonRequest):
showard3d6ae112009-05-02 00:45:48 +0000112 request = self.translateRequest(jsonRequest)
showard02ed4bd2009-09-09 15:30:11 +0000113 results = self.dispatchRequest(request)
114 return self.translateResult(results)
jadmanski0afbb632008-06-06 21:10:57 +0000115
mblighe8819cd2008-02-15 16:48:40 +0000116
showardef6fe022009-03-27 20:55:16 +0000117 @staticmethod
118 def translateRequest(data):
mblighe8819cd2008-02-15 16:48:40 +0000119 try:
120 req = json_decoder.decode(data)
121 except:
122 raise ServiceRequestNotTranslatable(data)
showard3d6ae112009-05-02 00:45:48 +0000123 req = customConvertJson(req)
mblighe8819cd2008-02-15 16:48:40 +0000124 return req
showard5da17d42008-04-28 18:07:58 +0000125
mblighe8819cd2008-02-15 16:48:40 +0000126 def findServiceEndpoint(self, name):
127 try:
128 meth = getattr(self.service, name)
mblighe8819cd2008-02-15 16:48:40 +0000129 return meth
mblighe8819cd2008-02-15 16:48:40 +0000130 except AttributeError:
131 raise ServiceMethodNotFound(name)
132
133 def invokeServiceEndpoint(self, meth, args):
134 return meth(*args)
135
showardef6fe022009-03-27 20:55:16 +0000136 @staticmethod
showard02ed4bd2009-09-09 15:30:11 +0000137 def translateResult(result_dict):
138 """
139 @param result_dict: a dictionary containing the result, error, traceback
140 and id.
141 @returns translated json result
142 """
143 if result_dict['err'] is not None:
144 error_name = result_dict['err'].__class__.__name__
145 result_dict['err'] = {'name': error_name,
146 'message': str(result_dict['err']),
147 'traceback': result_dict['err_traceback']}
148 result_dict['result'] = None
mblighe8819cd2008-02-15 16:48:40 +0000149
150 try:
showard02ed4bd2009-09-09 15:30:11 +0000151 json_dict = {'result': result_dict['result'],
152 'id': result_dict['id'],
153 'error': result_dict['err'] }
154 data = json_encoder.encode(json_dict)
mblighe8819cd2008-02-15 16:48:40 +0000155 except TypeError, e:
showard5da17d42008-04-28 18:07:58 +0000156 err_traceback = traceback.format_exc()
157 print err_traceback
158 err = {"name" : "JSONEncodeException",
159 "message" : "Result Object Not Serializable",
160 "traceback" : err_traceback}
showard02ed4bd2009-09-09 15:30:11 +0000161 data = json_encoder.encode({"result":None, "id":result_dict['id'],
162 "error":err})
showard5da17d42008-04-28 18:07:58 +0000163
mblighe8819cd2008-02-15 16:48:40 +0000164 return data