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

Source Code for Module rsbxml.xop

  1  # ============================================================ 
  2  # 
  3  # Copyright (C) 2011, 2012 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 -class Attachment (object):
28 """ 29 Instances of this class represent individual binary data items 30 associated to an XOP XML document. 31 32 For the XOP specification, see U{http://www.w3.org/TR/xop10/}. 33 34 @author: jmoringe 35 """
36 - def __init__(self, uri, data):
37 self._uri = uri 38 self._data = data
39
40 - def getURI(self):
41 return self._uri
42
43 - def setURI(self, uri):
44 self._uri = uri
45 46 uri = property(getURI, setURI) 47
48 - def getData(self):
49 return self._data
50
51 - def setData(self, data):
52 self._data = data
53 54 data = property(getData, setData) 55
56 - def __str__(self):
57 if hasattr(self.data, '__length__'): 58 data = '%s of length %d' % (type(self.data).__name__, len(self.data)) 59 else: 60 data = self.data 61 return '<%s %s: %s>' \ 62 % (type(self).__name__, self.uri, data)
63
64 - def __repr__(self):
65 return str(self)
66
67 -class XOP (object):
68 """ 69 Instances of this class represent composite XOP structures 70 consisting of an XML document and associated binary data items. 71 72 For the XOP specification, see U{http://www.w3.org/TR/xop10/}. 73 74 @author: jmoringe 75 """
76 - def __init__(self, document, attachments = None):
77 if isinstance(document, str): 78 self._document = minidom.parseString(document) 79 else: 80 self._document = document 81 if attachments is None: 82 self._attachments = {} 83 else: 84 self.setAttachments(attachments)
85
86 - def getDocument(self):
87 return self._document
88
89 - def setDocument(self, document):
90 if isinstance(document, str): 91 document = parse 92 self._document = document
93 94 document = property(getDocument, setDocument) 95
96 - def getAttachments(self):
97 return self._attachments.values()
98
99 - def setAttachments(self, attachments):
100 """ 101 Set the associated binary data items to L{attachments}. 102 103 @param attachments: Either a C{dict} the keys of which are 104 URIs and the values of which are the 105 binary data items, or a list of either 106 L{Attachment} objects or pairs of the same 107 kind as in the C{dict} case. 108 @type attachments: dict or list 109 110 Example: 111 112 >>> p.attachments = { 'http://foo.bar': bytearray(str('bla')) } 113 ... 114 115 >>> p.attachments = [ Attachment('http://foo.bar', bytearray(str('bla'))) ] 116 ... 117 """ 118 # dict of uris and things that can be converted into attachments 119 if isinstance(attachments, dict): 120 attachments = dict( (key, self._makeAttachment(key, value)) 121 for (key, value) in attachments.items() ) 122 # list of Attachment objects or pairs 123 elif isinstance(attachments, list): 124 def toPair(item): 125 if isinstance(item, Attachment): 126 return (item.uri, item) 127 else: 128 return item
129 attachments = dict( toPair(item) for item in attachments ) 130 else: 131 raise TypeError, attachments 132 self._attachments = attachments
133 134 attachments = property(getAttachments, setAttachments) 135
136 - def getAttachment(self, uri):
137 return self._attachments[uri]
138
139 - def setAttachment(self, uri, attachment):
140 if isinstance(attachment, Attachment): 141 self._attachments[uri] = attachment 142 else: 143 self.setAttachment(uri, Attachment(uri, attachment))
144
145 - def addAttachment(self, attachment):
146 """ 147 Add L{attachment} to the list of attachments. 148 149 @param attachment: The attachment that should be added. 150 @type attachment: Attachment 151 @raise KeyError: If there already is a attachment for the URI of 152 L{attachment}. 153 """ 154 if attachment.uri in self._attachments: 155 raise KeyError, 'duplicate attachment URI: %s' % attachment.uri 156 self._attachments[attachment.uri] = attachment
157
158 - def _makeAttachment(self, uri, thing):
159 return Attachment(uri, thing)
160
161 - def __str__(self):
162 return '<%s <%s .../> with %s attachment(s)>' \ 163 % (type(self).__name__, 164 self.document.documentElement.tagName, 165 len(self._attachments))
166
167 - def __repr__(self):
168 return str(self)
169 170 from rsb.converter import Converter, registerGlobalConverter, getGlobalConverterMap 171 import rst.xml.XOP_pb2 as pb 172
173 -class XOPConverter (Converter):
174 - def __init__(self, attachmentConverter = getGlobalConverterMap(bytearray)):
175 super(XOPConverter, self).__init__(wireType = bytearray, 176 dataType = XOP, 177 wireSchema = '.rst.xml.XOP') 178 self.__attachmentConverter = attachmentConverter
179 180
181 - def getAttachmentConverter(self):
182 return self.__attachmentConverter
183 184 attachmentConverter = property(getAttachmentConverter) 185
186 - def serialize(self, input):
187 if not isinstance(input, XOP): 188 raise TypeError, input 189 190 # Step 1: construct and fill the protocol buffer data-holder 191 # (of protocol buffer message type .rsb.xml.XOP) 192 holder = pb.XOP() 193 holder.xml = input.document.toxml(encoding = 'UTF-8') 194 for attachment in input.attachments: 195 attachment_ = holder.attachments.add() 196 attachment_.url = attachment.uri 197 198 data, wire_schema \ 199 = self.attachmentConverter \ 200 .getConverterForDataType(type(attachment.data)) \ 201 .serialize(attachment.data) 202 attachment_.data = str(data) 203 attachment_.wire_schema = wire_schema 204 205 # Step 2: serialize the protocol buffer data-holder to a 206 # string and associate a wire-schema 207 return holder.SerializeToString(), self.wireSchema
208
209 - def deserialize(self, input, wireSchema):
210 if not wireSchema == self.wireSchema: 211 raise ValueError("Cannot handle wire-schema %s" % wireSchema) 212 213 # Step 1: deserialize the data received over the wire into a 214 # data-holder (of protocol buffer message type 215 # .rsb.xml.XOP) 216 holder = pb.XOP() 217 holder.ParseFromString(str(input)) 218 219 # Step 2: construct and fill a domain object of type Package 220 # based on the contents of the data-holder. 221 package = XOP(document = minidom.parseString(holder.xml)) 222 for attachment_ in holder.attachments: 223 data = self.attachmentConverter \ 224 .getConverterForWireSchema(attachment_.wire_schema) \ 225 .deserialize(attachment_.data, attachment_.wire_schema) 226 package.setAttachment(attachment_.url, data) 227 228 return package
229 230 registerGlobalConverter(XOPConverter()) 231 232 import rsb 233 rsb.__defaultParticipantConfig = rsb.ParticipantConfig.fromDefaultSources() 234 # TODO we will probably regret this at some point, but the converter 235 # won't get registered in the ParticipantConfig otherwise 236