more tuning of hinted object handling. added support for hinted object parsing in...
[OpenSRF.git] / src / python / osrf / gateway.py
1 from xml.dom import minidom
2 from xml.sax import handler, make_parser, saxutils
3 from json import *
4 from net_obj import *
5 import urllib, urllib2, sys, re
6
7 defaultHost = None
8 #paramRegex = re.compile('\%27')
9
10 class GatewayRequest:
11     def __init__(self, service, method, params=[]):
12         self.service = service
13         self.method = method
14         self.params = params
15
16     def send(self):
17         params = self.buildPOSTParams()
18         request = urllib2.Request(self.buildURL(), data=params)
19         response = None
20         try:
21             response =urllib2.urlopen(request)
22         except urllib2.HTTPError, e:
23             # log this?
24             sys.stderr.write('HTTPError: code=%d : %s' % (e.code, str(e)))
25             raise e
26             
27         return self.handleResponse(response)
28
29     def buildPOSTParams(self):
30
31         params = urllib.urlencode({   
32             'service': self.service,
33             'method': self.method,
34             'format': self.getFormat(),
35             'input_format': self.getInputFormat()
36         })
37
38         for p in self.params:
39             params += '&param=%s' % urllib.quote(self.encodeParam(p), "'/")
40         return params
41
42     def setDefaultHost(host):
43         global defaultHost
44         defaultHost = host
45     setDefaultHost = staticmethod(setDefaultHost)
46
47     def buildURL(self):
48         return 'http://%s/gateway' % defaultHost
49
50
51 class XMLGatewayRequest(GatewayRequest):
52
53     def __init__(self, service, method, *params):
54         GatewayRequest.__init__(self, service, method, list(params))
55
56     def getFormat(self):
57         return 'xml'
58
59     def getInputFormat(self):
60         return self.getFormat()
61
62     def handleResponse(self, response):
63         handler = XMLGatewayParser()
64         parser = make_parser()
65         parser.setContentHandler(handler)
66         parser.parse(response)
67         return handler.getResult()
68
69     def encodeParam(self, param):
70         return osrfObjectToXML(param);
71
72 class XMLGatewayParser(handler.ContentHandler):
73
74     def __init__(self):
75         self.result = None
76         self.objStack = []
77         self.keyStack = []
78         self.posStack = [] # for tracking array-based hinted object indices
79
80     def getResult(self):
81         return self.result
82
83     def __getAttr(self, attrs, name):
84         for (k, v) in attrs.items():
85             if k == name:
86                 return v
87         return None
88
89     def startElement(self, name, attrs):
90
91         # XXX add support for serializable objects!
92
93         if name == 'null':
94             self.appendChild(None)
95             return
96
97         if name == 'element': # this is an object item wrapper
98             self.keyStack.append(self.__getAttr(attrs, 'key'))
99             return
100
101         hint = self.__getAttr(attrs, 'class_hint')
102         if hint:
103             obj = osrfNewObjectFromHint(hint)
104             self.appendChild(obj)
105             self.objStack.append(obj)
106             if name == 'array':
107                 self.posStack.append(0)
108             return
109
110         if name == 'array':
111             obj = []
112             self.appendChild(obj)
113             self.objStack.append(obj)
114             return
115
116         if name == 'object':
117             obj = {}
118             self.appendChild(obj)
119             self.objStack.append(obj)
120             return
121
122         if name == 'boolean':
123             self.appendChild((self.__getAttr(attrs, 'value') == 'true'))
124             return
125
126
127     def appendChild(self, child):
128
129         if self.result == None:
130             self.result = child
131
132         if not self.objStack: return;
133
134         parent = self.objStack[len(self.objStack)-1]
135
136         if isinstance(parent, list):
137             parent.append(child)
138         else:
139             if isinstance(parent, dict):
140                 parent[self.keyStack.pop()] = child
141             else:
142                 if isinstance(parent, osrfNetworkObject):
143                     key = None
144                     if parent.getRegistry().wireProtocol == 'array':
145                         keys = parent.getRegistry().keys
146                         i = self.posStack.pop()
147                         key = keys[i]
148                         if i+1 < len(keys):
149                             self.posStack.append(i+1)
150                     else:
151                         key = self.keyStack.pop()
152
153                     parent.setField(key, child)
154
155     def endElement(self, name):
156         if name == 'array' or name == 'object':
157             self.objStack.pop()
158
159     def characters(self, chars):
160         self.appendChild(urllib.unquote_plus(chars))
161
162
163
164     
165