Attachment 'PyBurlap.py'

Download

Toggle line numbers
   1 #
   2 # A Burlap client interface for Python.  The date and long types require
   3 # Python 2.3 or later.
   4 #
   5 # The Burlap proxy is used as follows:
   6 #
   7 # proxy = Burlap("http://localhost:8080/buffalo/Hello")
   8 #
   9 # print proxy.hello()
  10 #
  11 import string, time
  12 import urllib
  13 #import xmllib
  14 from types import *
  15 
  16 __version__ = "0.1"
  17 
  18 
  19 # --------------------------------------------------------------------
  20 # Exceptions
  21 
  22 class Error:
  23     # base class for client errors
  24     pass
  25 
  26 class ProtocolError(Error):
  27     # Represents an HTTP protocol error
  28     def __init__(self, url, code, message, headers):
  29 	self.url = url
  30 	self.code = code
  31 	self.message = message
  32 	self.headers = headers
  33 
  34     def __repr__(self):
  35 	return (
  36 	    "<ProtocolError for %s: %s %s>" %
  37 	    (self.url, self.code, self.message)
  38 	    )
  39 
  40 class Fault(Error):
  41     # Represents a fault from Burlap
  42     def __init__(self, code, message, **detail):
  43 	self.code = code
  44 	self.message = message
  45 
  46     def __repr__(self):
  47 	return "<BurlapFault %s: %s>" % (self.code, self.message)
  48 
  49 # --------------------------------------------------------------------
  50 # Wrappers for Burlap data types non-standard in Python
  51 #
  52 
  53 #
  54 # Boolean -- use the True or False constants
  55 #
  56 class Boolean:
  57     def __init__(self, value = 0):
  58 	self.value = (value != 0)
  59 
  60     def _burlap_write(self, out):
  61 	if self.value:
  62 	    out.write('<boolean>')
  63 	    out.write('1')
  64 	    out.write('</boolean>')
  65 	else:
  66 	    out.write('<boolean>')
  67 	    out.write('0')
  68 	    out.write('</boolean>')
  69 
  70     def __repr__(self):
  71 	if self.value:
  72 	    return "<True at %x>" % id(self)
  73 	else:
  74 	    return "<False at %x>" % id(self)
  75 
  76     def __int__(self):
  77 	return self.value
  78 
  79     def __nonzero__(self):
  80 	return self.value
  81 
  82 True, False = Boolean(1), Boolean(0)
  83 
  84 #
  85 # Date - wraps a time value in seconds
  86 #
  87 class Date:
  88     def __init__(self, value = 0):
  89 	self.value = value
  90 
  91     def __repr__(self):
  92 	return ("<Date %s at %x>" %
  93                 (time.asctime(time.localtime(self.value)), id(self)))
  94 
  95     def _burlap_write(self, out):
  96 	out.write("<date>")
  97 	out.write(self.value)
  98 	out.write("</date>")
  99 #
 100 # Binary - binary data
 101 #
 102 
 103 class Binary:
 104     def __init__(self, data=None):
 105 	self.data = data
 106 
 107     def _burlap_write(self, out):
 108 	out.write('<base64>')
 109 	out.write(self.data)
 110 	out.write('</base64>')
 111 
 112 #
 113 # BurlapWriter - writes Burlap data from Python objects
 114 #
 115 class BurlapWriter:
 116     dispatch = {}
 117 
 118     def write_call(self, method, params):
 119 	self.refs = {}
 120 	self.ref = 0
 121 	self.__out = []
 122 	self.write = write = self.__out.append
 123 
 124 	write("<burlap:call>");
 125         #write(pack(">H", len(method)));
 126 	write("<method>")
 127         write(method);
 128 	write("</method>")
 129 	for v in params:
 130 	    self.write_object(v)
 131         write("</burlap:call>");
 132 	result = string.join(self.__out, "")
 133 	del self.__out, self.write, self.refs
 134 	return result
 135 
 136     def write_object(self, value):
 137 	try:
 138 	    f = self.dispatch[type(value)]
 139 	except KeyError:
 140 	    raise TypeError, "cannot write %s objects" % type(value)
 141 	else:
 142 	    f(self, value)
 143 
 144     def write_int(self, value):
 145 	self.write('<int>')
 146 	self.write(str(value))
 147 	self.write('</int>')
 148     dispatch[IntType] = write_int
 149 
 150     def write_long(self, value):
 151 	self.write('<long>')
 152 	self.write(str(value))
 153 	self.write('</long>')
 154     dispatch[LongType] = write_long
 155 
 156     def write_double(self, value):
 157 	self.write('<double>')
 158 	self.write(str(value))
 159 	self.write('</double>')
 160     dispatch[FloatType] = write_double
 161 
 162     def write_string(self, value):
 163 	self.write('<string>')
 164 	self.write(str(value))
 165 	self.write('</string>')
 166     dispatch[StringType] = write_string
 167 
 168     def write_reference(self, value):
 169         # check for and write circular references
 170         # returns 1 if the object should be written, i.e. not a reference
 171 	i = id(value)
 172 	if self.refs.has_key(i):
 173 	    self.write('<ref>')
 174 	    self.write(self.refs[i])
 175 	    self.write('</ref>')
 176 	    return 0
 177 	else:
 178 	    self.refs[i] = self.ref
 179 	    self.ref = self.ref + 1
 180 	    return 1
 181 
 182     def write_list(self, value):
 183 	if self.write_reference(value):
 184 	    self.write("<list>");
 185 	    self.write('<length>'+str(len(value))+'</length>')
 186 	    for v in value:
 187 		#print v
 188 	        self.write_object(v)
 189 	    self.write('</list>')
 190     dispatch[TupleType] = write_list
 191     dispatch[ListType] = write_list
 192 
 193     def write_map(self, value):
 194 	if self.write_reference(value):
 195 	    self.write("<map>")
 196 	    for k, v in value.items():
 197 	        #self.__write(k)
 198 	        #self.__write('<string>'+v+'</string>')
 199 		self.write_object(v)
 200 		self.write_object(k)
 201 	    self.write("</map>")
 202     dispatch[DictType] = write_map
 203 
 204     def write_instance(self, value):
 205 	# check for special wrappers
 206 	if hasattr(value, "_burlap_write"):
 207 	    value._burlap_write(self)
 208     dispatch[InstanceType] = write_instance
 209 
 210 from xml.parsers import expat
 211 class Parser:
 212     def __init__(self):
 213         self._parser = expat.ParserCreate()
 214         self._parser.StartElementHandler = self.start
 215         #self._parser.EndElementHandler = self.end
 216         self._parser.CharacterDataHandler = self.data
 217 	self.tags = []
 218 	self.datas = []
 219 
 220     def feed(self, data):
 221         self._parser.Parse(data, 0)
 222 
 223     def close(self):
 224         self._parser.Parse("", 1) # end of data
 225         del self._parser # get rid of circular references
 226 
 227     def start(self, tag, attrs):
 228         #print "START", repr(tag), attrs
 229 	self.tags.append(tag)
 230 
 231     def end(self, tag):
 232         print "END", repr(tag)
 233 
 234     def data(self, data):
 235         #print "DATA", repr(data)
 236 	self.datas.append(data)
 237 	
 238 
 239 #
 240 # Parses the results from the server
 241 #
 242 class BurlapParser:
 243     def __init__(self, f):
 244 	self._f = f
 245 	self.read = self._f.readline()
 246 	self._refs = []
 247 
 248     def parse_reply(self):
 249 	#read = self.read
 250 	#major = read(1)
 251 	#minor = read(1)
 252 	#ch = read(1)
 253 
 254         value = self.parse_object()
 255 
 256 	return value
 257 	#self.error() # actually a fault
 258 
 259     def parse_object(self):
 260 	# parse an arbitrary object based on the type in the data
 261 	return self.parse_object_code(self.read)
 262 
 263     def parse_object_code(self, code):
 264 	# parse an object when the code is known
 265 	read = self.read
 266 
 267 	p = Parser()
 268 	p.feed(read)
 269 	p.close()
 270 
 271 	if code == 'null':
 272 	    return None
 273 
 274 	elif p.tags[1] == 'boolean':
 275 	    return p.datas[0]
 276 
 277 	#elif code == 'F':
 278 	#    return False
 279 
 280 	elif p.tags[1] == 'int':
 281 	    return p.datas[0]
 282 
 283 	elif p.tags[1] == 'long':
 284 	    return p.datas[0]
 285 
 286 	elif p.tags[1] == 'double':
 287 	    return p.datas[0]
 288 
 289 	elif p.tags[1] == 'date':
 290 	    ms = p.datas[0]
 291 
 292 	    return ms
 293 
 294 	elif p.tags[1] == 'string':
 295 	    #return self.parse_string()
 296 	    return p.datas[0]
 297 
 298 	elif code == 'B':
 299 	    return Binary(self.parse_string())
 300 
 301 	elif p.tags[1] == 'list':
 302 	    list = []
 303 	    self._refs.append(list)
 304 	    i = 2#skip length
 305 	    while i<=len(p.datas):
 306 		list.append(p.datas[i-1])
 307 		i = i+1
 308 	    return list
 309 
 310 	elif p.tags[1] == 'map':
 311 	    #self.parse_type() # skip type
 312 	    map = {}
 313 	    #self._refs.append(map)
 314 	    i = 1
 315 	    while i<=len(p.datas):
 316 		#key = self.parse_object_code(ch)
 317 		#value = self.parse_object()
 318 		key = p.datas[i-1]
 319 		value = p.datas[i]
 320 		map[key] = value
 321 		#ch = read(1)
 322 		i = i+2
 323 	    return map
 324 
 325 	elif code == 'R':
 326 	    return self._refs[unpack('>l', read(4))[0]]
 327 
 328 	elif code == 'r':
 329 	    self.parse_type()       # skip type
 330 	    url = self.parse_type() # reads the url
 331 	    return Burlap(url)
 332 
 333 	else:
 334 	    raise "UnknownObjectCode %d" % code
 335 
 336     def parse_type(self):
 337 	f = self._f
 338 	len = unpack('>cH', f.read(3))[1]
 339 	return f.read(len)
 340 
 341     def error(self):
 342 	raise "FOO"
 343 
 344 #
 345 # Encapsulates the method to be called
 346 #
 347 class _Method:
 348     def __init__(self, invoker, method):
 349 	self._invoker = invoker
 350 	self._method = method
 351 
 352     def __call__(self, *args):
 353 	return self._invoker(self._method, args)
 354 
 355 # --------------------------------------------------------------------
 356 # Burlap is the main class.  A Burlap proxy is created with the URL
 357 # and then called just as for a local method
 358 #
 359 # proxy = Burlap("http://localhost:8080/buffalo/Hello")
 360 # print proxy.hello()
 361 #
 362 class Burlap:
 363     """Represents a remote object reachable by Burlap"""
 364 
 365     def __init__(self, url):
 366 	# Creates a Burlap proxy object
 367 
 368 	self._url = url
 369 
 370 	# get the uri
 371 	type, uri = urllib.splittype(url)
 372 	if type != "http":
 373 	    raise IOError, "unsupported Burlap protocol"
 374 
 375 	self._host, self._uri = urllib.splithost(uri)
 376 
 377     def __invoke(self, method, params):
 378 	# call a method on the remote server
 379 
 380 	request = BurlapWriter().write_call(method, params)
 381 
 382 	import httplib
 383 
 384 	h = httplib.HTTP(self._host)
 385 	h.putrequest("POST", self._uri)
 386 
 387 	# required by HTTP/1.1
 388 	h.putheader("Host", self._host)
 389 
 390 	h.putheader("User-Agent", "PyBurlap.py/%s" % __version__)
 391 	h.putheader("Content-Length", str(len(request)))
 392 
 393 	h.endheaders()
 394 
 395 	h.send(request)
 396 
 397 	errcode, errmsg, headers = h.getreply()
 398 
 399 	if errcode != 200:
 400 	    raise ProtocolError(self._url, errcode, errmsg, headers)
 401 
 402 	return self.parse_response(h.getfile())
 403 
 404     def parse_response(self, f):
 405 	# read response from input file, and parse it
 406 
 407 	parser = BurlapParser(f)
 408 	value = parser.parse_reply()
 409 	f.close()
 410 
 411 	return value
 412 
 413     def _hessian_write(self, out):
 414 	# marshals the proxy itself
 415 	out.write("rt\x00\x00S")
 416 	out.write(pack(">H", len(self._url)))
 417 	out.write(self._url)
 418 
 419     def __repr__(self):
 420 	return "<BurlapProxy %s>" % self._url
 421 
 422     __str__ = __repr__
 423 
 424     def __getattr__(self, name):
 425 	# encapsulate the method call
 426 	return _Method(self.__invoke, name)
 427 
 428 #
 429 # Testing code.
 430 #
 431 if __name__ == "__main__":
 432     proxy = Burlap("http://localhost:8080/buffalo/Hello")
 433 
 434     try:
 435 	print proxy.hello("Breeze")
 436 	print proxy.replyInt(10)
 437 	print proxy.replyLong(10000)
 438 	print proxy.replyDouble(1000000.90)
 439 	print proxy.callIntStr(100,"Breeze")
 440 
 441 	print proxy.replyList(['Breeze','QingFeng','Wind',100,300.68])#list
 442 
 443 	print proxy.replyMap({'Breeze':1,'QingFeng':2,'Wind':3,100:4,300.68:5})#map->Python is dict
 444 
 445 	print proxy.replyBoolean(True)
 446 
 447 	#ISO_8609_DATETIME = '%Y%m%dT%H%M%SZ'
 448 	print proxy.replyDate(Date('20050501T095231Z'))
 449 
 450 	import base64
 451 	print proxy.replyBase64(base64.encodestring('Breeze Base64'))
 452     except Error, v:
 453 	print "ERROR", v

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2021-05-11 08:52:16, 10.2 KB) [[attachment:PyBurlap.py]]
  • [get | view] (2021-05-11 08:52:16, 2.9 KB) [[attachment:PyBurlap0.1.zip]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.