00001 from biosphere.types import *
00002 from xml.dom import minidom
00003 import base64
00004
00005 """The xlate module is used to parse XML into either a bs_definition
00006 class or a bs_service_response class. Since this python package will
00007 only be used on the client side, no bs_service_request functionality
00008 is present.
00009 """
00010
00011
00012 class XMLParser:
00013 """Parses the three different Bio-SPHERE XML representations
00014 into their respective classes."""
00015
00016 def __init__(self):
00017 """Initialize the XMLParser."""
00018 self.errorerror = None
00019
00020 def Parse(self, xmldata):
00021 """Parses a giving buffer with XML data into the correct
00022 data type. If an error is encountered, None is returned
00023 and the error can be examined at self.error.
00024
00025 Args:
00026 xmldata -- A buffer with XML data to parse.
00027 """
00028 dom = minidom.parseString(xmldata)
00029 if dom.documentElement.tagName == 'definitions':
00030 return self.ParseDefinitionsParseDefinitions(dom)
00031 elif dom.documentElement.tagName == 'response':
00032 return self.ParseResponseParseResponse(dom)
00033 else:
00034 self.errorerror = (0x00000204, 'Unknown root element')
00035 return None
00036
00037 def ParseDefinitions(self, dom):
00038 """Parse a definition XML structure. This method creates
00039 a bs_definition class which is returned or None if there
00040 was an error.
00041
00042 Args:
00043 dom -- The DOM of the XML
00044 """
00045 name = dom.documentElement.getAttribute('name')
00046 bsdef = bs_definition(name)
00047
00048 self.AddTypesAddTypes(dom, bsdef)
00049 self.AddMessagesAddMessages(dom, bsdef)
00050 self.AddPortTypesAddPortTypes(dom, bsdef)
00051 self.AddServicesAddServices(dom, bsdef)
00052
00053 dom.unlink()
00054 if self.errorerror != None:
00055 return None
00056 else:
00057 self.errorerror = None
00058 return bsdef
00059
00060 def AddTypes(self, dom, bsdef):
00061 """Add the data types used in the definition to the given
00062 bs_definition class.
00063
00064 Args:
00065 dom -- Part of the DOM with the data types.
00066 bsdef -- bs_definition class to add types to.
00067 """
00068 for type in dom.getElementsByTagName('type'):
00069 bstype = bs_data_type(type.getAttribute('name'))
00070 bsdef.types.append(bstype)
00071
00072 def AddMessages(self, dom, bsdef):
00073 """Add the messages used in the definition to the
00074 bs_definition class.
00075
00076 Args:
00077 dom -- Part of the DOM with the data types.
00078 bsdef -- bs_definition class to add messages to.
00079 """
00080 messages = dom.getElementsByTagName('message')
00081 for msg in messages:
00082 bsmsg = bs_message(msg.getAttribute('name'))
00083 self.AddMessagePartsAddMessageParts(msg, bsmsg, bsdef)
00084 bsdef.messages.append(bsmsg)
00085
00086 def AddMessageParts(self, msg, bsmsg, bsdef):
00087 """Add the parts of the message, whose DOM is in msg, to the
00088 bs_message class (bsmsg), searching for the correct type in
00089 bsdef.
00090
00091 Args:
00092 msg -- Part of the DOM tree related to the message.
00093 bsmsg -- bs_message class to add the parts to.
00094 bsdef -- bs_definition class for cross-referencing.
00095 """
00096 parts = msg.getElementsByTagName('part')
00097 for part in parts:
00098 name = part.getAttribute('name')
00099 typename = part.getAttribute('type')
00100 type = None
00101 for t in bsdef.types:
00102 if t.name == typename:
00103 type = t
00104 break
00105 if type == None:
00106 self.errorerror = (0x206, 'Data type unknown')
00107 bsmsg.parts.append(bs_message_part(name, type))
00108
00109 def AddPortTypes(self, dom, bsdef):
00110 """Add the port types to the bs_definition class.
00111
00112 Args:
00113 dom -- Part of the DOM containing the port types.
00114 bsdef -- bs_definition class to cross-reference.
00115 """
00116 pts = dom.getElementsByTagName('portType')
00117 for pt in pts:
00118 bspt = bs_port_type(pt.getAttribute('name'))
00119 self.AddOperationsAddOperations(pt, bspt, bsdef)
00120 bsdef.porttypes.append(bspt)
00121
00122 def AddOperations(self, pt, bspt, bsdef):
00123 """Add all the operations in pt (DOM) to the given
00124 bs_port_type class, while cross-referencing in the
00125 bs_definition class.
00126
00127 Args:
00128 pt -- Part of the DOM related to the portType.
00129 bspt -- bs_port_type class to add operations to.
00130 bsdef -- bs_definition class to use for crossreferencing.
00131 """
00132 ops = pt.getElementsByTagName('operation')
00133 for op in ops:
00134 bsop = bs_operation(op.getAttribute('name'))
00135
00136
00137 itag = op.getElementsByTagName('input')
00138 if itag != []:
00139 mname = itag[0].getAttribute('message')
00140 for msg in bsdef.messages:
00141 if msg.name == mname:
00142 bsop.input = msg
00143 if bsop.input == None:
00144 self.errorerror = (0x200, 'Couldnt find referenced message: %s' % mname)
00145
00146 otag = op.getElementsByTagName('output')
00147 if otag != []:
00148 mname = otag[0].getAttribute('message')
00149 for msg in bsdef.messages:
00150 if msg.name == mname:
00151 bsop.output = msg
00152 if bsop.output == None:
00153 self.errorerror = (0x200, 'Couldnt find referenced message: %s' % mname)
00154
00155 ftag = op.getElementsByTagName('fault')
00156 if ftag != []:
00157 mname = ftag[0].getAttribute('message')
00158 for msg in bsdef.messages:
00159 if msg.name == mname:
00160 bsop.fault = msg
00161 if bsop.fault == None:
00162 self.errorerror = (0x200, 'Couldnt find referenced message: %s' % mname)
00163
00164 bspt.operations.append(bsop)
00165
00166 def AddServices(self, dom, bsdef):
00167 """Add the services to the bs_definition structure.
00168
00169 Args:
00170 dom -- DOM structure of the definitions.
00171 bsdef -- bs_definition class to add them to.
00172 """
00173 services = dom.getElementsByTagName('service')
00174 for svc in services:
00175 bssvc = bs_service(svc.getAttribute('name'))
00176 self.AddPortsAddPorts(svc, bssvc, bsdef)
00177 bsdef.services.append(bssvc)
00178
00179 def AddPorts(self, svc, bssvc, bsdef):
00180 """Add the ports to the service, by using a partially
00181 completed/parsed bs_definition class as a reference.
00182
00183 Args:
00184 svc -- Part of the DOM used for searching the services.
00185 bssvc -- bs_service class to add the ports to.
00186 bsdef -- bs_definition class to search for port types.
00187 """
00188 ports = svc.getElementsByTagName('port')
00189 for port in ports:
00190 pname = port.getAttribute('name')
00191 tname = port.getAttribute('type')
00192 type = None
00193 for t in bsdef.porttypes:
00194 if t.name == tname:
00195 type = t
00196 break
00197 if type == None:
00198 self.errorerror(0x200, 'Couldnt find specified porttype: %s' % tname)
00199 else:
00200 bssvc.ports.append(bs_port(pname, type))
00201
00202 def ParseResponse(self, dom):
00203 uuid = dom.documentElement.getAttribute('uuid')
00204 resp = bs_service_response(None, None, None, uuid)
00205
00206 self.AddUsedAddUsed(dom, resp)
00207
00208 dom.unlink()
00209 if self.errorerror != None:
00210 return None
00211 else:
00212 self.errorerror = None
00213 return resp
00214
00215 def AddUsed(self, dom, resp):
00216 used = dom.getElementsByTagName('used')[0]
00217 resp.service = used.getAttribute('service')
00218 resp.port = used.getAttribute('port')
00219 resp.operation = used.getAttribute('operation')
00220
00221 output = dom.getElementsByTagName('output')
00222 if len(output) == 1:
00223 resp.output = self.AddMessageInstanceAddMessageInstance(dom, output[0],
00224 'output')
00225
00226 fault = dom.getElementsByTagName('fault')
00227 if len(fault) == 1:
00228 resp.fault = self.AddMessageInstanceAddMessageInstance(dom, fault[0],
00229 'fault')
00230
00231 def AddMessageInstance(self, dom, message, direction):
00232 name = message.getAttribute('message')
00233 msg = bs_message_instance(name, direction)
00234
00235 parts = dom.getElementsByTagName('part')
00236 for part in parts:
00237 name = part.getAttribute('name')
00238 type = bs_data_type(part.getAttribute('type'))
00239 rawdata = ''
00240 if hasattr(part.firstChild, 'data'):
00241 rawdata = part.firstChild.data
00242 if not type.isBuiltin():
00243 rawdata = base64.b64decode(rawdata)
00244 msg.parts.append(bs_part_instance(name, type, rawdata))
00245
00246 return msg
00247