(no commit message)
[sfa.git] / wsdl / gw2wsdl.py
1 #!/usr/bin/python
2 #
3 # Sapan Bhatia <sapanb@cs.princeton.edu>
4 #
5 # Generates a WSDL for geniwrapper
6 # Current limitations:
7 # - Invalid for the following reasons 
8 # - The types are python types, not WSDL types
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.firstChild.firstChild
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("wsdl: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", "tns:%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         return "sequence"
93     elif type(arg) == DictType or arg == DictType:
94         return "dict"
95     else:
96         return (name_simple_type(arg))
97
98 def name_simple_type(arg_type):
99     if arg_type == None:
100         return "none"
101     if arg_type == DictType:
102         return "xsd:dict"
103     elif arg_type == IntType or arg_type == LongType:
104         return "xsd:int"
105     elif arg_type == bool:
106         return "xsd:boolean"
107     elif arg_type == FloatType:
108         return "xsd:double"
109     elif arg_type in StringTypes:
110         return "xsd:string"
111     else:
112        #pdb.set_trace()
113         raise SoapError, "Cannot handle %s objects" % arg_type
114
115 def param_type(arg):
116     return (name_complex_type(arg))
117
118 def add_wsdl_ports_and_bindings (wsdl):
119     for method in apistub.methods:
120         # Skip system. methods
121         if "system." in method:
122             continue
123
124         function = apistub.callable(method) # Commented documentation
125         #lines = ["// " + line.strip() for line in function.__doc__.strip().split("\n")]
126         #print "\n".join(lines)
127         #print
128
129         
130         in_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:message"))
131         in_el.setAttribute("name", method + "_in")
132
133         for service_name in function.interfaces:
134             if (services.has_key(service_name)):
135                 if (not method in services[service_name]):
136                     services[service_name].append(method)
137             else:
138                 services[service_name]=[method]
139
140         # Arguments
141
142         if (function.accepts):
143             (min_args, max_args, defaults) = function.args()
144             for (argname,argtype) in zip(max_args,function.accepts):
145                 arg_part = in_el.appendChild(wsdl.createElement("wsdl:part"))
146                 arg_part.setAttribute("name", argname)
147                 arg_part.setAttribute("type", param_type(argtype))
148                 
149         # Return type            
150         return_type = function.returns
151         out_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:message"))
152         out_el.setAttribute("name", method + "_out")
153         ret_part = out_el.appendChild(wsdl.createElement("wsdl:part"))
154         ret_part.setAttribute("name", "returnvalue")
155         ret_part.setAttribute("type", param_type(return_type))
156
157         # Port connecting arguments with return type
158
159         port_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:portType"))
160         port_el.setAttribute("name", method + "_port")
161         
162         op_el = port_el.appendChild(wsdl.createElement("wsdl:operation"))
163         op_el.setAttribute("name", method)
164         inp_el=wsdl.createElement("wsdl:input")).setAttribute("message","tns:" + method + "_in"
165         inp_el.setAttribute("name",method+"_request")
166         op_el.appendChild(inp_el)
167         out_el = op_el.appendChild(wsdl.createElement("wsdl:output")).setAttribute("message","tns:" + method + "_out")
168         op_el.appendChild(out_el)
169
170         # Bindings
171
172         bind_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:binding"))
173         bind_el.setAttribute("name", method + "_binding")
174         bind_el.setAttribute("type", "tns:" + method + "_port")
175         
176         soap_bind = bind_el.appendChild(wsdl.createElement("soap:binding"))
177         soap_bind.setAttribute("style", "rpc")
178         soap_bind.setAttribute("transport","http://schemas.xmlsoap.org/soap/http")
179
180         
181         wsdl_op = bind_el.appendChild(wsdl.createElement("wsdl:operation"))
182         wsdl_op.setAttribute("name", method)
183         wsdl_op.appendChild(wsdl.createElement("soap:operation")).setAttribute("soapAction",
184                 "urn:" + method)
185
186         
187         wsdl_input = wsdl_op.appendChild(wsdl.createElement("wsdl:input"))
188         input_soap_body = wsdl_input.appendChild(wsdl.createElement("soap:body"))
189         input_soap_body.setAttribute("use", "encoded")
190         input_soap_body.setAttribute("namespace", "urn:" + method)
191         input_soap_body.setAttribute("encodingStyle","http://schemas.xmlsoap.org/soap/encoding/")
192
193         
194         wsdl_output = wsdl_op.appendChild(wsdl.createElement("wsdl:output"))
195         output_soap_body = wsdl_output.appendChild(wsdl.createElement("soap:body"))
196         output_soap_body.setAttribute("use", "encoded")
197         output_soap_body.setAttribute("namespace", "urn:" + method)
198         output_soap_body.setAttribute("encodingStyle","http://schemas.xmlsoap.org/soap/encoding/")
199         
200
201 def add_wsdl_service(wsdl):
202     for service in services.keys():
203         service_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:service"))
204         service_el.setAttribute("name", service)
205
206         for method in services[service]:
207             name=method
208             servport_el = service_el.appendChild(wsdl.createElement("wsdl:port"))
209             servport_el.setAttribute("name", name + "_port")
210             servport_el.setAttribute("binding", "tns:" + name + "_binding")
211
212             soapaddress = servport_el.appendChild(wsdl.createElement("soap:address"))
213             soapaddress.setAttribute("location", "%s/%s" % (globals.plc_ns,service))
214
215
216 def get_wsdl_definitions():
217     wsdl_text_header = """
218         <wsdl:definitions
219         name="auto_generated"
220         targetNamespace="%s"
221         xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
222         xmlns:tns="xmlns:%s"
223         xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
224         xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
225         """ % (globals.plc_ns,globals.plc_ns)
226         
227     wsdl = xml.dom.minidom.parseString(wsdl_text_header)
228     
229     return wsdl
230     
231
232 types = get_wsdl_definitions()
233 types.firstChild.appendChild(types.createElement("wsdl:types"))
234 wsdl = get_wsdl_definitions()
235 add_wsdl_ports_and_bindings(wsdl)
236 wsdl_types = wsdl.importNode(types.firstChild.firstChild, True)
237 wsdl.firstChild.appendChild(wsdl_types)
238 add_wsdl_service(wsdl)
239
240 xml.dom.ext.PrettyPrint(wsdl)