Merge lp:~j-launchpad-dennis/ladon/ladon into lp:ladon

Proposed by Dennis Plöger
Status: Merged
Merged at revision: 98
Proposed branch: lp:~j-launchpad-dennis/ladon/ladon
Merge into: lp:ladon
Diff against target: 615 lines (+601/-0)
2 files modified
frameworks/python/src/ladon/interfaces/__init__.py (+1/-0)
frameworks/python/src/ladon/interfaces/xmlrpc.py (+600/-0)
To merge this branch: bzr merge lp:~j-launchpad-dennis/ladon/ladon
Reviewer Review Type Date Requested Status
jsgaarde Approve
Review via email: mp+151397@code.launchpad.net

Description of the change

XMLRPC-interface with XRDL-support for python framework

To post a comment you must log in.
Revision history for this message
jsgaarde (jakob-simon-gaarde) wrote :

Looks ok

review: Approve
lp:~j-launchpad-dennis/ladon/ladon updated
97. By jsgaarde

JSONWSP version checking stuff

98. By jsgaarde

Added contribution from Dennis Plöeger

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'frameworks/python/src/ladon/interfaces/__init__.py'
2--- frameworks/python/src/ladon/interfaces/__init__.py 2012-10-18 12:05:57 +0000
3+++ frameworks/python/src/ladon/interfaces/__init__.py 2013-03-03 21:20:27 +0000
4@@ -72,3 +72,4 @@
5 import ladon.interfaces.soap11
6 import ladon.interfaces.jsonwsp
7 import ladon.interfaces.jsonrpc10
8+import ladon.interfaces.xmlrpc
9\ No newline at end of file
10
11=== added file 'frameworks/python/src/ladon/interfaces/xmlrpc.py'
12--- frameworks/python/src/ladon/interfaces/xmlrpc.py 1970-01-01 00:00:00 +0000
13+++ frameworks/python/src/ladon/interfaces/xmlrpc.py 2013-03-03 21:20:27 +0000
14@@ -0,0 +1,600 @@
15+# -*- coding: utf-8 -*-
16+
17+"""XMLRPC-Interface for ladon.
18+"""
19+
20+__author__ = 'Dennis Ploeger <develop@dieploegers.de>'
21+
22+from StringIO import StringIO
23+
24+import base64
25+import re
26+import sys
27+import datetime
28+import traceback
29+from ladon.exceptions.dispatcher import UndefinedServiceMethod
30+from ladon.exceptions.service import ClientFault
31+
32+from ladon.interfaces import expose
33+
34+from ladon.interfaces.base import BaseInterface, \
35+ ServiceDescriptor, BaseRequestHandler, BaseResponseHandler, BaseFaultHandler
36+from ladon.compat import pytype_support, BytesIO, PORTABLE_STRING
37+
38+from xml.dom import Node
39+
40+from xml.dom.minidom import parseString, getDOMImplementation
41+
42+def u(instring):
43+ if sys.version_info[0]==2:
44+ return PORTABLE_STRING(instring, 'utf-8')
45+ else:
46+ return PORTABLE_STRING(instring)
47+
48+def is_binary(test_string):
49+ """Return true if the given filename is binary.
50+ @attention: based on http://bytes
51+ .com/topic/python/answers/21222-determine-file-type-binary-text on 6/08/2010
52+ @author: Trent Mick <TrentM@ActiveState.com>
53+ @author: Jorge Orpinel <jorge@orpinel.com>"""
54+ fin = StringIO(test_string)
55+ try:
56+ CHUNKSIZE = 1024
57+ while 1:
58+ chunk = fin.read(CHUNKSIZE)
59+ if '\0' in chunk: # found null byte
60+ return True
61+ if len(chunk) < CHUNKSIZE:
62+ break # done
63+ finally:
64+ fin.close()
65+
66+ return False
67+
68+class XMLRPCServiceDescriptor(ServiceDescriptor):
69+ """Generate XRDL (based on
70+ http://code.google.com/p/xrdl/source/browse/documentation/xrdl.xsd)"""
71+
72+ _content_type = 'text/xml'
73+ _special_types = []
74+
75+ def _get_type_name(self, type_class):
76+
77+ try:
78+
79+ return type_class.__name__
80+
81+ except:
82+
83+ return type(type_class).__name__
84+
85+ def _type_to_xmlrpc(self, type_name):
86+
87+ if type_name in ['str', 'unicode']:
88+
89+ return 'string'
90+
91+ elif type_name in ['int', 'long']:
92+
93+ return 'int'
94+
95+ elif type_name in ['float']:
96+
97+ return 'double'
98+
99+ elif type_name == 'datetime.time':
100+
101+ return 'dateTime8601'
102+
103+ elif type_name == 'bool':
104+
105+ return 'boolean'
106+
107+ elif type_name in self._special_types:
108+
109+ return type_name
110+
111+ elif type_name in ['list', 'tuple', 'set']:
112+
113+ return 'array'
114+
115+ elif type_name == 'dict':
116+
117+ return 'struct'
118+
119+ else:
120+
121+ # Assume binary if no other type matches
122+
123+ return 'base64'
124+
125+ def generate(
126+ self,
127+ servicename,
128+ servicenumber,
129+ typemanager,
130+ methodlist,
131+ service_url,
132+ encoding
133+ ):
134+
135+ type_dict = typemanager.type_dict
136+
137+ for type_class in type_dict:
138+
139+ self._special_types.append(self._get_type_name(type_class))
140+
141+ impl = getDOMImplementation()
142+
143+ resp_doc = impl.createDocument(None, 'service', None)
144+
145+ resp_doc.documentElement.setAttribute(
146+ 'url',
147+ service_url
148+ )
149+
150+ resp_doc.documentElement.setAttribute(
151+ 'ns',
152+ ''
153+ )
154+
155+ resp_doc.documentElement.setAttribute(
156+ 'name',
157+ servicename
158+ )
159+
160+ # Types
161+
162+ types_el = resp_doc.createElement('types')
163+
164+ for type_class, type_info in type_dict.iteritems():
165+ type_el = resp_doc.createElement('type')
166+
167+ type_el.setAttribute('name', type_info['name'])
168+
169+ for member in type_info['attributes']:
170+
171+ (member_name, member_type, member_opt) = member
172+
173+ member_el = resp_doc.createElement('member')
174+
175+ member_el.setAttribute(
176+ 'type',
177+ self._type_to_xmlrpc(
178+ self._get_type_name(member_type)
179+ )
180+ )
181+
182+ member_el.appendChild(
183+ resp_doc.createTextNode(member_name)
184+ )
185+
186+ type_el.appendChild(member_el)
187+
188+ types_el.appendChild(type_el)
189+
190+ resp_doc.documentElement.appendChild(types_el)
191+
192+ # Methods
193+
194+ methods_el = resp_doc.createElement('methods')
195+
196+ for method in methodlist:
197+
198+ method_info = method.serialize()
199+
200+ method_el = resp_doc.createElement('method')
201+
202+ method_el.setAttribute('name', method.name())
203+ method_el.setAttribute(
204+ 'result',
205+ self._type_to_xmlrpc(
206+ self._get_type_name(method_info['rtype'][0])
207+ )
208+ )
209+
210+ for param in method.args():
211+
212+ param_el = resp_doc.createElement('param')
213+
214+ param_el.setAttribute(
215+ 'type',
216+ self._type_to_xmlrpc(
217+ self._get_type_name(param['type'])
218+ )
219+ )
220+
221+ param_el.appendChild(
222+ resp_doc.createTextNode(param['name'])
223+ )
224+
225+ method_el.appendChild(param_el)
226+
227+ methods_el.appendChild(method_el)
228+
229+ resp_doc.documentElement.appendChild(methods_el)
230+
231+ return resp_doc.toxml(encoding = encoding)
232+
233+class XMLRPCRequestHandler(BaseRequestHandler):
234+
235+ def get_param_value(self, node):
236+ """Turn a param node into a value
237+ """
238+
239+ type_defined = False
240+
241+ for node_index in range(0, node.childNodes.length):
242+
243+ if node.childNodes.item(node_index).nodeType != Node.TEXT_NODE:
244+ type_defined = True
245+
246+ type_node = node.childNodes.item(node_index)
247+
248+ current_type = type_node.tagName
249+
250+ if not type_defined:
251+ # No type give, assume String
252+
253+ current_type = "string"
254+
255+ if current_type in ['i4', 'int']:
256+ return int(type_node.firstChild.data.strip())
257+ elif current_type == 'boolean':
258+ return int(type_node.firstChild.data.strip()) == 1
259+ elif current_type == 'double':
260+ return float(type_node.firstChild.data.strip())
261+ elif current_type in ['dateTime.iso8601', 'base64', 'string']:
262+ return type_node.firstChild.data.strip()
263+
264+ # We have a list data type
265+
266+ if current_type == 'struct':
267+ return_dict = {}
268+
269+ members = type_node.getElementsByTagName('member')
270+
271+ for member_index in range(0, members.length):
272+
273+ current_member = members.item(member_index)
274+
275+ name_node = current_member.getElementsByTagName('name')
276+
277+ if name_node.length > 1:
278+ raise ClientFault('More than one name nodes in a struct')
279+
280+ if name_node.firstChild.nodeType != Node.TEXT_NODE:
281+ raise ClientFault(
282+ 'Unexpected Node type %d while parsing '
283+ 'a struct member name' %
284+ name_node.firstChild.nodeType
285+ )
286+
287+ key = name_node.firstChild.data.strip()
288+
289+ value_node = current_member.getElementsByTagName('value')
290+
291+ value = self.get_param_value(value_node)
292+
293+ return_dict[key] = value
294+
295+ return return_dict
296+
297+ if current_type == 'array':
298+
299+ return_list = []
300+
301+ values = type_node.getElementsByTagName('value')
302+
303+ for value_index in range(0, values.length):
304+
305+ return_list.append(
306+ self.get_param_value(values.item(value_index))
307+ )
308+
309+ return return_list
310+
311+ def parse_request(self,req,sinfo,encoding):
312+
313+ req_dict = {'args': {}}
314+
315+ req_doc = parseString(req)
316+
317+ # Find method name
318+
319+ method_name = req_doc.getElementsByTagName('methodName')
320+
321+ req_dict['methodname'] = method_name.item(0).firstChild.data.strip()
322+
323+ # Fill params
324+
325+ if sinfo.method(req_dict['methodname']) is None:
326+
327+ # Unknown method
328+
329+ raise UndefinedServiceMethod(
330+ 'xmlrpc',
331+ sinfo.servicename,
332+ 'Unknown method %s' % req_dict['methodname']
333+ )
334+
335+ args = sinfo.method(req_dict['methodname']).args()
336+
337+ params = req_doc.getElementsByTagName('param')
338+
339+ for current_param in range(0, params.length):
340+
341+ node = params.item(current_param)
342+
343+ value_node = node.getElementsByTagName('value').item(0)
344+
345+ value = self.get_param_value(value_node)
346+
347+ current_arg = args[current_param]
348+
349+ req_dict['args'][current_arg['name']] = value
350+
351+ return req_dict
352+
353+class XMLRPCResponseHandler(BaseResponseHandler):
354+
355+ _content_type = 'text/xml'
356+ _stringify_res_dict = False
357+ datetime_re = None
358+
359+ def get_xml_value(self, value, resp_doc):
360+
361+ value_el = resp_doc.createElement('value')
362+
363+ if isinstance(value, (str, unicode)):
364+
365+ # Check for special cases base64, dateTime.iso8601
366+
367+ if is_binary(value):
368+
369+ base64_el = resp_doc.createElement('base64')
370+ base64_el.appendChild(
371+ resp_doc.createTextNode(base64.b64encode(str(value)))
372+ )
373+
374+ value_el.appendChild(base64_el)
375+
376+ elif self.datetime_re.match(value):
377+
378+ datetime_el = resp_doc.createElement('dateTime.iso8601')
379+ datetime_el.appendChild(
380+ resp_doc.createTextNode(value)
381+ )
382+
383+ value_el.appendChild(datetime_el)
384+
385+ elif isinstance(value, unicode):
386+
387+ string_el = resp_doc.createElement('string')
388+ string_el.appendChild(
389+ resp_doc.createTextNode(value)
390+ )
391+
392+ value_el.appendChild(string_el)
393+
394+ else:
395+
396+ string_el = resp_doc.createElement('string')
397+ string_el.appendChild(
398+ resp_doc.createTextNode(u(value))
399+ )
400+
401+ value_el.appendChild(string_el)
402+
403+ elif isinstance(value, int):
404+
405+ int_el = resp_doc.createElement('int')
406+ int_el.appendChild(
407+ resp_doc.createTextNode(value)
408+ )
409+
410+ value_el.appendChild(int_el)
411+
412+ elif isinstance(value, float):
413+
414+ double_el = resp_doc.createElement('double')
415+ double_el.appendChild(
416+ resp_doc.createTextNode(value)
417+ )
418+
419+ value_el.appendChild(double_el)
420+
421+ elif isinstance(value, bool):
422+
423+ if value:
424+ value = 1
425+ else:
426+ value = 0
427+
428+ boolean_el = resp_doc.createElement('boolean')
429+ boolean_el.appendChild(
430+ resp_doc.createTextNode(value)
431+ )
432+
433+ value_el.appendChild(boolean_el)
434+
435+ elif isinstance(value, datetime.time):
436+
437+ datetime_el = resp_doc.createElement('dateTime.iso8601')
438+ datetime_el.appendChild(
439+ resp_doc.createTextNode(
440+ value.strftime('%Y%m%dT%H:%M:%S')
441+ )
442+ )
443+
444+ value_el.appendChild(datetime_el)
445+
446+ elif isinstance(value, dict):
447+
448+ struct_el = resp_doc.createElement('struct')
449+
450+ for current_member in range(0, len(value.keys())):
451+
452+ member_key = value.keys()[current_member]
453+
454+ member_value_el = self.get_xml_value(
455+ value[member_key],
456+ resp_doc
457+ )
458+
459+ member_el = resp_doc.createElement('member')
460+
461+ name_el = resp_doc.createElement('name')
462+ name_el.appendChild(
463+ resp_doc.createTextNode(member_key)
464+ )
465+
466+ member_el.appendChild(name_el)
467+ member_el.appendChild(member_value_el)
468+
469+ struct_el.appendChild(member_el)
470+
471+ value_el.appendChild(struct_el)
472+
473+ elif isinstance(value, list):
474+
475+ array_el = resp_doc.createElement('array')
476+ data_el = resp_doc.createElement('data')
477+
478+ for current_value in range(0, len(value)):
479+ data_value_el = self.get_xml_value(
480+ value[current_value],
481+ resp_doc
482+ )
483+
484+ data_el.appendChild(data_value_el)
485+
486+ array_el.appendChild(data_el)
487+
488+ value_el.appendChild(array_el)
489+
490+ return value_el
491+
492+ def build_response(self,res_dict,sinfo,encoding):
493+ self.datetime_re = re.compile('\d{8}T\d{2}:\d{2}:\d{2}')
494+
495+ value = res_dict['result']
496+
497+ impl = getDOMImplementation()
498+
499+ resp_doc = impl.createDocument(None, 'methodResponse', None)
500+ params_el = resp_doc.createElement('params')
501+ param_el = resp_doc.createElement('param')
502+
503+ value_el = self.get_xml_value(value, resp_doc)
504+
505+ param_el.appendChild(value_el)
506+
507+ params_el.appendChild(param_el)
508+
509+ resp_doc.documentElement.appendChild(params_el)
510+
511+ return resp_doc.toxml(encoding = encoding)
512+
513+class XMLRPCFaultHandler(BaseFaultHandler):
514+ _content_type = 'text/xml'
515+ _stringify_res_dict = False
516+
517+ def build_fault_response(self,service_exc,sinfo,methodname,encoding):
518+ if service_exc.detail:
519+ detail = service_exc.detail
520+ else:
521+ detail = traceback.format_exc()
522+
523+ detail = detail.replace('\r\n','\n')
524+
525+ impl = getDOMImplementation()
526+
527+ resp_doc = impl.createDocument(None, 'methodResponse', None)
528+
529+ fault_el = resp_doc.createElement('fault')
530+ value_el = resp_doc.createElement('value')
531+ struct_el = resp_doc.createElement('struct')
532+
533+ # Fault-Code
534+
535+ code_member_el = resp_doc.createElement('member')
536+
537+ code_name_el = resp_doc.createElement('name')
538+ code_name_el.appendChild(
539+ resp_doc.createTextNode('faultCode')
540+ )
541+
542+ code_member_el.appendChild(code_name_el)
543+
544+ code_value_el = resp_doc.createElement('value')
545+
546+ code_value_int_el = resp_doc.createElement('int')
547+ code_value_int_el.appendChild(
548+ resp_doc.createTextNode('99')
549+ )
550+
551+ code_value_el.appendChild(code_value_int_el)
552+
553+ code_member_el.appendChild(code_value_el)
554+
555+ struct_el.appendChild(code_member_el)
556+
557+ # Fault-String
558+
559+ string_member_el = resp_doc.createElement('member')
560+
561+ string_name_el = resp_doc.createElement('name')
562+ string_name_el.appendChild(
563+ resp_doc.createTextNode('faultString')
564+ )
565+
566+ string_member_el.appendChild(string_name_el)
567+
568+ string_value_el = resp_doc.createElement('value')
569+
570+ string_value_string_el = resp_doc.createElement('string')
571+ string_value_string_el.appendChild(
572+ resp_doc.createTextNode(service_exc.faultstring + "\n" + detail)
573+ )
574+
575+ string_value_el.appendChild(string_value_string_el)
576+
577+ string_member_el.appendChild(string_value_el)
578+
579+ struct_el.appendChild(string_member_el)
580+
581+ value_el.appendChild(struct_el)
582+ fault_el.appendChild(value_el)
583+
584+ resp_doc.documentElement.appendChild(fault_el)
585+
586+ return resp_doc.toxml(encoding = encoding)
587+
588+@expose
589+class XMLRPCInterface(BaseInterface):
590+
591+ def __init__(self,sinfo,**kw):
592+ def_kw = {
593+ 'service_descriptor': XMLRPCServiceDescriptor,
594+ 'request_handler': XMLRPCRequestHandler,
595+ 'response_handler': XMLRPCResponseHandler,
596+ 'fault_handler': XMLRPCFaultHandler}
597+ def_kw.update(kw)
598+ BaseInterface.__init__(self,sinfo,**def_kw)
599+
600+ @staticmethod
601+ def _interface_name():
602+ return 'xmlrpc'
603+
604+ @staticmethod
605+ def _accept_basetype(typ):
606+ return pytype_support.count(typ)>0
607+
608+ @staticmethod
609+ def _accept_list():
610+ return True
611+
612+ @staticmethod
613+ def _accept_dict():
614+ return True
615\ No newline at end of file

Subscribers

People subscribed via source and target branches