(no commit message)
[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 geni.util.auth import Auth
20 from geni.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 "tns:%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","Array")
100         attribute = restriction.appendChild(types.createElement("attribute"))
101         attribute.setAttribute("wsdl:arrayType",inner_type+"[]")
102         return "tns:%s"%type_name
103         
104     elif type(arg) == DictType or arg == DictType or issubclass(arg, dict):
105         num_types=num_types+1
106         type_name = "Type%d"%num_types
107         complex_type = types_section.appendChild(types.createElement("xsd:complexType"))
108         complex_type.setAttribute("name", type_name)
109         complex_content = complex_type.appendChild(types.createElement("xsd:sequence"))
110  
111         for k in arg.fields:
112             inner_type = name_complex_type(arg.fields[k]) 
113             element=complex_content.appendChild(types.createElement("xsd:element"))
114             element.setAttribute("name",k)
115             element.setAttribute("type",inner_type)
116
117         return "tns:%s"%type_name 
118
119     else:
120         return (name_simple_type(arg))
121
122 def name_simple_type(arg_type):
123     if arg_type == None:
124         return "none"
125     if arg_type == DictType:
126         return "xsd:anyType"
127     elif arg_type == IntType or arg_type == LongType:
128         return "xsd:int"
129     elif arg_type == bool:
130         return "xsd:boolean"
131     elif arg_type == FloatType:
132         return "xsd:double"
133     elif arg_type in StringTypes:
134         return "xsd:string"
135     else:
136        pdb.set_trace()
137        raise SoapError, "Cannot handle %s objects" % arg_type
138
139 def param_type(arg):
140     return (name_complex_type(arg))
141
142 def add_wsdl_ports_and_bindings (wsdl):
143     for method in apistub.methods:
144         # Skip system. methods
145         if "system." in method:
146             continue
147
148         function = apistub.callable(method) # Commented documentation
149         #lines = ["// " + line.strip() for line in function.__doc__.strip().split("\n")]
150         #print "\n".join(lines)
151         #print
152
153         
154         in_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:message"))
155         in_el.setAttribute("name", method + "_in")
156
157         for service_name in function.interfaces:
158             if (services.has_key(service_name)):
159                 if (not method in services[service_name]):
160                     services[service_name].append(method)
161             else:
162                 services[service_name]=[method]
163
164         # Arguments
165
166         if (function.accepts):
167             (min_args, max_args, defaults) = function.args()
168             for (argname,argtype) in zip(max_args,function.accepts):
169                 arg_part = in_el.appendChild(wsdl.createElement("wsdl:part"))
170                 arg_part.setAttribute("name", argname)
171                 arg_part.setAttribute("type", param_type(argtype))
172                 
173         # Return type            
174         return_type = function.returns
175         out_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:message"))
176         out_el.setAttribute("name", method + "_out")
177         ret_part = out_el.appendChild(wsdl.createElement("wsdl:part"))
178         ret_part.setAttribute("name", "returnvalue")
179         ret_part.setAttribute("type", param_type(return_type))
180
181         # Port connecting arguments with return type
182
183         port_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:portType"))
184         port_el.setAttribute("name", method + "_port")
185         
186         op_el = port_el.appendChild(wsdl.createElement("wsdl:operation"))
187         op_el.setAttribute("name", method)
188         inp_el=wsdl.createElement("wsdl:input")
189         inp_el.setAttribute("message","tns:" + method + "_in")
190         inp_el.setAttribute("name",method+"_request")
191         op_el.appendChild(inp_el)
192         out_el = wsdl.createElement("wsdl:output")
193         out_el.setAttribute("message","tns:" + method + "_out")
194         out_el.setAttribute("name",method+"_response")
195         op_el.appendChild(out_el)
196
197         # Bindings
198
199         bind_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:binding"))
200         bind_el.setAttribute("name", method + "_binding")
201         bind_el.setAttribute("type", "tns:" + method + "_port")
202         
203         soap_bind = bind_el.appendChild(wsdl.createElement("soap:binding"))
204         soap_bind.setAttribute("style", "rpc")
205         soap_bind.setAttribute("transport","http://schemas.xmlsoap.org/soap/http")
206
207         
208         wsdl_op = bind_el.appendChild(wsdl.createElement("wsdl:operation"))
209         wsdl_op.setAttribute("name", method)
210         wsdl_op.appendChild(wsdl.createElement("soap:operation")).setAttribute("soapAction",
211                 "urn:" + method)
212
213         
214         wsdl_input = wsdl_op.appendChild(wsdl.createElement("wsdl:input"))
215         input_soap_body = wsdl_input.appendChild(wsdl.createElement("soap:body"))
216         input_soap_body.setAttribute("use", "encoded")
217         input_soap_body.setAttribute("namespace", "urn:" + method)
218         input_soap_body.setAttribute("encodingStyle","http://schemas.xmlsoap.org/soap/encoding/")
219
220         
221         wsdl_output = wsdl_op.appendChild(wsdl.createElement("wsdl:output"))
222         output_soap_body = wsdl_output.appendChild(wsdl.createElement("soap:body"))
223         output_soap_body.setAttribute("use", "encoded")
224         output_soap_body.setAttribute("namespace", "urn:" + method)
225         output_soap_body.setAttribute("encodingStyle","http://schemas.xmlsoap.org/soap/encoding/")
226         
227
228 def add_wsdl_service(wsdl):
229     for service in services.keys():
230         service_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:service"))
231         service_el.setAttribute("name", service)
232
233         for method in services[service]:
234             name=method
235             servport_el = service_el.appendChild(wsdl.createElement("wsdl:port"))
236             servport_el.setAttribute("name", name + "_port")
237             servport_el.setAttribute("binding", "tns:" + name + "_binding")
238
239             soapaddress = servport_el.appendChild(wsdl.createElement("soap:address"))
240             soapaddress.setAttribute("location", "%s/%s" % (globals.plc_ns,service))
241
242
243 def get_wsdl_definitions():
244     wsdl_text_header = """
245         <wsdl:definitions
246         name="auto_generated"
247         targetNamespace="%s"
248         xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
249         xmlns:tns="xmlns:%s"
250         xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
251         xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
252         """ % (globals.plc_ns,globals.plc_ns)
253         
254     wsdl = xml.dom.minidom.parseString(wsdl_text_header)
255     
256     return wsdl
257
258 def get_wsdl_definitions():
259     wsdl_text_header = """
260         <wsdl:definitions
261         name="auto_generated"
262         targetNamespace="%s"
263         xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
264         xmlns:tns="%s"
265         xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
266         xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
267         """ % (globals.plc_ns,globals.plc_ns)
268         
269     wsdl = xml.dom.minidom.parseString(wsdl_text_header)
270     
271     return wsdl
272
273 def get_wsdl_definitions_and_types():
274     wsdl_text_header = """
275     <wsdl:definitions
276         name="auto_generated"
277         targetNamespace="%s"
278         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
279         xmlns:tns="%s"
280         xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
281         xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
282         <wsdl:types>
283             <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="%s"/>
284         </wsdl:types>
285     </wsdl:definitions> """ % (globals.plc_ns,globals.plc_ns,globals.plc_ns)
286     wsdl = xml.dom.minidom.parseString(wsdl_text_header)
287     return wsdl
288
289     
290 types = get_wsdl_definitions_and_types()
291
292 wsdl = get_wsdl_definitions()
293 add_wsdl_ports_and_bindings(wsdl)
294 wsdl_types = wsdl.importNode(types.getElementsByTagName("wsdl:types")[0], True)
295 wsdl.firstChild.appendChild(wsdl_types)
296 add_wsdl_service(wsdl)
297
298 xml.dom.ext.PrettyPrint(wsdl)