summaryrefslogtreecommitdiffstats
path: root/silpa/jsonrpc
diff options
context:
space:
mode:
authorSanthosh Thottingal <santhosh.thottingal@gmail.com>2009-07-19 18:32:04 +0530
committerSanthosh Thottingal <santhosh.thottingal@gmail.com>2009-07-19 18:32:04 +0530
commitc8a17ee264a269a59651936b34a960f4d40a9074 (patch)
tree3b2b21be4668f50a5c5f307c89e42323b8a8c292 /silpa/jsonrpc
parent05f7f938168f9b3195c9b101f4b98f298ab2e981 (diff)
downloadAnjaliOldLipi.git-c8a17ee264a269a59651936b34a960f4d40a9074.tar.gz
AnjaliOldLipi.git-c8a17ee264a269a59651936b34a960f4d40a9074.tar.xz
AnjaliOldLipi.git-c8a17ee264a269a59651936b34a960f4d40a9074.zip
JSON RPC Based new architecture and corresponding changes
Diffstat (limited to 'silpa/jsonrpc')
-rw-r--r--silpa/jsonrpc/__init__.py26
-rw-r--r--silpa/jsonrpc/cgiwrapper.py45
-rw-r--r--silpa/jsonrpc/json.py230
-rw-r--r--silpa/jsonrpc/modpywrapper.py52
-rw-r--r--silpa/jsonrpc/proxy.py49
-rw-r--r--silpa/jsonrpc/serviceHandler.py152
6 files changed, 554 insertions, 0 deletions
diff --git a/silpa/jsonrpc/__init__.py b/silpa/jsonrpc/__init__.py
new file mode 100644
index 0000000..71779a1
--- /dev/null
+++ b/silpa/jsonrpc/__init__.py
@@ -0,0 +1,26 @@
+
+"""
+ Copyright (c) 2007 Jan-Klaas Kollhof
+
+ This file is part of jsonrpc.
+
+ jsonrpc is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this software; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+from jsonrpc.json import loads, dumps, JSONEncodeException, JSONDecodeException
+from jsonrpc.proxy import ServiceProxy, JSONRPCException
+from jsonrpc.serviceHandler import ServiceMethod, ServiceHandler, ServiceMethodNotFound, ServiceException
+from jsonrpc.cgiwrapper import handleCGI
+from jsonrpc.modpywrapper import handler \ No newline at end of file
diff --git a/silpa/jsonrpc/cgiwrapper.py b/silpa/jsonrpc/cgiwrapper.py
new file mode 100644
index 0000000..a5bc2b0
--- /dev/null
+++ b/silpa/jsonrpc/cgiwrapper.py
@@ -0,0 +1,45 @@
+import sys, os
+from jsonrpc import ServiceHandler
+
+class CGIServiceHandler(ServiceHandler):
+ def __init__(self, service):
+ if service == None:
+ import __main__ as service
+
+ ServiceHandler.__init__(self, service)
+
+ def handleRequest(self, fin=None, fout=None, env=None):
+ if fin==None:
+ fin = sys.stdin
+ if fout==None:
+ fout = sys.stdout
+ if env == None:
+ env = os.environ
+
+ try:
+ contLen=int(env['CONTENT_LENGTH'])
+ data = fin.read(contLen)
+ except Exception, e:
+ data = ""
+
+ resultData = ServiceHandler.handleRequest(self, data)
+
+ response = "Content-Type: text/plain\n"
+ response += "Content-Length: %d\n\n" % len(resultData)
+ response += resultData
+
+ #on windows all \n are converted to \r\n if stdout is a terminal and is not set to binary mode :(
+ #this will then cause an incorrect Content-length.
+ #I have only experienced this problem with apache on Win so far.
+ if sys.platform == "win32":
+ try:
+ import msvcrt
+ msvcrt.setmode(fout.fileno(), os.O_BINARY)
+ except:
+ pass
+ #put out the response
+ fout.write(response)
+ fout.flush()
+
+def handleCGI(service=None, fin=None, fout=None, env=None):
+ CGIServiceHandler(service).handleRequest(fin, fout, env) \ No newline at end of file
diff --git a/silpa/jsonrpc/json.py b/silpa/jsonrpc/json.py
new file mode 100644
index 0000000..4f945b2
--- /dev/null
+++ b/silpa/jsonrpc/json.py
@@ -0,0 +1,230 @@
+
+"""
+ Copyright (c) 2007 Jan-Klaas Kollhof
+
+ This file is part of jsonrpc.
+
+ jsonrpc is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this software; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+from types import *
+import re
+
+CharReplacements ={
+ '\t': '\\t',
+ '\b': '\\b',
+ '\f': '\\f',
+ '\n': '\\n',
+ '\r': '\\r',
+ '\\': '\\\\',
+ '/': '\\/',
+ '"': '\\"'}
+
+EscapeCharToChar = {
+ 't': '\t',
+ 'b': '\b',
+ 'f': '\f',
+ 'n': '\n',
+ 'r': '\r',
+ '\\': '\\',
+ '/': '/',
+ '"' : '"'}
+
+StringEscapeRE= re.compile(r'[\x00-\x19\\"/\b\f\n\r\t]')
+Digits = ['0', '1', '2','3','4','5','6','7','8','9']
+
+
+class JSONEncodeException(Exception):
+ def __init__(self, obj):
+ Exception.__init__(self)
+ self.obj = obj
+
+ def __str__(self):
+ return "Object not encodeable: %s" % self.obj
+
+
+class JSONDecodeException(Exception):
+ def __init__(self, message):
+ Exception.__init__(self)
+ self.message = message
+
+ def __str__(self):
+ return self.message
+
+
+def escapeChar(match):
+ c=match.group(0)
+ try:
+ replacement = CharReplacements[c]
+ return replacement
+ except KeyError:
+ d = ord(c)
+ if d < 32:
+ return '\\u%04x' % d
+ else:
+ return c
+
+def dumps(obj):
+ return unicode("".join([part for part in dumpParts (obj)]))
+
+def dumpParts (obj):
+ objType = type(obj)
+ if obj == None:
+ yield u'null'
+ elif objType is BooleanType:
+ if obj:
+ yield u'true'
+ else:
+ yield u'false'
+ elif objType is DictionaryType:
+ yield u'{'
+ isFirst=True
+ for (key, value) in obj.items():
+ if isFirst:
+ isFirst=False
+ else:
+ yield u","
+ yield u'"' + StringEscapeRE.sub(escapeChar, key) +u'":'
+ for part in dumpParts (value):
+ yield part
+ yield u'}'
+ elif objType in StringTypes:
+ yield u'"' + StringEscapeRE.sub(escapeChar, obj) +u'"'
+
+ elif objType in [TupleType, ListType, GeneratorType]:
+ yield u'['
+ isFirst=True
+ for item in obj:
+ if isFirst:
+ isFirst=False
+ else:
+ yield u","
+ for part in dumpParts (item):
+ yield part
+ yield u']'
+ elif objType in [IntType, LongType, FloatType]:
+ yield unicode(obj)
+ else:
+ raise JSONEncodeException(obj)
+
+
+def loads(s):
+ stack = []
+ chars = iter(s)
+ value = None
+ currCharIsNext=False
+
+ try:
+ while(1):
+ skip = False
+ if not currCharIsNext:
+ c = chars.next()
+ while(c in [' ', '\t', '\r','\n']):
+ c = chars.next()
+ currCharIsNext=False
+ if c=='"':
+ value = ''
+ try:
+ c=chars.next()
+ while c != '"':
+ if c == '\\':
+ c=chars.next()
+ try:
+ value+=EscapeCharToChar[c]
+ except KeyError:
+ if c == 'u':
+ hexCode = chars.next() + chars.next() + chars.next() + chars.next()
+ value += unichr(int(hexCode,16))
+ else:
+ raise JSONDecodeException("Bad Escape Sequence Found")
+ else:
+ value+=c
+ c=chars.next()
+ except StopIteration:
+ raise JSONDecodeException("Expected end of String")
+ elif c == '{':
+ stack.append({})
+ skip=True
+ elif c =='}':
+ value = stack.pop()
+ elif c == '[':
+ stack.append([])
+ skip=True
+ elif c == ']':
+ value = stack.pop()
+ elif c in [',',':']:
+ skip=True
+ elif c in Digits or c == '-':
+ digits=[c]
+ c = chars.next()
+ numConv = int
+ try:
+ while c in Digits:
+ digits.append(c)
+ c = chars.next()
+ if c == ".":
+ numConv=float
+ digits.append(c)
+ c = chars.next()
+ while c in Digits:
+ digits.append(c)
+ c = chars.next()
+ if c.upper() == 'E':
+ digits.append(c)
+ c = chars.next()
+ if c in ['+','-']:
+ digits.append(c)
+ c = chars.next()
+ while c in Digits:
+ digits.append(c)
+ c = chars.next()
+ else:
+ raise JSONDecodeException("Expected + or -")
+ except StopIteration:
+ pass
+ value = numConv("".join(digits))
+ currCharIsNext=True
+
+ elif c in ['t','f','n']:
+ kw = c+ chars.next() + chars.next() + chars.next()
+ if kw == 'null':
+ value = None
+ elif kw == 'true':
+ value = True
+ elif kw == 'fals' and chars.next() == 'e':
+ value = False
+ else:
+ raise JSONDecodeException('Expected Null, False or True')
+ else:
+ raise JSONDecodeException('Expected []{}," or Number, Null, False or True')
+
+ if not skip:
+ if len(stack):
+ top = stack[-1]
+ if type(top) is ListType:
+ top.append(value)
+ elif type(top) is DictionaryType:
+ stack.append(value)
+ elif type(top) in StringTypes:
+ key = stack.pop()
+ stack[-1][key] = value
+ else:
+ raise JSONDecodeException("Expected dictionary key, or start of a value")
+ else:
+ return value
+ except StopIteration:
+ raise JSONDecodeException("Unexpected end of JSON source")
+
+
diff --git a/silpa/jsonrpc/modpywrapper.py b/silpa/jsonrpc/modpywrapper.py
new file mode 100644
index 0000000..3e61017
--- /dev/null
+++ b/silpa/jsonrpc/modpywrapper.py
@@ -0,0 +1,52 @@
+import sys, os
+from jsonrpc import ServiceHandler, ServiceException
+
+
+class ServiceImplementaionNotFound(ServiceException):
+ pass
+
+
+class ModPyServiceHandler(ServiceHandler):
+ def __init__(self, req):
+ self.req = req
+ ServiceHandler.__init__(self, None)
+
+
+ def findServiceEndpoint(self, name):
+ req = self.req
+
+ (modulePath, fileName) = os.path.split(req.filename)
+ (moduleName, ext) = os.path.splitext(fileName)
+
+ if not os.path.exists(os.path.join(modulePath, moduleName + ".py")):
+ raise ServiceImplementaionNotFound()
+ else:
+ if not modulePath in sys.path:
+ sys.path.insert(0, modulePath)
+
+ from mod_python import apache
+ module = apache.import_module(moduleName, log=1)
+
+ if hasattr(module, "service"):
+ self.service = module.service
+ elif hasattr(module, "Service"):
+ self.service = module.Service()
+ else:
+ self.service = module
+
+ return ServiceHandler.findServiceEndpoint(self, name)
+
+
+ def handleRequest(self, data):
+ self.req.content_type = "text/plain"
+ data = self.req.read()
+ resultData = ServiceHandler.handleRequest(self, data)
+ self.req.write(resultData)
+ self.req.flush()
+
+def handler(req):
+ from mod_python import apache
+ ModPyServiceHandler(req).handleRequest(req)
+ return apache.OK
+
+
diff --git a/silpa/jsonrpc/proxy.py b/silpa/jsonrpc/proxy.py
new file mode 100644
index 0000000..e61fd13
--- /dev/null
+++ b/silpa/jsonrpc/proxy.py
@@ -0,0 +1,49 @@
+
+"""
+ Copyright (c) 2007 Jan-Klaas Kollhof
+
+ This file is part of jsonrpc.
+
+ jsonrpc is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this software; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+import urllib
+from jsonrpc.json import dumps, loads
+
+class JSONRPCException(Exception):
+ def __init__(self, rpcError):
+ Exception.__init__(self)
+ self.error = rpcError
+
+class ServiceProxy(object):
+ def __init__(self, serviceURL, serviceName=None):
+ self.__serviceURL = serviceURL
+ self.__serviceName = serviceName
+
+ def __getattr__(self, name):
+ if self.__serviceName != None:
+ name = "%s.%s" % (self.__serviceName, name)
+ return ServiceProxy(self.__serviceURL, name)
+
+ def __call__(self, *args):
+ postdata = dumps({"method": self.__serviceName, 'params': args, 'id':'jsonrpc'})
+ respdata = urllib.urlopen(self.__serviceURL, postdata).read()
+ resp = loads(respdata)
+ if resp['error'] != None:
+ raise JSONRPCException(resp['error'])
+ else:
+ return resp['result']
+
+
diff --git a/silpa/jsonrpc/serviceHandler.py b/silpa/jsonrpc/serviceHandler.py
new file mode 100644
index 0000000..3fb5675
--- /dev/null
+++ b/silpa/jsonrpc/serviceHandler.py
@@ -0,0 +1,152 @@
+
+"""
+ Copyright (c) 2007 Jan-Klaas Kollhof
+
+ This file is part of jsonrpc.
+
+ jsonrpc is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this software; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+from common import *
+from jsonrpc import JSONEncodeException
+from jsonrpc import dumps
+from jsonrpc import loads
+from utils import *
+
+
+def ServiceMethod(fn):
+ fn.IsServiceMethod = True
+ return fn
+
+class ServiceException(Exception):
+ pass
+
+class ServiceRequestNotTranslatable(ServiceException):
+ pass
+
+class BadServiceRequest(ServiceException):
+ pass
+
+class ServiceMethodNotFound(ServiceException):
+ def __init__(self, name):
+ self.methodName = name
+
+class ServiceHandler(object):
+
+ def __init__(self, service):
+ self.service = service
+
+ def handleRequest(self, json):
+ err = None
+ result = None
+ id_ = ''
+ args = None
+ try:
+ req = self.translateRequest(json)
+ except ServiceRequestNotTranslatable, e:
+ err = e
+ req = {'id':id_}
+
+ if err == None:
+ try:
+ id_ = req['id']
+ methName = req['method']
+ try:
+ args = req['params']
+ except:
+ pass
+ except:
+ err = BadServiceRequest(json)
+ module_instance=None
+ if err == None:
+ try:
+ meth = self.locate(methName)
+ except Exception, e:
+ err = e
+
+ if err == None:
+ try:
+ result = self.call(meth, args)
+ except Exception, e:
+ err = e
+
+ resultdata = self.translateResult(result, err, id_)
+ return resultdata
+
+ def translateRequest(self, data):
+ try:
+ req = loads(data)
+ except:
+ raise ServiceRequestNotTranslatable(data)
+ return req
+
+ def locate(self, name):
+ try:
+ if name.startswith("system."):
+ return getattr(self, name.split(".")[1])
+ module_manager = ModuleManager()
+ modules = module_manager.getAllModules()
+ for module in modules:
+ for key in dir(module):
+ try:
+ method = getattr(module, key)
+ if getattr(method, "IsServiceMethod"):
+ if ("modules."+module.__class__.__name__ + "." + key) == name :
+ meth = method
+ break
+ except AttributeError:
+ pass
+ if meth==None :
+ raise ServiceMethodNotFound(name)
+ except AttributeError:
+ raise ServiceMethodNotFound(name)
+
+ return meth
+ def listMethods(self):
+ results = []
+ module_manager = ModuleManager()
+ modules = module_manager.getAllModules()
+ for module in modules:
+ for key in dir(module):
+ method = getattr(module, key)
+ try:
+ if getattr(method, "IsServiceMethod"):
+ results.append("modules."+module.__class__.__name__ + "." + key)
+ except:
+ pass
+ results.sort()
+ return results
+
+ def call(self, meth, args=None):
+ if args == None :
+ return meth()
+ else:
+ return meth(args) #return meth(*args)
+
+ def translateResult(self, rslt, err, id_):
+ if err != None:
+ err = {"name": err.__class__.__name__, "message":err.message}
+ rslt = None
+
+ try:
+ data = dumps({"result":rslt, "id":id_, "error":err})
+ except JSONEncodeException, e:
+ err = {"name": "JSONEncodeException", "message":"Result Object Not Serializable"}
+ data = dumps({"result":None, "id":id_, "error":err})
+
+ return data
+# --------------------------------------------------------------------
+# request dispatcher
+