ladon-dev-team team mailing list archive
-
ladon-dev-team team
-
Mailing list archive
-
Message #00085
[Merge] lp:~j-launchpad-dennis/ladon/ladon into lp:ladon
Dennis Plöger has proposed merging lp:~j-launchpad-dennis/ladon/ladon into lp:ladon.
Requested reviews:
Ladon Developer (ladon-dev-team)
For more details, see:
https://code.launchpad.net/~j-launchpad-dennis/ladon/ladon/+merge/151397
XMLRPC-interface with XRDL-support for python framework
--
https://code.launchpad.net/~j-launchpad-dennis/ladon/ladon/+merge/151397
Your team Ladon Developer is requested to review the proposed merge of lp:~j-launchpad-dennis/ladon/ladon into lp:ladon.
=== modified file 'frameworks/python/src/ladon/interfaces/__init__.py'
--- frameworks/python/src/ladon/interfaces/__init__.py 2012-10-18 12:05:57 +0000
+++ frameworks/python/src/ladon/interfaces/__init__.py 2013-03-03 21:20:27 +0000
@@ -72,3 +72,4 @@
import ladon.interfaces.soap11
import ladon.interfaces.jsonwsp
import ladon.interfaces.jsonrpc10
+import ladon.interfaces.xmlrpc
\ No newline at end of file
=== added file 'frameworks/python/src/ladon/interfaces/xmlrpc.py'
--- frameworks/python/src/ladon/interfaces/xmlrpc.py 1970-01-01 00:00:00 +0000
+++ frameworks/python/src/ladon/interfaces/xmlrpc.py 2013-03-03 21:20:27 +0000
@@ -0,0 +1,600 @@
+# -*- coding: utf-8 -*-
+
+"""XMLRPC-Interface for ladon.
+"""
+
+__author__ = 'Dennis Ploeger <develop@xxxxxxxxxxxxxx>'
+
+from StringIO import StringIO
+
+import base64
+import re
+import sys
+import datetime
+import traceback
+from ladon.exceptions.dispatcher import UndefinedServiceMethod
+from ladon.exceptions.service import ClientFault
+
+from ladon.interfaces import expose
+
+from ladon.interfaces.base import BaseInterface, \
+ ServiceDescriptor, BaseRequestHandler, BaseResponseHandler, BaseFaultHandler
+from ladon.compat import pytype_support, BytesIO, PORTABLE_STRING
+
+from xml.dom import Node
+
+from xml.dom.minidom import parseString, getDOMImplementation
+
+def u(instring):
+ if sys.version_info[0]==2:
+ return PORTABLE_STRING(instring, 'utf-8')
+ else:
+ return PORTABLE_STRING(instring)
+
+def is_binary(test_string):
+ """Return true if the given filename is binary.
+ @attention: based on http://bytes
+ .com/topic/python/answers/21222-determine-file-type-binary-text on 6/08/2010
+ @author: Trent Mick <TrentM@xxxxxxxxxxxxxxx>
+ @author: Jorge Orpinel <jorge@xxxxxxxxxxx>"""
+ fin = StringIO(test_string)
+ try:
+ CHUNKSIZE = 1024
+ while 1:
+ chunk = fin.read(CHUNKSIZE)
+ if '\0' in chunk: # found null byte
+ return True
+ if len(chunk) < CHUNKSIZE:
+ break # done
+ finally:
+ fin.close()
+
+ return False
+
+class XMLRPCServiceDescriptor(ServiceDescriptor):
+ """Generate XRDL (based on
+ http://code.google.com/p/xrdl/source/browse/documentation/xrdl.xsd)"""
+
+ _content_type = 'text/xml'
+ _special_types = []
+
+ def _get_type_name(self, type_class):
+
+ try:
+
+ return type_class.__name__
+
+ except:
+
+ return type(type_class).__name__
+
+ def _type_to_xmlrpc(self, type_name):
+
+ if type_name in ['str', 'unicode']:
+
+ return 'string'
+
+ elif type_name in ['int', 'long']:
+
+ return 'int'
+
+ elif type_name in ['float']:
+
+ return 'double'
+
+ elif type_name == 'datetime.time':
+
+ return 'dateTime8601'
+
+ elif type_name == 'bool':
+
+ return 'boolean'
+
+ elif type_name in self._special_types:
+
+ return type_name
+
+ elif type_name in ['list', 'tuple', 'set']:
+
+ return 'array'
+
+ elif type_name == 'dict':
+
+ return 'struct'
+
+ else:
+
+ # Assume binary if no other type matches
+
+ return 'base64'
+
+ def generate(
+ self,
+ servicename,
+ servicenumber,
+ typemanager,
+ methodlist,
+ service_url,
+ encoding
+ ):
+
+ type_dict = typemanager.type_dict
+
+ for type_class in type_dict:
+
+ self._special_types.append(self._get_type_name(type_class))
+
+ impl = getDOMImplementation()
+
+ resp_doc = impl.createDocument(None, 'service', None)
+
+ resp_doc.documentElement.setAttribute(
+ 'url',
+ service_url
+ )
+
+ resp_doc.documentElement.setAttribute(
+ 'ns',
+ ''
+ )
+
+ resp_doc.documentElement.setAttribute(
+ 'name',
+ servicename
+ )
+
+ # Types
+
+ types_el = resp_doc.createElement('types')
+
+ for type_class, type_info in type_dict.iteritems():
+ type_el = resp_doc.createElement('type')
+
+ type_el.setAttribute('name', type_info['name'])
+
+ for member in type_info['attributes']:
+
+ (member_name, member_type, member_opt) = member
+
+ member_el = resp_doc.createElement('member')
+
+ member_el.setAttribute(
+ 'type',
+ self._type_to_xmlrpc(
+ self._get_type_name(member_type)
+ )
+ )
+
+ member_el.appendChild(
+ resp_doc.createTextNode(member_name)
+ )
+
+ type_el.appendChild(member_el)
+
+ types_el.appendChild(type_el)
+
+ resp_doc.documentElement.appendChild(types_el)
+
+ # Methods
+
+ methods_el = resp_doc.createElement('methods')
+
+ for method in methodlist:
+
+ method_info = method.serialize()
+
+ method_el = resp_doc.createElement('method')
+
+ method_el.setAttribute('name', method.name())
+ method_el.setAttribute(
+ 'result',
+ self._type_to_xmlrpc(
+ self._get_type_name(method_info['rtype'][0])
+ )
+ )
+
+ for param in method.args():
+
+ param_el = resp_doc.createElement('param')
+
+ param_el.setAttribute(
+ 'type',
+ self._type_to_xmlrpc(
+ self._get_type_name(param['type'])
+ )
+ )
+
+ param_el.appendChild(
+ resp_doc.createTextNode(param['name'])
+ )
+
+ method_el.appendChild(param_el)
+
+ methods_el.appendChild(method_el)
+
+ resp_doc.documentElement.appendChild(methods_el)
+
+ return resp_doc.toxml(encoding = encoding)
+
+class XMLRPCRequestHandler(BaseRequestHandler):
+
+ def get_param_value(self, node):
+ """Turn a param node into a value
+ """
+
+ type_defined = False
+
+ for node_index in range(0, node.childNodes.length):
+
+ if node.childNodes.item(node_index).nodeType != Node.TEXT_NODE:
+ type_defined = True
+
+ type_node = node.childNodes.item(node_index)
+
+ current_type = type_node.tagName
+
+ if not type_defined:
+ # No type give, assume String
+
+ current_type = "string"
+
+ if current_type in ['i4', 'int']:
+ return int(type_node.firstChild.data.strip())
+ elif current_type == 'boolean':
+ return int(type_node.firstChild.data.strip()) == 1
+ elif current_type == 'double':
+ return float(type_node.firstChild.data.strip())
+ elif current_type in ['dateTime.iso8601', 'base64', 'string']:
+ return type_node.firstChild.data.strip()
+
+ # We have a list data type
+
+ if current_type == 'struct':
+ return_dict = {}
+
+ members = type_node.getElementsByTagName('member')
+
+ for member_index in range(0, members.length):
+
+ current_member = members.item(member_index)
+
+ name_node = current_member.getElementsByTagName('name')
+
+ if name_node.length > 1:
+ raise ClientFault('More than one name nodes in a struct')
+
+ if name_node.firstChild.nodeType != Node.TEXT_NODE:
+ raise ClientFault(
+ 'Unexpected Node type %d while parsing '
+ 'a struct member name' %
+ name_node.firstChild.nodeType
+ )
+
+ key = name_node.firstChild.data.strip()
+
+ value_node = current_member.getElementsByTagName('value')
+
+ value = self.get_param_value(value_node)
+
+ return_dict[key] = value
+
+ return return_dict
+
+ if current_type == 'array':
+
+ return_list = []
+
+ values = type_node.getElementsByTagName('value')
+
+ for value_index in range(0, values.length):
+
+ return_list.append(
+ self.get_param_value(values.item(value_index))
+ )
+
+ return return_list
+
+ def parse_request(self,req,sinfo,encoding):
+
+ req_dict = {'args': {}}
+
+ req_doc = parseString(req)
+
+ # Find method name
+
+ method_name = req_doc.getElementsByTagName('methodName')
+
+ req_dict['methodname'] = method_name.item(0).firstChild.data.strip()
+
+ # Fill params
+
+ if sinfo.method(req_dict['methodname']) is None:
+
+ # Unknown method
+
+ raise UndefinedServiceMethod(
+ 'xmlrpc',
+ sinfo.servicename,
+ 'Unknown method %s' % req_dict['methodname']
+ )
+
+ args = sinfo.method(req_dict['methodname']).args()
+
+ params = req_doc.getElementsByTagName('param')
+
+ for current_param in range(0, params.length):
+
+ node = params.item(current_param)
+
+ value_node = node.getElementsByTagName('value').item(0)
+
+ value = self.get_param_value(value_node)
+
+ current_arg = args[current_param]
+
+ req_dict['args'][current_arg['name']] = value
+
+ return req_dict
+
+class XMLRPCResponseHandler(BaseResponseHandler):
+
+ _content_type = 'text/xml'
+ _stringify_res_dict = False
+ datetime_re = None
+
+ def get_xml_value(self, value, resp_doc):
+
+ value_el = resp_doc.createElement('value')
+
+ if isinstance(value, (str, unicode)):
+
+ # Check for special cases base64, dateTime.iso8601
+
+ if is_binary(value):
+
+ base64_el = resp_doc.createElement('base64')
+ base64_el.appendChild(
+ resp_doc.createTextNode(base64.b64encode(str(value)))
+ )
+
+ value_el.appendChild(base64_el)
+
+ elif self.datetime_re.match(value):
+
+ datetime_el = resp_doc.createElement('dateTime.iso8601')
+ datetime_el.appendChild(
+ resp_doc.createTextNode(value)
+ )
+
+ value_el.appendChild(datetime_el)
+
+ elif isinstance(value, unicode):
+
+ string_el = resp_doc.createElement('string')
+ string_el.appendChild(
+ resp_doc.createTextNode(value)
+ )
+
+ value_el.appendChild(string_el)
+
+ else:
+
+ string_el = resp_doc.createElement('string')
+ string_el.appendChild(
+ resp_doc.createTextNode(u(value))
+ )
+
+ value_el.appendChild(string_el)
+
+ elif isinstance(value, int):
+
+ int_el = resp_doc.createElement('int')
+ int_el.appendChild(
+ resp_doc.createTextNode(value)
+ )
+
+ value_el.appendChild(int_el)
+
+ elif isinstance(value, float):
+
+ double_el = resp_doc.createElement('double')
+ double_el.appendChild(
+ resp_doc.createTextNode(value)
+ )
+
+ value_el.appendChild(double_el)
+
+ elif isinstance(value, bool):
+
+ if value:
+ value = 1
+ else:
+ value = 0
+
+ boolean_el = resp_doc.createElement('boolean')
+ boolean_el.appendChild(
+ resp_doc.createTextNode(value)
+ )
+
+ value_el.appendChild(boolean_el)
+
+ elif isinstance(value, datetime.time):
+
+ datetime_el = resp_doc.createElement('dateTime.iso8601')
+ datetime_el.appendChild(
+ resp_doc.createTextNode(
+ value.strftime('%Y%m%dT%H:%M:%S')
+ )
+ )
+
+ value_el.appendChild(datetime_el)
+
+ elif isinstance(value, dict):
+
+ struct_el = resp_doc.createElement('struct')
+
+ for current_member in range(0, len(value.keys())):
+
+ member_key = value.keys()[current_member]
+
+ member_value_el = self.get_xml_value(
+ value[member_key],
+ resp_doc
+ )
+
+ member_el = resp_doc.createElement('member')
+
+ name_el = resp_doc.createElement('name')
+ name_el.appendChild(
+ resp_doc.createTextNode(member_key)
+ )
+
+ member_el.appendChild(name_el)
+ member_el.appendChild(member_value_el)
+
+ struct_el.appendChild(member_el)
+
+ value_el.appendChild(struct_el)
+
+ elif isinstance(value, list):
+
+ array_el = resp_doc.createElement('array')
+ data_el = resp_doc.createElement('data')
+
+ for current_value in range(0, len(value)):
+ data_value_el = self.get_xml_value(
+ value[current_value],
+ resp_doc
+ )
+
+ data_el.appendChild(data_value_el)
+
+ array_el.appendChild(data_el)
+
+ value_el.appendChild(array_el)
+
+ return value_el
+
+ def build_response(self,res_dict,sinfo,encoding):
+ self.datetime_re = re.compile('\d{8}T\d{2}:\d{2}:\d{2}')
+
+ value = res_dict['result']
+
+ impl = getDOMImplementation()
+
+ resp_doc = impl.createDocument(None, 'methodResponse', None)
+ params_el = resp_doc.createElement('params')
+ param_el = resp_doc.createElement('param')
+
+ value_el = self.get_xml_value(value, resp_doc)
+
+ param_el.appendChild(value_el)
+
+ params_el.appendChild(param_el)
+
+ resp_doc.documentElement.appendChild(params_el)
+
+ return resp_doc.toxml(encoding = encoding)
+
+class XMLRPCFaultHandler(BaseFaultHandler):
+ _content_type = 'text/xml'
+ _stringify_res_dict = False
+
+ def build_fault_response(self,service_exc,sinfo,methodname,encoding):
+ if service_exc.detail:
+ detail = service_exc.detail
+ else:
+ detail = traceback.format_exc()
+
+ detail = detail.replace('\r\n','\n')
+
+ impl = getDOMImplementation()
+
+ resp_doc = impl.createDocument(None, 'methodResponse', None)
+
+ fault_el = resp_doc.createElement('fault')
+ value_el = resp_doc.createElement('value')
+ struct_el = resp_doc.createElement('struct')
+
+ # Fault-Code
+
+ code_member_el = resp_doc.createElement('member')
+
+ code_name_el = resp_doc.createElement('name')
+ code_name_el.appendChild(
+ resp_doc.createTextNode('faultCode')
+ )
+
+ code_member_el.appendChild(code_name_el)
+
+ code_value_el = resp_doc.createElement('value')
+
+ code_value_int_el = resp_doc.createElement('int')
+ code_value_int_el.appendChild(
+ resp_doc.createTextNode('99')
+ )
+
+ code_value_el.appendChild(code_value_int_el)
+
+ code_member_el.appendChild(code_value_el)
+
+ struct_el.appendChild(code_member_el)
+
+ # Fault-String
+
+ string_member_el = resp_doc.createElement('member')
+
+ string_name_el = resp_doc.createElement('name')
+ string_name_el.appendChild(
+ resp_doc.createTextNode('faultString')
+ )
+
+ string_member_el.appendChild(string_name_el)
+
+ string_value_el = resp_doc.createElement('value')
+
+ string_value_string_el = resp_doc.createElement('string')
+ string_value_string_el.appendChild(
+ resp_doc.createTextNode(service_exc.faultstring + "\n" + detail)
+ )
+
+ string_value_el.appendChild(string_value_string_el)
+
+ string_member_el.appendChild(string_value_el)
+
+ struct_el.appendChild(string_member_el)
+
+ value_el.appendChild(struct_el)
+ fault_el.appendChild(value_el)
+
+ resp_doc.documentElement.appendChild(fault_el)
+
+ return resp_doc.toxml(encoding = encoding)
+
+@expose
+class XMLRPCInterface(BaseInterface):
+
+ def __init__(self,sinfo,**kw):
+ def_kw = {
+ 'service_descriptor': XMLRPCServiceDescriptor,
+ 'request_handler': XMLRPCRequestHandler,
+ 'response_handler': XMLRPCResponseHandler,
+ 'fault_handler': XMLRPCFaultHandler}
+ def_kw.update(kw)
+ BaseInterface.__init__(self,sinfo,**def_kw)
+
+ @staticmethod
+ def _interface_name():
+ return 'xmlrpc'
+
+ @staticmethod
+ def _accept_basetype(typ):
+ return pytype_support.count(typ)>0
+
+ @staticmethod
+ def _accept_list():
+ return True
+
+ @staticmethod
+ def _accept_dict():
+ return True
\ No newline at end of file
Follow ups