renaming the toplevel geni/ package into sfa/
[sfa.git] / wsdl / gw2wsdl.py
1 #!/usr/bin/python
2 #
3 # Sapan Bhatia <sapanb@cs.princeton.edu>
4 #
5 # This code is under preliminary development. I am going to clean it up
6 # once it is tested to work.
7 # Generates a WSDL for geniwrapper
8
9
10 import os, sys
11 import time
12 import pdb
13 import xml.dom.minidom
14 import xml.dom.ext
15 import globals
16 import apistub
17 from types import *
18
19 from sfa.util.auth import Auth
20 from sfa.util.parameter import Parameter,Mixed
21
22 complex_types = {}
23 services = {}
24
25 num_types = 0
26
27 class SoapError(Exception):
28      def __init__(self, value):
29          self.value = value
30      def __str__(self):
31          return repr(self.value)
32 try:
33     set
34 except NameError:
35     from sets import Set
36     set = Set
37
38 def fold_complex_type_names(acc, arg):
39     name = arg.doc
40     if (type(acc)==list):
41         acc.append(name)
42     else:
43         python_is_braindead = acc.doc
44         acc = [python_is_braindead,name]
45     return acc
46
47
48 def fold_complex_type(acc, arg):
49     global complex_types
50     name = name_complex_type(arg)
51     complex_types[arg]=name
52     if (type(acc)==list):
53         acc.append(name)
54     else:
55         python_is_braindead = name_complex_type(acc)
56         acc = [python_is_braindead,name]
57     return acc
58
59 def name_complex_type(arg):
60     global num_types
61     global types
62
63     #if (complex_types.has_key(arg)):
64     #    return complex_types[arg]
65
66     types_section = types.getElementsByTagName("xsd:schema")[0]
67
68     if (isinstance(arg, Mixed)):
69         inner_types = reduce(fold_complex_type, arg)
70         inner_names = reduce(fold_complex_type_names, arg)
71         if (inner_types[-1]=="none"):
72             inner_types=inner_types[:-1]
73             min_args = 0
74         else:
75             min_args = 1
76     
77         num_types=num_types+1
78         type_name = "Type%d"%num_types
79         complex_type = types_section.appendChild(types.createElement("xsd:complexType"))
80         complex_type.setAttribute("name", type_name)
81
82         choice = complex_type.appendChild(types.createElement("xsd:choice"))
83         for n,t in zip(inner_names,inner_types):
84             element = choice.appendChild(types.createElement("element"))
85             element.setAttribute("name", n)
86             element.setAttribute("type", "%s"%t)
87             element.setAttribute("minOccurs","%d"%min_args)
88         return "xsdl:%s"%type_name
89     elif (isinstance(arg, Parameter)):
90         return (name_simple_type(arg.type))
91     elif type(arg) == ListType or type(arg) == TupleType:
92         inner_type = name_complex_type(arg[0]) 
93         num_types=num_types+1
94         type_name = "Type%d"%num_types
95         complex_type = types_section.appendChild(types.createElement("xsd:complexType"))
96         complex_type.setAttribute("name", type_name)
97         complex_content = complex_type.appendChild(types.createElement("xsd:complexContent"))
98         restriction = complex_content.appendChild(types.createElement("restriction"))
99         restriction.setAttribute("base","soapenc:Array")
100         attribute = restriction.appendChild(types.createElement("attribute"))
101         attribute.setAttribute("ref","soapenc:arrayType")
102         attribute.setAttribute("wsdl:arrayType",inner_type+"[]")
103         return "xsdl:%s"%type_name
104         
105     elif type(arg) == DictType or arg == DictType or issubclass(arg, dict):
106         num_types=num_types+1
107         type_name = "Type%d"%num_types
108         complex_type = types_section.appendChild(types.createElement("xsd:complexType"))
109         complex_type.setAttribute("name", type_name)
110         complex_content = complex_type.appendChild(types.createElement("xsd:sequence"))
111  
112         for k in arg.fields:
113             inner_type = name_complex_type(arg.fields[k]) 
114             element=complex_content.appendChild(types.createElement("xsd:element"))
115             element.setAttribute("name",k)
116             element.setAttribute("type",inner_type)
117
118         return "xsdl:%s"%type_name 
119
120     else:
121         return (name_simple_type(arg))
122
123 def name_simple_type(arg_type):
124     if arg_type == None:
125         return "none"
126     if arg_type == DictType:
127         return "xsd:anyType"
128     elif arg_type == IntType or arg_type == LongType:
129         return "xsd:int"
130     elif arg_type == bool:
131         return "xsd:boolean"
132     elif arg_type == FloatType:
133         return "xsd:double"
134     elif arg_type in StringTypes:
135         return "xsd:string"
136     else:
137        pdb.set_trace()
138        raise SoapError, "Cannot handle %s objects" % arg_type
139
140 def param_type(arg):
141     return (name_complex_type(arg))
142
143 def add_wsdl_ports_and_bindings (wsdl):
144     for method in apistub.methods:
145         # Skip system. methods
146         if "system." in method:
147             continue
148
149         function = apistub.callable(method) # Commented documentation
150         #lines = ["// " + line.strip() for line in function.__doc__.strip().split("\n")]
151         #print "\n".join(lines)
152         #print
153
154         
155         in_el = wsdl.firstChild.appendChild(wsdl.createElement("message"))
156         in_el.setAttribute("name", method + "_in")
157
158         for service_name in function.interfaces:
159             if (services.has_key(service_name)):
160                 if (not method in services[service_name]):
161                     services[service_name].append(method)
162             else:
163                 services[service_name]=[method]
164
165         # Arguments
166
167         if (function.accepts):
168             (min_args, max_args, defaults) = function.args()
169             for (argname,argtype) in zip(max_args,function.accepts):
170                 arg_part = in_el.appendChild(wsdl.createElement("part"))
171                 arg_part.setAttribute("name", argname)
172                 arg_part.setAttribute("type", param_type(argtype))
173                 
174         # Return type            
175         return_type = function.returns
176         out_el = wsdl.firstChild.appendChild(wsdl.createElement("message"))
177         out_el.setAttribute("name", method + "_out")
178         ret_part = out_el.appendChild(wsdl.createElement("part"))
179         ret_part.setAttribute("name", "returnvalue")
180         ret_part.setAttribute("type", param_type(return_type))
181
182         # Port connecting arguments with return type
183
184         port_el = wsdl.firstChild.appendChild(wsdl.createElement("portType"))
185         port_el.setAttribute("name", method + "_port")
186         
187         op_el = port_el.appendChild(wsdl.createElement("operation"))
188         op_el.setAttribute("name", method)
189         inp_el=wsdl.createElement("input")
190         inp_el.setAttribute("message","tns:" + method + "_in")
191         inp_el.setAttribute("name",method+"_request")
192         op_el.appendChild(inp_el)
193         out_el = wsdl.createElement("output")
194         out_el.setAttribute("message","tns:" + method + "_out")
195         out_el.setAttribute("name",method+"_response")
196         op_el.appendChild(out_el)
197
198         # Bindings
199
200         bind_el = wsdl.firstChild.appendChild(wsdl.createElement("binding"))
201         bind_el.setAttribute("name", method + "_binding")
202         bind_el.setAttribute("type", "tns:" + method + "_port")
203         
204         soap_bind = bind_el.appendChild(wsdl.createElement("soap:binding"))
205         soap_bind.setAttribute("style", "rpc")
206         soap_bind.setAttribute("transport","http://schemas.xmlsoap.org/soap/http")
207
208         
209         wsdl_op = bind_el.appendChild(wsdl.createElement("operation"))
210         wsdl_op.setAttribute("name", method)
211         wsdl_op.appendChild(wsdl.createElement("soap:operation")).setAttribute("soapAction",
212                 "urn:" + method)
213
214         
215         wsdl_input = wsdl_op.appendChild(wsdl.createElement("input"))
216         input_soap_body = wsdl_input.appendChild(wsdl.createElement("soap:body"))
217         input_soap_body.setAttribute("use", "encoded")
218         input_soap_body.setAttribute("namespace", "urn:" + method)
219         input_soap_body.setAttribute("encodingStyle","http://schemas.xmlsoap.org/soap/encoding/")
220
221         
222         wsdl_output = wsdl_op.appendChild(wsdl.createElement("output"))
223         output_soap_body = wsdl_output.appendChild(wsdl.createElement("soap:body"))
224         output_soap_body.setAttribute("use", "encoded")
225         output_soap_body.setAttribute("namespace", "urn:" + method)
226         output_soap_body.setAttribute("encodingStyle","http://schemas.xmlsoap.org/soap/encoding/")
227         
228
229 def add_wsdl_service(wsdl):
230     for service in services.keys():
231         service_el = wsdl.firstChild.appendChild(wsdl.createElement("service"))
232         service_el.setAttribute("name", service)
233
234         for method in services[service]:
235             name=method
236             servport_el = service_el.appendChild(wsdl.createElement("port"))
237             servport_el.setAttribute("name", name + "_port")
238             servport_el.setAttribute("binding", "tns:" + name + "_binding")
239
240             soapaddress = servport_el.appendChild(wsdl.createElement("soap:address"))
241             soapaddress.setAttribute("location", "%s/%s" % (globals.plc_ns,service))
242
243
244 def get_wsdl_definitions():
245     wsdl_text_header = """
246         <wsdl:definitions
247         name="geniwrapper_autogenerated"
248         targetNamespace="%s/2009/06/sfa.wsdl"
249         xmlns="http://schemas.xmlsoap.org/wsdl/"
250         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
251         xmlns:xsdl="http://%s/2009/06/schema"
252         xmlns:tns="%s/2009/06/sfa.wsdl"
253         xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
254         xmlns:soapenc="http://schemas.xmlsoap.org/wsdl/soap/encoding"
255         xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
256         """ % (globals.plc_ns,globals.plc_ns,globals.plc_ns)
257         
258     wsdl = xml.dom.minidom.parseString(wsdl_text_header)
259     
260     return wsdl
261
262 def get_wsdl_definitions_and_types():
263     wsdl_text_header = """
264     <wsdl:definitions
265         name="geniwrapper_autogenerated"
266         targetNamespace="%s/2009/06/sfa.wsdl"
267         xmlns="http://schemas.xmlsoap.org/wsdl/"
268         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
269         xmlns:xsdl="http://%s/2009/06/schema"
270         xmlns:tns="%s/2009/06/sfa.wsdl"
271         xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
272         xmlns:soapenc="http://schemas.xmlsoap.org/wsdl/soap/encoding"
273         xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
274         <types>
275             <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="%s/2009/06/schema"/>
276         </types>
277     </wsdl:definitions> """ % (globals.plc_ns, globals.plc_ns, globals.plc_ns, globals.plc_ns)
278     wsdl = xml.dom.minidom.parseString(wsdl_text_header)
279     return wsdl
280
281     
282 types = get_wsdl_definitions_and_types()
283
284 wsdl = get_wsdl_definitions()
285 add_wsdl_ports_and_bindings(wsdl)
286 wsdl_types = wsdl.importNode(types.getElementsByTagName("types")[0], True)
287 wsdl.firstChild.appendChild(wsdl_types)
288 add_wsdl_service(wsdl)
289
290 xml.dom.ext.PrettyPrint(wsdl)