• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

contrib/opal/ZSI/build/lib/ZSI/writer.py

00001 #! /usr/bin/env python
00002 # $Id: writer.py 1367 2007-03-27 19:20:47Z boverhof $
00003 '''SOAP message serialization.
00004 '''
00005 
00006 from ZSI import _copyright, _get_idstr, ZSI_SCHEMA_URI
00007 from ZSI import _backtrace, _stringtypes, _seqtypes
00008 from ZSI.wstools.Utility import MessageInterface, ElementProxy
00009 from ZSI.wstools.Namespaces import XMLNS, SOAP, SCHEMA
00010 from ZSI.wstools.c14n import Canonicalize
00011 import types
00012 
00013 _standard_ns = [ ('xml', XMLNS.XML), ('xmlns', XMLNS.BASE) ]
00014 
00015 _reserved_ns = {
00016         'SOAP-ENV': SOAP.ENV,
00017         'SOAP-ENC': SOAP.ENC,
00018         'ZSI': ZSI_SCHEMA_URI,
00019         'xsd': SCHEMA.BASE,
00020         'xsi': SCHEMA.BASE + '-instance',
00021 }
00022 
00023 class SoapWriter:
00024     '''SOAP output formatter.
00025        Instance Data:
00026            memo -- memory for id/href 
00027            envelope -- add Envelope?
00028            encodingStyle -- 
00029            header -- add SOAP Header?
00030            outputclass -- ElementProxy class.
00031     '''
00032 
00033     def __init__(self, envelope=True, encodingStyle=None, header=True, 
00034     nsdict={}, outputclass=None, **kw):
00035         '''Initialize.
00036         '''
00037         outputclass = outputclass or ElementProxy
00038         if not issubclass(outputclass, MessageInterface):
00039             raise TypeError, 'outputclass must subclass MessageInterface'
00040 
00041         self.dom, self.memo, self.nsdict= \
00042             outputclass(self), [], nsdict
00043         self.envelope = envelope
00044         self.encodingStyle = encodingStyle
00045         self.header = header
00046         self.body = None
00047         self.callbacks = []
00048         self.closed = False
00049 
00050     def __str__(self):
00051         self.close()
00052         return str(self.dom)
00053 
00054     def getSOAPHeader(self):
00055         if self.header in (True, False):
00056             return None
00057         return self.header
00058 
00059     def serialize_header(self, pyobj, typecode=None, **kw):
00060         '''Serialize a Python object in SOAP-ENV:Header, make
00061         sure everything in Header unique (no #href).  Must call
00062         serialize first to create a document.
00063 
00064         Parameters: 
00065             pyobjs -- instances to serialize in SOAP Header
00066             typecode -- default typecode
00067         '''
00068         kw['unique'] = True
00069         soap_env = _reserved_ns['SOAP-ENV']
00070         #header = self.dom.getElement(soap_env, 'Header')
00071         header = self._header
00072         if header is None:
00073             header = self._header = self.dom.createAppendElement(soap_env, 
00074                                                                  'Header')
00075 
00076         typecode = getattr(pyobj, 'typecode', typecode)
00077         if typecode is None:
00078             raise RuntimeError(
00079                    'typecode is required to serialize pyobj in header')
00080 
00081         helt = typecode.serialize(header, self, pyobj, **kw)
00082 
00083     def serialize(self, pyobj, typecode=None, root=None, header_pyobjs=(), **kw):
00084         '''Serialize a Python object to the output stream.
00085            pyobj -- python instance to serialize in body.
00086            typecode -- typecode describing body 
00087            root -- SOAP-ENC:root
00088            header_pyobjs -- list of pyobj for soap header inclusion, each
00089               instance must specify the typecode attribute.
00090         '''
00091         self.body = None
00092         if self.envelope: 
00093             soap_env = _reserved_ns['SOAP-ENV']
00094             self.dom.createDocument(soap_env, 'Envelope')
00095             for prefix, nsuri in _reserved_ns.items():
00096                 self.dom.setNamespaceAttribute(prefix, nsuri)
00097             self.writeNSdict(self.nsdict)
00098             if self.encodingStyle:
00099                 self.dom.setAttributeNS(soap_env, 'encodingStyle', 
00100                                         self.encodingStyle)
00101             if self.header:
00102                 self._header = self.dom.createAppendElement(soap_env, 'Header')
00103 
00104                 for h in header_pyobjs:
00105                     self.serialize_header(h, **kw)
00106 
00107             self.body = self.dom.createAppendElement(soap_env, 'Body')
00108         else:
00109             self.dom.createDocument(None,None)
00110 
00111         if typecode is None: 
00112             typecode = pyobj.__class__.typecode
00113             
00114         if self.body is None:
00115             elt = typecode.serialize(self.dom, self, pyobj, **kw)
00116         else:
00117             elt = typecode.serialize(self.body, self, pyobj, **kw)
00118             
00119         if root is not None:
00120             if root not in [ 0, 1 ]:
00121                 raise ValueError, "SOAP-ENC root attribute not in [0,1]"
00122             elt.setAttributeNS(SOAP.ENC, 'root', root)
00123                         
00124         return self
00125 
00126     def writeNSdict(self, nsdict):
00127         '''Write a namespace dictionary, taking care to not clobber the
00128         standard (or reserved by us) prefixes.
00129         '''
00130         for k,v in nsdict.items():
00131             if (k,v) in _standard_ns: continue
00132             rv = _reserved_ns.get(k)
00133             if rv:
00134                 if rv != v:
00135                     raise KeyError("Reserved namespace " + str((k,v)) + " used")
00136                 continue
00137             if k:
00138                 self.dom.setNamespaceAttribute(k, v)
00139             else:
00140                 self.dom.setNamespaceAttribute('xmlns', v)
00141 
00142 
00143     def ReservedNS(self, prefix, uri):
00144         '''Is this namespace (prefix,uri) reserved by us?
00145         '''
00146         return _reserved_ns.get(prefix, uri) != uri
00147 
00148     def AddCallback(self, func, *arglist):
00149         '''Add a callback function and argument list to be invoked before
00150         closing off the SOAP Body.
00151         '''
00152         self.callbacks.append((func, arglist))
00153 
00154     def Known(self, obj):
00155         '''Seen this object (known by its id()?  Return 1 if so,
00156         otherwise add it to our memory and return 0.
00157         '''
00158         obj = _get_idstr(obj)
00159         if obj in self.memo: return 1
00160         self.memo.append(obj)
00161         return 0
00162 
00163     def Forget(self, obj):
00164         '''Forget we've seen this object.
00165         '''
00166         obj = _get_idstr(obj)
00167         try:
00168             self.memo.remove(obj)
00169         except ValueError:
00170             pass
00171 
00172     def Backtrace(self, elt):
00173         '''Return a human-readable "backtrace" from the document root to
00174         the specified element.
00175         '''
00176         return _backtrace(elt._getNode(), self.dom._getNode())
00177 
00178     def close(self):
00179         '''Invoke all the callbacks, and close off the SOAP message.
00180         '''
00181         if self.closed: return
00182         for func,arglist in self.callbacks:
00183             apply(func, arglist)
00184         self.closed = True
00185 
00186     def __del__(self):
00187         if not self.closed: self.close()
00188         
00189 
00190 if __name__ == '__main__': print _copyright

Generated on Wed Oct 20 2010 11:12:16 for APBS by  doxygen 1.7.2