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

contrib/opal/ZSI/ZSI/dispatch.py

00001 #! /usr/bin/env python
00002 # $Header$
00003 '''Simple CGI dispatching.
00004 '''
00005 
00006 import types, os, sys
00007 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
00008 from ZSI import *
00009 from ZSI import _child_elements, _copyright, _seqtypes, _find_arraytype, _find_type, resolvers 
00010 from ZSI.auth import _auth_tc, AUTH, ClientBinding
00011 
00012 
00013 # Client binding information is stored in a global. We provide an accessor
00014 # in case later on it's not.
00015 _client_binding = None
00016 
00017 def GetClientBinding():
00018     '''Return the client binding object.
00019     '''
00020     return _client_binding
00021 
00022 gettypecode = lambda mod,e: getattr(mod, str(e.localName)).typecode
00023 def _Dispatch(ps, modules, SendResponse, SendFault, nsdict={}, typesmodule=None, 
00024               gettypecode=gettypecode, rpc=False, docstyle=False, **kw):
00025     '''Find a handler for the SOAP request in ps; search modules.
00026     Call SendResponse or SendFault to send the reply back, appropriately.
00027 
00028     Behaviors:
00029         default -- Call "handler" method with pyobj representation of body root, and return
00030             a self-describing request (w/typecode).  Parsing done via a typecode from 
00031             typesmodule, or Any.
00032 
00033         docstyle -- Call "handler" method with ParsedSoap instance and parse result with an
00034           XML typecode (DOM). Behavior, wrap result in a body_root "Response" appended message.
00035 
00036         rpc -- Specify RPC wrapper of result. Behavior, ignore body root (RPC Wrapper)
00037            of request, parse all "parts" of message via individual typecodes.  Expect
00038            the handler to return the parts of the message, whether it is a dict, single instance, 
00039            or a list try to serialize it as a Struct but if this is not possible put it in an Array.
00040            Parsing done via a typecode from typesmodule, or Any.
00041 
00042     '''
00043     global _client_binding
00044     try:
00045         what = str(ps.body_root.localName)
00046 
00047         # See what modules have the element name.
00048         if modules is None:
00049             modules = ( sys.modules['__main__'], )
00050 
00051         handlers = [ getattr(m, what) for m in modules if hasattr(m, what) ]
00052         if len(handlers) == 0:
00053             raise TypeError("Unknown method " + what)
00054 
00055         # Of those modules, see who's callable.
00056         handlers = [ h for h in handlers if callable(h) ]
00057         if len(handlers) == 0:
00058             raise TypeError("Unimplemented method " + what)
00059         if len(handlers) > 1:
00060             raise TypeError("Multiple implementations found: " + `handlers`)
00061         handler = handlers[0]
00062 
00063         _client_binding = ClientBinding(ps)
00064         if docstyle:
00065             result = handler(ps.body_root)
00066             tc = TC.XML(aslist=1, pname=what+'Response')
00067         elif not rpc:
00068             try:
00069                 tc = gettypecode(typesmodule, ps.body_root)
00070             except Exception:
00071                 tc = TC.Any()
00072 
00073             try:
00074                 arg = tc.parse(ps.body_root, ps)
00075             except EvaluateException, ex:
00076                 SendFault(FaultFromZSIException(ex), **kw)
00077                 return
00078 
00079             try:
00080                 result = handler(arg)
00081             except Exception,ex:
00082                 SendFault(FaultFromZSIException(ex), **kw)
00083                 return
00084 
00085             try:
00086                 tc = result.typecode
00087             except AttributeError,ex:
00088                 SendFault(FaultFromZSIException(ex), **kw)
00089                 return
00090 
00091         elif typesmodule is not None:
00092             kwargs = {}
00093             for e in _child_elements(ps.body_root):
00094                 try:
00095                     tc = gettypecode(typesmodule, e)
00096                 except Exception:
00097                     tc = TC.Any()
00098 
00099                 try:
00100                     kwargs[str(e.localName)] = tc.parse(e, ps)
00101                 except EvaluateException, ex:
00102                     SendFault(FaultFromZSIException(ex), **kw)
00103                     return
00104 
00105             result = handler(**kwargs)
00106             aslist = False
00107             # make sure data is wrapped, try to make this a Struct
00108             if type(result) in _seqtypes:
00109                  for o in result:
00110                      aslist = hasattr(result, 'typecode')
00111                      if aslist: break
00112             elif type(result) is not dict:
00113                  aslist = not hasattr(result, 'typecode')
00114                  result = (result,)
00115 
00116             tc = TC.Any(pname=what+'Response', aslist=aslist)
00117         else:
00118             # if this is an Array, call handler with list
00119             # if this is an Struct, call handler with dict
00120             tp = _find_type(ps.body_root)
00121             isarray = ((type(tp) in (tuple,list) and tp[1] == 'Array') or _find_arraytype(ps.body_root))
00122             data = _child_elements(ps.body_root)
00123             tc = TC.Any()
00124             if isarray and len(data) == 0:
00125                 result = handler()
00126             elif isarray:
00127                 try: arg = [ tc.parse(e, ps) for e in data ]
00128                 except EvaluateException, e:
00129                     #SendFault(FaultFromZSIException(e), **kw)
00130                     SendFault(RuntimeError("THIS IS AN ARRAY: %s" %isarray))
00131                     return
00132 
00133                 result = handler(*arg)
00134             else:
00135                 try: kwarg = dict([ (str(e.localName),tc.parse(e, ps)) for e in data ])
00136                 except EvaluateException, e:
00137                     SendFault(FaultFromZSIException(e), **kw)
00138                     return
00139 
00140                 result = handler(**kwarg)
00141 
00142             # reponse typecode
00143             #tc = getattr(result, 'typecode', TC.Any(pname=what+'Response'))
00144             tc = TC.Any(pname=what+'Response')
00145 
00146         sw = SoapWriter(nsdict=nsdict)
00147         sw.serialize(result, tc)
00148         return SendResponse(str(sw), **kw)
00149     except Fault, e:
00150         return SendFault(e, **kw)
00151     except Exception, e:
00152         # Something went wrong, send a fault.
00153         return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
00154 
00155 
00156 def _ModPythonSendXML(text, code=200, **kw):
00157     req = kw['request']
00158     req.content_type = 'text/xml'
00159     req.content_length = len(text)
00160     req.send_http_header()
00161     req.write(text)
00162 
00163 
00164 def _ModPythonSendFault(f, **kw):
00165     _ModPythonSendXML(f.AsSOAP(), 500, **kw)
00166 
00167 def _JonPySendFault(f, **kw):
00168     _JonPySendXML(f.AsSOAP(), 500, **kw)
00169 
00170 def _JonPySendXML(text, code=200, **kw):
00171     req = kw['request']
00172     req.set_header("Content-Type", 'text/xml; charset="%s"' %UNICODE_ENCODING)
00173     req.set_header("Content-Length", str(len(text)))
00174     req.write(text)
00175 
00176 def _CGISendXML(text, code=200, **kw):
00177     print 'Status: %d' % code
00178     print 'Content-Type: text/xml; charset="%s"' %UNICODE_ENCODING
00179     print 'Content-Length: %d' % len(text)
00180     print ''
00181     print text
00182 
00183 def _CGISendFault(f, **kw):
00184     _CGISendXML(f.AsSOAP(), 500, **kw)
00185 
00186 
00187 class SOAPRequestHandler(BaseHTTPRequestHandler):
00188     '''SOAP handler.
00189     '''
00190     server_version = 'ZSI/1.1 ' + BaseHTTPRequestHandler.server_version
00191 
00192     def send_xml(self, text, code=200):
00193         '''Send some XML.
00194         '''
00195         self.send_response(code)
00196         
00197         if text:
00198             self.send_header('Content-type', 'text/xml; charset="%s"' %UNICODE_ENCODING)
00199             self.send_header('Content-Length', str(len(text)))
00200 
00201         self.end_headers()
00202         
00203         if text:
00204             self.wfile.write(text)
00205 
00206         self.wfile.flush()
00207 
00208     def send_fault(self, f, code=500):
00209         '''Send a fault.
00210         '''
00211         self.send_xml(f.AsSOAP(), code)
00212 
00213     def do_POST(self):
00214         '''The POST command.
00215         '''
00216         try:
00217             ct = self.headers['content-type']
00218             if ct.startswith('multipart/'):
00219                 cid = resolvers.MIMEResolver(ct, self.rfile)
00220                 xml = cid.GetSOAPPart()
00221                 ps = ParsedSoap(xml, resolver=cid.Resolve)
00222             else:
00223                 length = int(self.headers['content-length'])
00224                 ps = ParsedSoap(self.rfile.read(length))
00225         except ParseException, e:
00226             self.send_fault(FaultFromZSIException(e))
00227             return
00228         except Exception, e:
00229             # Faulted while processing; assume it's in the header.
00230             self.send_fault(FaultFromException(e, 1, sys.exc_info()[2]))
00231             return
00232 
00233         _Dispatch(ps, self.server.modules, self.send_xml, self.send_fault,
00234                   docstyle=self.server.docstyle, nsdict=self.server.nsdict,
00235                   typesmodule=self.server.typesmodule, rpc=self.server.rpc)
00236 
00237 def AsServer(port=80, modules=None, docstyle=False, nsdict={}, typesmodule=None,
00238              rpc=False, addr=''):
00239     address = (addr, port)
00240     httpd = HTTPServer(address, SOAPRequestHandler)
00241     httpd.modules = modules
00242     httpd.docstyle = docstyle
00243     httpd.nsdict = nsdict
00244     httpd.typesmodule = typesmodule
00245     httpd.rpc = rpc
00246     httpd.serve_forever()
00247 
00248 def AsCGI(nsdict={}, typesmodule=None, rpc=False, modules=None):
00249     '''Dispatch within a CGI script.
00250     '''
00251     if os.environ.get('REQUEST_METHOD') != 'POST':
00252         _CGISendFault(Fault(Fault.Client, 'Must use POST'))
00253         return
00254     ct = os.environ['CONTENT_TYPE']
00255     try:
00256         if ct.startswith('multipart/'):
00257             cid = resolvers.MIMEResolver(ct, sys.stdin)
00258             xml = cid.GetSOAPPart()
00259             ps = ParsedSoap(xml, resolver=cid.Resolve)
00260         else:
00261             length = int(os.environ['CONTENT_LENGTH'])
00262             ps = ParsedSoap(sys.stdin.read(length))
00263     except ParseException, e:
00264         _CGISendFault(FaultFromZSIException(e))
00265         return
00266     _Dispatch(ps, modules, _CGISendXML, _CGISendFault, nsdict=nsdict,
00267               typesmodule=typesmodule, rpc=rpc)
00268 
00269 def AsHandler(request=None, modules=None, **kw):
00270     '''Dispatch from within ModPython.'''
00271     ps = ParsedSoap(request)
00272     kw['request'] = request
00273     _Dispatch(ps, modules, _ModPythonSendXML, _ModPythonSendFault, **kw)
00274     
00275 def AsJonPy(request=None, modules=None, **kw):
00276     '''Dispatch within a jonpy CGI/FastCGI script.
00277     '''
00278 
00279     kw['request'] = request
00280     if request.environ.get('REQUEST_METHOD') != 'POST':
00281         _JonPySendFault(Fault(Fault.Client, 'Must use POST'), **kw)
00282         return
00283     ct = request.environ['CONTENT_TYPE']
00284     try:
00285         if ct.startswith('multipart/'):
00286             cid = resolvers.MIMEResolver(ct, request.stdin)
00287             xml = cid.GetSOAPPart()
00288             ps = ParsedSoap(xml, resolver=cid.Resolve)
00289         else:
00290             length = int(request.environ['CONTENT_LENGTH'])
00291             ps = ParsedSoap(request.stdin.read(length))
00292     except ParseException, e:
00293         _JonPySendFault(FaultFromZSIException(e), **kw)
00294         return
00295     _Dispatch(ps, modules, _JonPySendXML, _JonPySendFault, **kw)
00296 
00297 
00298 if __name__ == '__main__': print _copyright

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