1 from osrf.const import OSRF_JSON_PAYLOAD_KEY, OSRF_JSON_CLASS_KEY
2 from xml.sax import saxutils
5 class osrfNetworkObject(object):
6 ''' Base class for all network serializable objects '''
9 def osrfNewObjectFromHint(hint):
12 exec('obj = osrfNetworkObject.%s()' % hint)
14 except AttributeError:
15 return osrfNetworkObject.__unknown()
16 #newFromHint = staticmethod(newFromHint)
19 ''' Global object registry '''
22 class osrfNetworkRegistry(object):
23 ''' Network-serializable objects must be registered. The class
24 hint maps to a set (ordered in the case of array-base objects)
25 of field names (keys).
28 def __init__(self, hint, keys, wireProtocol):
32 self.wireProtocol = wireProtocol
33 objectRegistry[hint] = self
35 def getRegistry(hint):
37 return objectRegistry.get(hint)
38 getRegistry = staticmethod(getRegistry)
41 def __makeNetworkAccessor(cls, key):
42 ''' Creates and accessor/mutator method for the given class.
44 'key' is the name the method will have and represents
45 the field on the object whose data we are accessing
47 def accessor(self, *args):
49 self.__data[key] = args[0]
50 return self.__data.get(key)
51 setattr(cls, key, accessor)
55 def __makeGetRegistry(cls, registry):
56 ''' Wraps the registry for this class inside an accessor method '''
59 setattr(cls, 'getRegistry', get)
61 def __makeGetData(cls):
62 ''' Wraps the stored data in an accessor method '''
65 setattr(cls, 'getData', get)
67 def __makeSetField(cls):
68 ''' Creates a generic mutator for fields by fieldname '''
69 def set(self, field, value):
70 self.__data[field] = value
71 setattr(cls, 'setField', set)
74 def __osrfNetworkObjectInit(self, data={}):
75 ''' __init__ method for osrNetworkObjects.
76 If this is an array, we pull data out of the data array
77 (if there is any) and translate that into a hash internally
82 reg = self.getRegistry()
83 if reg.wireProtocol == 'array':
85 for i in range(len(reg.keys)):
87 self.__data[reg.keys[i]] = data[i]
89 self.__data[reg.keys[i]] = None
92 def osrfNetworkRegisterHint(hint, keys, type='hash'):
93 ''' Registers a new network-serializable object class.
95 'hint' is the class hint
96 'keys' is the list of field names on the object
97 If this is an array-based object, the field names
98 must be sorted to reflect the encoding order of the fields
99 'type' is the wire-protocol of the object. hash or array.
102 # register the class with the global registry
103 registry = osrfNetworkRegistry(hint, keys, type)
105 # create the new class locally with the given hint name
106 exec('class %s(osrfNetworkObject):\n\tpass' % hint)
108 # give the new registered class a local handle
110 exec('cls = %s' % hint)
112 # assign an accessor/mutator for each field on the object
114 __makeNetworkAccessor(cls, k)
116 # assign our custom init function
117 setattr(cls, '__init__', __osrfNetworkObjectInit)
118 __makeGetRegistry(cls, registry)
123 # attach our new class to the osrfNetworkObject
124 # class so others can access it
125 setattr(osrfNetworkObject, hint , cls)
130 # create a unknown object to handle unregistred types
131 osrfNetworkRegisterHint('__unknown', [], 'hash')
133 # -------------------------------------------------------------------
134 # Define the custom object parsing behavior
135 # -------------------------------------------------------------------
136 def parseNetObject(obj):
140 hint = obj[OSRF_JSON_CLASS_KEY]
141 obj = obj[OSRF_JSON_PAYLOAD_KEY]
143 if isinstance(obj,list):
145 for i in range(len(obj)):
146 obj[i] = parseNetObject(obj[i])
148 if isinstance(obj,dict):
149 for k,v in obj.iteritems():
150 obj[k] = parseNetObject(v)
152 if hint: # Now, "bless" the object into an osrfNetworkObject
153 estr = 'obj = osrfNetworkObject.%s(obj)' % hint
156 except AttributeError:
157 # this object has not been registered, shove it into the default container
158 obj = osrfNetworkObject.__unknown(obj)
164 def osrfObjectToXML(obj):
165 """ Returns the XML representation of an internal object."""
167 __osrfObjectToXML(obj, chars)
168 return ''.join(chars)
170 def __osrfObjectToXML(obj, chars):
171 """ Turns an internal object into OpenSRF XML """
174 chars.append('<null/>')
177 if isinstance(obj, unicode) or isinstance(obj, str):
178 chars.append('<string>%s</string>' % saxutils.escape(obj))
181 if isinstance(obj, int) or isinstance(obj, long):
182 chars.append('<number>%d</number>' % obj)
185 if isinstance(obj, float):
186 chars.append('<number>%f</number>' % obj)
191 if isinstance(obj, osrfNetworkObject):
193 registry = obj.getRegistry()
195 hint = saxutils.escape(registry.hint)
197 if registry.wireProtocol == 'array':
198 chars.append("<array class_hint='%s'>" % hint)
199 for k in registry.keys:
200 __osrfObjectToXML(data.get(k), chars)
201 chars.append('</array>')
204 if registry.wireProtocol == 'hash':
205 chars.append("<object class_hint='%s'>" % hint)
206 for k,v in data.items():
207 chars.append("<element key='%s'>" % saxutils.escape(k))
208 __osrfObjectToXML(v, chars)
209 chars.append('</element>')
210 chars.append('</object>')
213 if isinstance(obj, list):
214 chars.append('<array>')
216 __osrfObjectToXML(i, chars)
217 chars.append('</array>')
220 if isinstance(obj, dict):
221 chars.append('<object>')
222 for k,v in obj.items():
223 chars.append("<element key='%s'>" % saxutils.escape(k))
224 __osrfObjectToXML(v, chars)
225 chars.append('</element>')
226 chars.append('</object>')
229 if isinstance(obj, bool):
232 chars.append("<boolean value='%s'/>" % val)