Package rsbxml :: Module xop
[hide private]
[frames] | no frames]

Source Code for Module rsbxml.xop

  1  # ============================================================ 
  2  # 
  3  # Copyright (C) 2011-2017 Jan Moringen <jmoringe@techfak.uni-bielefeld.de> 
  4  # 
  5  # This file may be licensed under the terms of the 
  6  # GNU Lesser General Public License Version 3 (the ``LGPL''), 
  7  # or (at your option) any later version. 
  8  # 
  9  # Software distributed under the License is distributed 
 10  # on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either 
 11  # express or implied. See the LGPL for the specific language 
 12  # governing rights and limitations. 
 13  # 
 14  # You should have received a copy of the LGPL along with this 
 15  # program. If not, go to http://www.gnu.org/licenses/lgpl.html 
 16  # or write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 
 18  # 
 19  # The development of this software was supported by: 
 20  #   CoR-Lab, Research Institute for Cognition and Robotics 
 21  #     Bielefeld University 
 22  # 
 23  # ============================================================ 
 24   
 25  from xml.dom import minidom 
 26   
 27  from rsb.converter import Converter, registerGlobalConverter, \ 
 28      getGlobalConverterMap 
 29  import rst.xml.XOP_pb2 as pb 
 30   
 31  import rsb 
 32   
 33   
34 -class Attachment (object):
35 """ 36 Instances of this class represent individual binary data items 37 associated to an XOP XML document. 38 39 For the XOP specification, see U{http://www.w3.org/TR/xop10/}. 40 41 @author: jmoringe 42 """
43 - def __init__(self, uri, data):
44 self._uri = uri 45 self._data = data
46
47 - def getURI(self):
48 return self._uri
49
50 - def setURI(self, uri):
51 self._uri = uri
52 53 uri = property(getURI, setURI) 54
55 - def getData(self):
56 return self._data
57
58 - def setData(self, data):
59 self._data = data
60 61 data = property(getData, setData) 62
63 - def __str__(self):
64 if hasattr(self.data, '__length__'): 65 data = '%s of length %d' % (type(self.data).__name__, 66 len(self.data)) 67 else: 68 data = self.data 69 return '<%s %s: %s>' \ 70 % (type(self).__name__, self.uri, data)
71
72 - def __repr__(self):
73 return str(self)
74 75
76 -class XOP (object):
77 """ 78 Instances of this class represent composite XOP structures 79 consisting of an XML document and associated binary data items. 80 81 For the XOP specification, see U{http://www.w3.org/TR/xop10/}. 82 83 @author: jmoringe 84 """
85 - def __init__(self, document, attachments=None):
86 if isinstance(document, str): 87 self._document = minidom.parseString(document) 88 else: 89 self._document = document 90 if attachments is None: 91 self._attachments = {} 92 else: 93 self.setAttachments(attachments)
94
95 - def getDocument(self):
96 return self._document
97
98 - def setDocument(self, document):
99 if isinstance(document, str): 100 document = parse 101 self._document = document
102 103 document = property(getDocument, setDocument) 104
105 - def getAttachments(self):
106 return self._attachments.values()
107
108 - def setAttachments(self, attachments):
109 """ 110 Set the associated binary data items to L{attachments}. 111 112 @param attachments: Either a C{dict} the keys of which are 113 URIs and the values of which are the 114 binary data items, or a list of either 115 L{Attachment} objects or pairs of the same 116 kind as in the C{dict} case. 117 @type attachments: dict or list 118 119 Example: 120 121 >>> p.attachments = { 'http://foo.bar': bytearray(str('bla')) } 122 ... 123 124 >>> p.attachments = [ Attachment('http://foo.bar', bytearray(str('bla'))) ] 125 ... 126 """ 127 # dict of uris and things that can be converted into attachments 128 if isinstance(attachments, dict): 129 attachments = dict((key, self._makeAttachment(key, value)) 130 for (key, value) in attachments.items()) 131 # list of Attachment objects or pairs 132 elif isinstance(attachments, list): 133 def toPair(item): 134 if isinstance(item, Attachment): 135 return (item.uri, item) 136 else: 137 return item
138 attachments = dict(toPair(item) for item in attachments) 139 else: 140 raise TypeError, attachments 141 self._attachments = attachments
142 143 attachments = property(getAttachments, setAttachments) 144
145 - def getAttachment(self, uri):
146 return self._attachments[uri]
147
148 - def setAttachment(self, uri, attachment):
149 if isinstance(attachment, Attachment): 150 self._attachments[uri] = attachment 151 else: 152 self.setAttachment(uri, Attachment(uri, attachment))
153
154 - def addAttachment(self, attachment):
155 """ 156 Add L{attachment} to the list of attachments. 157 158 @param attachment: The attachment that should be added. 159 @type attachment: Attachment 160 @raise KeyError: If there already is a attachment for the URI of 161 L{attachment}. 162 """ 163 if attachment.uri in self._attachments: 164 raise KeyError('duplicate attachment URI: %s' % attachment.uri) 165 self._attachments[attachment.uri] = attachment
166
167 - def _makeAttachment(self, uri, thing):
168 return Attachment(uri, thing)
169
170 - def __str__(self):
171 return '<%s <%s .../> with %s attachment(s)>' \ 172 % (type(self).__name__, 173 self.document.documentElement.tagName, 174 len(self._attachments))
175
176 - def __repr__(self):
177 return str(self)
178 179
180 -class XOPConverter (Converter):
181 - def __init__(self, attachmentConverter=getGlobalConverterMap(bytearray)):
182 super(XOPConverter, self).__init__(wireType=bytearray, 183 dataType=XOP, 184 wireSchema='.rst.xml.XOP') 185 self.__attachmentConverter = attachmentConverter
186
187 - def getAttachmentConverter(self):
188 return self.__attachmentConverter
189 190 attachmentConverter = property(getAttachmentConverter) 191
192 - def serialize(self, input):
193 if not isinstance(input, XOP): 194 raise TypeError(input) 195 196 # Step 1: construct and fill the protocol buffer data-holder 197 # (of protocol buffer message type .rsb.xml.XOP) 198 holder = pb.XOP() 199 holder.xml = input.document.toxml(encoding='UTF-8') 200 for attachment in input.attachments: 201 attachment_ = holder.attachments.add() 202 attachment_.url = attachment.uri 203 204 data, wire_schema \ 205 = self.attachmentConverter \ 206 .getConverterForDataType(type(attachment.data)) \ 207 .serialize(attachment.data) 208 attachment_.data = str(data) 209 attachment_.wire_schema = wire_schema 210 211 # Step 2: serialize the protocol buffer data-holder to a 212 # string and associate a wire-schema 213 return holder.SerializeToString(), self.wireSchema
214
215 - def deserialize(self, input, wireSchema):
216 if not wireSchema == self.wireSchema: 217 raise ValueError("Cannot handle wire-schema %s" % wireSchema) 218 219 # Step 1: deserialize the data received over the wire into a 220 # data-holder (of protocol buffer message type 221 # .rsb.xml.XOP) 222 holder = pb.XOP() 223 holder.ParseFromString(str(input)) 224 225 # Step 2: construct and fill a domain object of type Package 226 # based on the contents of the data-holder. 227 package = XOP(document=minidom.parseString(holder.xml)) 228 for attachment_ in holder.attachments: 229 data = self.attachmentConverter \ 230 .getConverterForWireSchema(attachment_.wire_schema) \ 231 .deserialize(attachment_.data, attachment_.wire_schema) 232 package.setAttachment(attachment_.url, data) 233 234 return package
235 236 237 registerGlobalConverter(XOPConverter()) 238 239 240 rsb.__defaultParticipantConfig = rsb.ParticipantConfig.fromDefaultSources() 241