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 '''
10 exec('obj = osrfNetworkObject.%s()' % hint)
12 newFromHint = staticmethod(newFromHint)
15 ''' Global object registry '''
18 class osrfNetworkRegistry(object):
19 ''' Network-serializable objects must be registered. The class
20 hint maps to a set (ordered in the case of array-base objects)
21 of field names (keys).
24 def __init__(self, hint, keys, wireProtocol):
28 self.wireProtocol = wireProtocol
29 objectRegistry[hint] = self
31 def getRegistry(hint):
33 return objectRegistry.get(hint)
34 getRegistry = staticmethod(getRegistry)
37 def __makeNetworkAccessor(cls, key):
38 ''' Creates and accessor/mutator method for the given class.
40 'key' is the name the method will have and represents
41 the field on the object whose data we are accessing
43 def accessor(self, *args):
45 self.__data[key] = args[0]
46 return self.__data.get(key)
47 setattr(cls, key, accessor)
51 def __makeGetRegistry(cls, registry):
52 ''' Wraps the registry for this class inside an accessor method '''
55 setattr(cls, 'getRegistry', get)
57 def __makeGetData(cls):
58 ''' Wraps the stored data in an accessor method '''
61 setattr(cls, 'getData', get)
64 def __osrfNetworkObjectInit(self, data={}):
65 ''' __init__ method for osrNetworkObjects.
66 If this is an array, we pull data out of the data array
67 (if there is any) and translate that into a hash internally
72 reg = self.getRegistry()
73 if reg.wireProtocol == 'array':
75 for i in range(len(reg.keys)):
77 self.__data[reg.keys[i]] = data[i]
79 self.__data[reg.keys[i]] = None
82 def osrfNetworkRegisterHint(hint, keys, type='hash'):
83 ''' Registers a new network-serializable object class.
85 'hint' is the class hint
86 'keys' is the list of field names on the object
87 If this is an array-based object, the field names
88 must be sorted to reflect the encoding order of the fields
89 'type' is the wire-protocol of the object. hash or array.
92 # register the class with the global registry
93 registry = osrfNetworkRegistry(hint, keys, type)
95 # create the new class locally with the given hint name
96 exec('class %s(osrfNetworkObject):\n\tpass' % hint)
98 # give the new registered class a local handle
100 exec('cls = %s' % hint)
102 # assign an accessor/mutator for each field on the object
104 __makeNetworkAccessor(cls, k)
106 # assign our custom init function
107 setattr(cls, '__init__', __osrfNetworkObjectInit)
108 __makeGetRegistry(cls, registry)
112 # attach our new class to the osrfNetworkObject
113 # class so others can access it
114 setattr(osrfNetworkObject, hint , cls)
119 # create a unknown object to handle unregistred types
120 osrfNetworkRegisterHint('__unknown', [], 'hash')
122 # -------------------------------------------------------------------
123 # Define the custom object parsing behavior
124 # -------------------------------------------------------------------
125 def parseNetObject(obj):
129 hint = obj[OSRF_JSON_CLASS_KEY]
130 obj = obj[OSRF_JSON_PAYLOAD_KEY]
132 if isinstance(obj,list):
134 for i in range(len(obj)):
135 obj[i] = parseNetObject(obj[i])
137 if isinstance(obj,dict):
138 for k,v in obj.iteritems():
139 obj[k] = parseNetObject(v)
141 if hint: # Now, "bless" the object into an osrfNetworkObject
142 estr = 'obj = osrfNetworkObject.%s(obj)' % hint
145 except AttributeError:
146 # this object has not been registered, shove it into the default container
147 obj = osrfNetworkObject.__unknown(obj)
153 def osrfObjectToXML(obj):
154 """ Returns the XML representation of an internal object."""
156 __osrfObjectToXML(obj, chars)
157 return ''.join(chars)
159 def __osrfObjectToXML(obj, chars):
160 """ Turns an internal object into OpenSRF XML """
163 chars.append('<null/>')
166 if isinstance(obj, unicode) or isinstance(obj, str):
167 chars.append('<string>%s</string>' % saxutils.escape(obj))
170 if isinstance(obj, int) or isinstance(obj, long):
171 chars.append('<number>%d</number>' % obj)
174 if isinstance(obj, float):
175 chars.append('<number>%f</number>' % obj)
180 if isinstance(obj, osrfNetworkObject):
182 registry = obj.getRegistry()
184 hint = saxutils.escape(registry.hint)
186 if registry.wireProtocol == 'array':
187 chars.append("<array class_hint='%s'>" % hint)
188 for k in registry.keys:
189 __osrfObjectToXML(data.get(k), chars)
190 chars.append('</array>')
193 if registry.wireProtocol == 'hash':
194 chars.append("<object class_hint='%s'>" % hint)
195 for k,v in data.items():
196 chars.append("<element key='%s'>" % saxutils.escape(k))
197 __osrfObjectToXML(v, chars)
198 chars.append('</element>')
199 chars.append('</object>')
202 if isinstance(obj, list):
203 chars.append('<array>')
205 __osrfObjectToXML(i, chars)
206 chars.append('</array>')
209 if isinstance(obj, dict):
210 chars.append('<object>')
211 for k,v in obj.items():
212 chars.append("<element key='%s'>" % saxutils.escape(k))
213 __osrfObjectToXML(v, chars)
214 chars.append('</element>')
215 chars.append('</object>')
218 if isinstance(obj, bool):
221 chars.append("<boolean value='%s'/>" % val)