/examples/jsonrpc/public/services/jsonrpc/__init__.py

http://pyjamas.googlecode.com/ · Python · 241 lines · 172 code · 19 blank · 50 comment · 15 complexity · d8401018c999557644a64108fa041064 MD5 · raw file

  1. """
  2. Copyright (c) 2006 Jan-Klaas Kollhof
  3. This file is part of jsonrpc.
  4. jsonrpc is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This software is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this software; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. """
  16. from threading import Event, Lock
  17. from errors import *
  18. from simplejson import JSONDecoder, JSONEncoder
  19. class JSONRPCEncoder(JSONEncoder):
  20. def default(self, obj):
  21. if isinstance(obj, JSONRPCError):
  22. return obj.__class__.__name__
  23. else:
  24. return JSONEncoder.default(self, obj)
  25. class Timeout(Exception):
  26. pass
  27. class ResponseEvent:
  28. """Event which is fired when the response is returned for a request.
  29. For each request sent this event is created.
  30. An application can wait for the event to create a blocking request.
  31. """
  32. def __init__(self):
  33. self.__evt = Event()
  34. def waiting(self):
  35. return not self.__evt.isSet()
  36. def waitForResponse(self, timeOut=None):
  37. """blocks until the response arrived or timeout is reached."""
  38. self.__evt.wait(timeOut)
  39. if self.waiting():
  40. raise Timeout()
  41. else:
  42. if self.response["error"]:
  43. raise Exception(self.response["error"])
  44. else:
  45. return self.response["result"]
  46. def handleResponse(self, resp):
  47. self.response = resp
  48. self.__evt.set()
  49. class SimpleMessageHandler:
  50. def __init__(self, DecoderClass=JSONDecoder, EncoderClass=JSONRPCEncoder, messageDelimiter=""):
  51. self.decoder = DecoderClass()
  52. self.encoder = EncoderClass()
  53. self.partialData = ""
  54. self.respEvents={}
  55. self.respLock = Lock()
  56. self.messageDelimiter=messageDelimiter
  57. def close(self):
  58. pass
  59. def send(self, data):
  60. pass
  61. def sendMessage(self, msg):
  62. self.send(self.encoder.encode(msg) + self.messageDelimiter)
  63. def handlePartialData(self, data):
  64. data = self.partialData + data.replace("\r","").replace("\n", "")
  65. msgs=[]
  66. while data != "":
  67. pos = data.find("{")
  68. if(pos > -1):
  69. data=data[pos:]
  70. try:
  71. (obj, pos) = self.decoder.raw_decode(data)
  72. data = data[pos:]
  73. msgs.append(obj)
  74. except:
  75. break
  76. else:
  77. break
  78. self.partialData = data
  79. self.handleMessages(msgs)
  80. def sendNotify(self, name, args):
  81. """sends a notification object to the peer"""
  82. self.sendMessage({"method":name, "params": args})
  83. def sendRequest(self, name, args):
  84. """sends a request to the peer"""
  85. (respEvt, id) = self.newResponseEvent()
  86. self.sendMessage({"id":id, "method":name, "params": args})
  87. return respEvt
  88. def sendResponse(self, id, result, error):
  89. """sends a response to the peer"""
  90. self.sendMessage({"result":result, "error": error, "id":id})
  91. def newResponseEvent(self):
  92. """creates a response event and adds it to a waiting list
  93. When the reponse arrives it will be removed from the list.
  94. """
  95. respEvt = ResponseEvent()
  96. self.respLock.acquire()
  97. eid = id(respEvt)
  98. self.respEvents[eid] = respEvt
  99. self.respLock.release()
  100. return (respEvt,eid)
  101. def handleMessages(self, msgs):
  102. for msg in msgs:
  103. if msg.has_key("method") and msg.has_key("params"):
  104. if msg.has_key("id"):
  105. if msg["id"]:
  106. self.handleRequest(msg)
  107. else:
  108. self.handleNotification(msg)
  109. else:
  110. self.handleNotification(msg)
  111. elif msg.has_key("result") and msg.has_key("error"):
  112. self.handleResponse(msg)
  113. else:#unknown object
  114. self.sendResponse(None, InvalidJSONMessage())
  115. self.close()
  116. def handleResponse(self, resp):
  117. """handles a response by fireing the response event for the response coming in"""
  118. id=resp["id"]
  119. evt = self.respEvents[id]
  120. del(self.respEvents[id])
  121. evt.handleResponse(resp)
  122. def handleRequest(self, request):
  123. pass
  124. def handleNotification(self, notification):
  125. pass
  126. import re
  127. NameAllowedRegExp=re.compile("^[a-zA-Z]\w*$")
  128. def nameAllowed(name):
  129. """checks if a name is allowed.
  130. """
  131. if NameAllowedRegExp.match(name):
  132. return 1
  133. else:
  134. return 0
  135. def getMethodByName(obj, name):
  136. """searches for an object with the name given inside the object given.
  137. "obj.child.meth" will return the meth obj.
  138. """
  139. try:#to get a method by asking the service
  140. obj = obj._getMethodByName(name)
  141. except:
  142. #assumed a childObject is ment
  143. #split the name from objName.childObjName... -> [objName, childObjName, ...]
  144. #and get all objects up to the last in list with name checking from the service object
  145. names = name.split(".")
  146. for name in names:
  147. if nameAllowed(name):
  148. obj = getattr(obj, name)
  149. else:
  150. raise MethodNameNotAllowed()
  151. return obj
  152. class SimpleServiceHandler(SimpleMessageHandler):
  153. def __init__(self, service, DecoderClass=JSONDecoder, EncoderClass=JSONRPCEncoder, messageDelimiter=""):
  154. self.service = service
  155. SimpleMessageHandler.__init__(self, DecoderClass, EncoderClass, messageDelimiter)
  156. try:
  157. service._newConnection(self)
  158. except:
  159. pass
  160. def close(self):
  161. try:
  162. self.service._closingConnection(self)
  163. except:
  164. pass
  165. def handleRequest(self, req):
  166. """handles a request by calling the appropriete method the service exposes"""
  167. name = req["method"]
  168. params = req["params"]
  169. id=req["id"]
  170. obj=None
  171. try: #to get a callable obj
  172. obj = getMethodByName(self.service, name)
  173. except MethodNameNotAllowed,e:
  174. self.sendResponse(id, None, e)
  175. except:
  176. self.sendResponse(id, None, MethodNotFound())
  177. if obj:
  178. try: #to call the object with parameters
  179. rslt = obj(*params)
  180. self.sendResponse(id, rslt, None)
  181. except TypeError: # wrong arguments
  182. #todo what if the TypeError was not thrown directly by the callable obj
  183. s=getTracebackStr()
  184. self.sendResponse(id, None, InvalidMethodParameters())
  185. except: #error inside the callable object
  186. s=getTracebackStr()
  187. self.sendResponse(id, None, s)
  188. def handleNotification(self, req):
  189. """handles a notification request by calling the appropriete method the service exposes"""
  190. name = req["method"]
  191. params = req["params"]
  192. try: #to get a callable obj
  193. obj = getMethodByName(self.service, name)
  194. rslt = obj(*params)
  195. except:
  196. pass