00001
00002 import inspect
00003 from cStringIO import StringIO
00004 import ZSI, string, sys, getopt, urlparse, types, warnings
00005 from ZSI.wstools import WSDLTools
00006 from ZSI.ServiceContainer import ServiceSOAPBinding, SimpleWSResource, WSAResource
00007
00008 from ZSI.generate import WsdlGeneratorError, Wsdl2PythonError
00009 from utility import TextProtect, GetModuleBaseNameFromWSDL, \
00010 NCName_to_ClassName, GetPartsSubNames, TextProtectAttributeName
00011 from containers import BindingDescription
00012 from wsdl2python import MessageWriter, WriteServiceModule,\
00013 MessageTypecodeContainer, SchemaDescription
00014
00015
00016 rsplit = lambda x,sep,: (x[:x.rfind(sep)], x[x.rfind(sep)+1:],)
00017 if sys.version_info[0:2] == (2, 4, 0, 'final', 0)[0:2]:
00018 rsplit = lambda x,sep,: x.rsplit(sep, 1)
00019
00020
00021 class SOAPService:
00022 def __init__(self, service):
00023 self.classdef = StringIO()
00024 self.initdef = StringIO()
00025 self.location = ''
00026 self.methods = []
00027
00028 def newMethod(self):
00029 '''name -- operation name
00030 '''
00031 self.methods.append(StringIO())
00032 return self.methods[-1]
00033
00034
00035 class ServiceModuleWriter:
00036 '''Creates a skeleton for a SOAP service instance.
00037 '''
00038 indent = ' '*4
00039 server_module_suffix = '_server'
00040 func_aname = TextProtectAttributeName
00041 func_aname = staticmethod(func_aname)
00042 separate_messages = False
00043
00044 def __init__(self, base=ServiceSOAPBinding, prefix='soap',
00045 service_class=SOAPService):
00046 '''
00047 parameters:
00048 base -- either a class definition, or a str representing a qualified
00049 class name (eg. module.name.classname)
00050 prefix -- method prefix.
00051 '''
00052 if inspect.isclass(base):
00053 self.base_class_name = base.__name__
00054 self.base_module_name = inspect.getmodule(base).__name__
00055 else:
00056 self.base_module_name, self.base_class_name = base.rsplit('.', 1)
00057
00058 self.wsdl = None
00059 self.method_prefix = prefix
00060 self._service_class = SOAPService
00061
00062 self.header = None
00063 self.imports = None
00064 self.messages = []
00065 self._services = None
00066 self.types_module_path = None
00067 self.types_module_name = None
00068 self.messages_module_name = None
00069
00070 def reset(self):
00071 self.header = StringIO()
00072 self.imports = StringIO()
00073 self.message = []
00074 self._services = {}
00075
00076 def getIndent(self, level=1):
00077 '''return indent.
00078 '''
00079 assert 0 < level < 10, 'bad indent level %d' %level
00080 return self.indent*level
00081
00082 def getMethodName(self, method):
00083 '''return method name.
00084 '''
00085 return '%s_%s' %(self.method_prefix, TextProtect(method))
00086
00087 def getClassName(self, name):
00088 '''return class name.
00089 '''
00090 return NCName_to_ClassName(name)
00091
00092 def setTypesModuleName(self, name):
00093 self.types_module_name = name
00094
00095
00096 setClientModuleName = setTypesModuleName
00097
00098 def getTypesModuleName(self):
00099 '''return module name.
00100 '''
00101 assert self.wsdl is not None, 'initialize, call fromWSDL'
00102 if self.types_module_name is not None:
00103 return self.types_module_name
00104
00105 wsm = WriteServiceModule(self.wsdl)
00106 return wsm.getTypesModuleName()
00107
00108 def getServiceModuleName(self):
00109 '''return module name.
00110 '''
00111 name = GetModuleBaseNameFromWSDL(self.wsdl)
00112 if not name:
00113 raise WsdlGeneratorError, 'could not determine a service name'
00114
00115 if self.server_module_suffix is None:
00116 return name
00117 return '%s%s' %(name, self.server_module_suffix)
00118
00119 def getTypesModulePath(self):
00120 return self.types_module_path
00121 getClientModulePath = getTypesModulePath
00122
00123 def setTypesModulePath(self, path):
00124 '''setup module path to where client module before calling fromWSDL.
00125 '''
00126 self.types_module_path = path
00127 setClientModulePath = setTypesModulePath
00128
00129 def setUpClassDef(self, service):
00130 '''set class definition and class variables.
00131 service -- ServiceDescription instance
00132 '''
00133 assert isinstance(service, WSDLTools.Service) is True,\
00134 'expecting WSDLTools.Service instance.'
00135
00136 s = self._services[service.name].classdef
00137
00138 print >>s, 'class %s(%s):' %(self.getClassName(service.name), self.base_class_name)
00139
00140 print >>s, '%ssoapAction = {}' % self.getIndent(level=1)
00141 print >>s, '%sroot = {}' % self.getIndent(level=1)
00142
00143 def setUpImports(self):
00144 '''set import statements
00145 '''
00146 i = self.imports
00147 print >>i, 'from ZSI.schema import GED, GTD'
00148 print >>i, 'from ZSI.TCcompound import ComplexType, Struct'
00149
00150 module = self.getTypesModuleName()
00151 package = self.getTypesModulePath()
00152 if package:
00153 module = '%s.%s' %(package, module)
00154
00155 print >>i, 'from %s import *' %(module)
00156
00157 print >>i, 'from %s import %s' %(self.base_module_name, self.base_class_name)
00158
00159 def setUpInitDef(self, service):
00160 '''set __init__ function
00161 '''
00162 assert isinstance(service, WSDLTools.Service), \
00163 'expecting WSDLTools.Service instance.'
00164
00165 sd = self._services[service.name]
00166 d = sd.initdef
00167
00168 if sd.location is not None:
00169 scheme,netloc,path,params,query,fragment = urlparse.urlparse(sd.location)
00170 print >>d, '%sdef __init__(self, post=\'%s\', **kw):' %(self.getIndent(level=1), path)
00171 else:
00172 print >>d, '%sdef __init__(self, post, **kw):' %self.getIndent(level=1)
00173
00174
00175 if self.base_module_name == inspect.getmodule(ServiceSOAPBinding).__name__:
00176 print >>d, '%s%s.__init__(self, post)' %(self.getIndent(level=2), self.base_class_name)
00177 return
00178
00179
00180 print >>d, '%s%s.__init__(self)' %(self.getIndent(level=2), self.base_class_name)
00181
00182 def mangle(self, name):
00183 return TextProtect(name)
00184
00185 def getAttributeName(self, name):
00186 return self.func_aname(name)
00187
00188 def setUpMethods(self, port):
00189 '''set up all methods representing the port operations.
00190 Parameters:
00191 port -- Port that defines the operations.
00192 '''
00193 assert isinstance(port, WSDLTools.Port), \
00194 'expecting WSDLTools.Port not: ' %type(port)
00195
00196 sd = self._services.get(port.getService().name)
00197 assert sd is not None, 'failed to initialize.'
00198
00199 binding = port.getBinding()
00200 portType = port.getPortType()
00201 action_in = ''
00202 for bop in binding.operations:
00203 try:
00204 op = portType.operations[bop.name]
00205 except KeyError, ex:
00206 raise WsdlGeneratorError,\
00207 'Port(%s) PortType(%s) missing operation(%s) defined in Binding(%s)' \
00208 %(port.name,portType.name,bop.name,binding.name)
00209
00210 for ext in bop.extensions:
00211 if isinstance(ext, WSDLTools.SoapOperationBinding):
00212 action_in = ext.soapAction
00213 break
00214 else:
00215 warnings.warn('Port(%s) operation(%s) defined in Binding(%s) missing soapAction' \
00216 %(port.name,op.name,binding.name)
00217 )
00218
00219 msgin = op.getInputMessage()
00220 msgin_name = TextProtect(msgin.name)
00221 method_name = self.getMethodName(op.name)
00222
00223 m = sd.newMethod()
00224 print >>m, '%sdef %s(self, ps, **kw):' %(self.getIndent(level=1), method_name)
00225 if msgin is not None:
00226 print >>m, '%srequest = ps.Parse(%s.typecode)' %(self.getIndent(level=2), msgin_name)
00227 else:
00228 print >>m, '%s# NO input' %self.getIndent(level=2)
00229
00230 msgout = op.getOutputMessage()
00231 if msgout is not None:
00232 msgout_name = TextProtect(msgout.name)
00233 print >>m, '%sreturn request,%s()' %(self.getIndent(level=2), msgout_name)
00234 else:
00235 print >>m, '%s# NO output' % self.getIndent(level=2)
00236 print >>m, '%sreturn request,None' % self.getIndent(level=2)
00237
00238 print >>m, ''
00239 print >>m, '%ssoapAction[\'%s\'] = \'%s\'' %(self.getIndent(level=1), action_in, method_name)
00240 print >>m, '%sroot[(%s.typecode.nspname,%s.typecode.pname)] = \'%s\'' \
00241 %(self.getIndent(level=1), msgin_name, msgin_name, method_name)
00242
00243 return
00244
00245 def setUpHeader(self):
00246 print >>self.header, '#'*50
00247 print >>self.header, '# file: %s.py' %self.getServiceModuleName()
00248 print >>self.header, '#'
00249 print >>self.header, '# skeleton generated by "%s"' %self.__class__
00250 print >>self.header, '# %s' %' '.join(sys.argv)
00251 print >>self.header, '#'
00252 print >>self.header, '#'*50
00253
00254 def write(self, fd=sys.stdout):
00255 '''write out to file descriptor,
00256 should not need to override.
00257 '''
00258 print >>fd, self.header.getvalue()
00259 print >>fd, self.imports.getvalue()
00260
00261 print >>fd, '# Messages ',
00262 for m in self.messages:
00263 print >>fd, m
00264
00265 print >>fd, ''
00266 print >>fd, ''
00267 print >>fd, '# Service Skeletons'
00268 for k,v in self._services.items():
00269 print >>fd, v.classdef.getvalue()
00270 print >>fd, v.initdef.getvalue()
00271 for s in v.methods:
00272 print >>fd, s.getvalue()
00273
00274 def fromWSDL(self, wsdl):
00275 '''setup the service description from WSDL,
00276 should not need to override.
00277 '''
00278 assert isinstance(wsdl, WSDLTools.WSDL), 'expecting WSDL instance'
00279
00280 if len(wsdl.services) == 0:
00281 raise WsdlGeneratorError, 'No service defined'
00282
00283 self.reset()
00284 self.wsdl = wsdl
00285 self.setUpHeader()
00286 self.setUpImports()
00287
00288 for service in wsdl.services:
00289 sd = self._service_class(service.name)
00290 self._services[service.name] = sd
00291
00292 for port in service.ports:
00293 desc = BindingDescription(wsdl=wsdl)
00294 try:
00295 desc.setUp(port.getBinding())
00296 except Wsdl2PythonError, ex:
00297 continue
00298
00299 for soc in desc.operations:
00300 if not soc.hasInput(): continue
00301
00302 self.messages.append(MessageWriter())
00303 self.messages[-1].setUp(soc, port, input=True)
00304 if soc.hasOutput():
00305 self.messages.append(MessageWriter())
00306 self.messages[-1].setUp(soc, port, input=False)
00307
00308 for e in port.extensions:
00309 if isinstance(e, WSDLTools.SoapAddressBinding):
00310 sd.location = e.location
00311
00312 self.setUpMethods(port)
00313
00314 self.setUpClassDef(service)
00315 self.setUpInitDef(service)
00316
00317
00318 class WSAServiceModuleWriter(ServiceModuleWriter):
00319 '''Creates a skeleton for a WS-Address service instance.
00320 '''
00321 def __init__(self, base=WSAResource, prefix='wsa', service_class=SOAPService,
00322 strict=True):
00323 '''
00324 Parameters:
00325 strict -- check that soapAction and input ws-action do not collide.
00326 '''
00327 ServiceModuleWriter.__init__(self, base, prefix, service_class)
00328 self.strict = strict
00329
00330 def createMethodBody(msgInName, msgOutName, **kw):
00331 '''return a tuple of strings containing the body of a method.
00332 msgInName -- None or a str
00333 msgOutName -- None or a str
00334 '''
00335 body = []
00336 if msgInName is not None:
00337 body.append('request = ps.Parse(%s.typecode)' %msgInName)
00338
00339 if msgOutName is not None:
00340 body.append('return request,%s()' %msgOutName)
00341 else:
00342 body.append('return request,None')
00343
00344 return tuple(body)
00345 createMethodBody = staticmethod(createMethodBody)
00346
00347 def setUpClassDef(self, service):
00348 '''use soapAction dict for WS-Action input, setup wsAction
00349 dict for grabbing WS-Action output values.
00350 '''
00351 assert isinstance(service, WSDLTools.Service), \
00352 'expecting WSDLTools.Service instance'
00353
00354 s = self._services[service.name].classdef
00355 print >>s, 'class %s(%s):' %(self.getClassName(service.name), self.base_class_name)
00356 print >>s, '%ssoapAction = {}' % self.getIndent(level=1)
00357 print >>s, '%swsAction = {}' % self.getIndent(level=1)
00358 print >>s, '%sroot = {}' % self.getIndent(level=1)
00359
00360 def setUpMethods(self, port):
00361 '''set up all methods representing the port operations.
00362 Parameters:
00363 port -- Port that defines the operations.
00364 '''
00365 assert isinstance(port, WSDLTools.Port), \
00366 'expecting WSDLTools.Port not: ' %type(port)
00367
00368 binding = port.getBinding()
00369 portType = port.getPortType()
00370 service = port.getService()
00371 s = self._services[service.name]
00372 for bop in binding.operations:
00373 try:
00374 op = portType.operations[bop.name]
00375 except KeyError, ex:
00376 raise WsdlGeneratorError,\
00377 'Port(%s) PortType(%s) missing operation(%s) defined in Binding(%s)' \
00378 %(port.name, portType.name, op.name, binding.name)
00379
00380 soap_action = wsaction_in = wsaction_out = None
00381 if op.input is not None:
00382 wsaction_in = op.getInputAction()
00383 if op.output is not None:
00384 wsaction_out = op.getOutputAction()
00385
00386 for ext in bop.extensions:
00387 if isinstance(ext, WSDLTools.SoapOperationBinding) is False: continue
00388 soap_action = ext.soapAction
00389 if not soap_action: break
00390 if wsaction_in is None: break
00391 if wsaction_in == soap_action: break
00392 if self.strict is False:
00393 warnings.warn(\
00394 'Port(%s) operation(%s) in Binding(%s) soapAction(%s) != WS-Action(%s)' \
00395 %(port.name, op.name, binding.name, soap_action, wsaction_in),
00396 )
00397 break
00398 raise WsdlGeneratorError,\
00399 'Port(%s) operation(%s) in Binding(%s) soapAction(%s) MUST match WS-Action(%s)' \
00400 %(port.name, op.name, binding.name, soap_action, wsaction_in)
00401
00402 method_name = self.getMethodName(op.name)
00403
00404 m = s.newMethod()
00405 print >>m, '%sdef %s(self, ps, address):' %(self.getIndent(level=1), method_name)
00406
00407 msgin_name = msgout_name = None
00408 msgin,msgout = op.getInputMessage(),op.getOutputMessage()
00409 if msgin is not None:
00410 msgin_name = TextProtect(msgin.name)
00411 if msgout is not None:
00412 msgout_name = TextProtect(msgout.name)
00413
00414 indent = self.getIndent(level=2)
00415 for l in self.createMethodBody(msgin_name, msgout_name):
00416 print >>m, indent + l
00417
00418 print >>m, ''
00419 print >>m, '%ssoapAction[\'%s\'] = \'%s\'' %(self.getIndent(level=1), wsaction_in, method_name)
00420 print >>m, '%swsAction[\'%s\'] = \'%s\'' %(self.getIndent(level=1), method_name, wsaction_out)
00421 print >>m, '%sroot[(%s.typecode.nspname,%s.typecode.pname)] = \'%s\'' \
00422 %(self.getIndent(level=1), msgin_name, msgin_name, method_name)
00423