(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")
165         inp_el.setAttribute("message","tns:" + method + "_in")
166         inp_el.setAttribute("name",method+"_request")
167         op_el.appendChild(inp_el)
168         out_el = wsdl.createElement("wsdl:output")
169         out_el.setAttribute("message","tns:" + method + "_out")
170         out_el.setAttribute("name",method+"_response")
171         op_el.appendChild(out_el)
172
173         # Bindings
174
175         bind_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:binding"))
176         bind_el.setAttribute("name", method + "_binding")
177         bind_el.setAttribute("type", "tns:" + method + "_port")
178         
179         soap_bind = bind_el.appendChild(wsdl.createElement("soap:binding"))
180         soap_bind.setAttribute("style", "rpc")
181         soap_bind.setAttribute("transport","http://schemas.xmlsoap.org/soap/http")
182
183         
184         wsdl_op = bind_el.appendChild(wsdl.createElement("wsdl:operation"))
185         wsdl_op.setAttribute("name", method)
186         wsdl_op.appendChild(wsdl.createElement("soap:operation")).setAttribute("soapAction",
187                 "urn:" + method)
188
189         
190         wsdl_input = wsdl_op.appendChild(wsdl.createElement("wsdl:input"))
191         input_soap_body = wsdl_input.appendChild(wsdl.createElement("soap:body"))
192         input_soap_body.setAttribute("use", "encoded")
193         input_soap_body.setAttribute("namespace", "urn:" + method)
194         input_soap_body.setAttribute("encodingStyle","http://schemas.xmlsoap.org/soap/encoding/")
195
196         
197         wsdl_output = wsdl_op.appendChild(wsdl.createElement("wsdl:output"))
198         output_soap_body = wsdl_output.appendChild(wsdl.createElement("soap:body"))
199         output_soap_body.setAttribute("use", "encoded")
200         output_soap_body.setAttribute("namespace", "urn:" + method)
201         output_soap_body.setAttribute("encodingStyle","http://schemas.xmlsoap.org/soap/encoding/")
202         
203
204 def add_wsdl_service(wsdl):
205     for service in services.keys():
206         service_el = wsdl.firstChild.appendChild(wsdl.createElement("wsdl:service"))
207         service_el.setAttribute("name", service)
208
209         for method in services[service]:
210             name=method
211             servport_el = service_el.appendChild(wsdl.createElement("wsdl:port"))
212             servport_el.setAttribute("name", name + "_port")
213             servport_el.setAttribute("binding", "tns:" + name + "_binding")
214
215             soapaddress = servport_el.appendChild(wsdl.createElement("soap:address"))
216             soapaddress.setAttribute("location", "%s/%s" % (globals.plc_ns,service))
217
218
219 def get_wsdl_definitions():
220     wsdl_text_header = """
221         <wsdl:definitions
222         name="auto_generated"
223         targetNamespace="%s"
224         xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
225         xmlns:tns="xmlns:%s"
226         xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
227         xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
228         """ % (globals.plc_ns,globals.plc_ns)
229         
230     wsdl = xml.dom.minidom.parseString(wsdl_text_header)
231     
232     return wsdl
233     
234
235 types = get_wsdl_definitions()
236 types.firstChild.appendChild(types.createElement("wsdl:types"))
237 wsdl = get_wsdl_definitions()
238 add_wsdl_ports_and_bindings(wsdl)
239 wsdl_types = wsdl.importNode(types.firstChild.firstChild, True)
240 wsdl.firstChild.appendChild(wsdl_types)
241 add_wsdl_service(wsdl)
242
243 xml.dom.ext.PrettyPrint(wsdl)