Welcome to the "trac"-ing site of soap4r!
[soap4r] [httpclient] [openpgp4u] [pkcs1] [logger] [csv] [vtr]

root/branches/1_5/lib/wsdl/soap/methodDefCreator.rb

Revision 2001, 7.6 kB (checked in by nahi, 1 year ago)
  • wsdl2ruby.rb did not generate proper definitions for overloaded method in WSDL. closes #446.
  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1 # WSDL4R - Creating driver code from WSDL.
2 # Copyright (C) 2000-2007  NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
4 # This program is copyrighted free software by NAKAMURA, Hiroshi.  You can
5 # redistribute it and/or modify it under the same terms of Ruby's license;
6 # either the dual license version in 2003, or any later version.
7
8
9 require 'wsdl/info'
10 require 'wsdl/soap/classDefCreatorSupport'
11 require 'soap/rpc/element'
12
13
14 module WSDL
15 module SOAP
16
17
18 class MethodDefCreator
19   include ClassDefCreatorSupport
20
21   attr_reader :definitions
22   # TODO: should not export this kind of stateful information.
23   # will be rewwritten in 1.6.1
24   attr_reader :assigned_method
25
26   def initialize(definitions, name_creator, modulepath, defined_const)
27     @definitions = definitions
28     @name_creator = name_creator
29     @modulepath = modulepath
30     @simpletypes = @definitions.collect_simpletypes
31     @complextypes = @definitions.collect_complextypes
32     @elements = @definitions.collect_elements
33     @types = []
34     @encoded = false
35     @literal = false
36     @defined_const = defined_const
37     @assigned_method = {}
38   end
39
40   def dump(name)
41     @types.clear
42     @encoded = false
43     @literal = false
44     methoddef = ""
45     porttype = @definitions.porttype(name)
46     binding = porttype.find_binding
47     if binding
48       binding.operations.each do |op_bind|
49         next unless op_bind # no binding is defined
50         next unless op_bind.soapoperation # not a SOAP operation binding
51         op = op_bind.find_operation
52         methoddef << ",\n" unless methoddef.empty?
53         methoddef << dump_method(op, op_bind).chomp
54       end
55     end
56     result = {
57       :methoddef => methoddef,
58       :types => @types,
59       :encoded => @encoded,
60       :literal => @literal
61     }
62     result
63   end
64
65   def collect_rpcparameter(operation)
66     result = operation.inputparts.collect { |part|
67       collect_type(part.type)
68       param_set(::SOAP::RPC::SOAPMethod::IN, part.name, rpcdefinedtype(part))
69     }
70     outparts = operation.outputparts
71     if outparts.size > 0
72       retval = outparts[0]
73       collect_type(retval.type)
74       result << param_set(::SOAP::RPC::SOAPMethod::RETVAL, retval.name,
75         rpcdefinedtype(retval))
76       cdr(outparts).each { |part|
77         collect_type(part.type)
78         result << param_set(::SOAP::RPC::SOAPMethod::OUT, part.name,
79           rpcdefinedtype(part))
80       }
81     end
82     result
83   end
84
85   def collect_documentparameter(operation)
86     param = []
87     operation.inputparts.each do |input|
88       param << param_set(::SOAP::RPC::SOAPMethod::IN, input.name,
89         documentdefinedtype(input))
90     end
91     operation.outputparts.each do |output|
92       param << param_set(::SOAP::RPC::SOAPMethod::OUT, output.name,
93         documentdefinedtype(output))
94     end
95     param
96   end
97
98 private
99
100   def dump_method(operation, op_bind)
101     op_faults = {}
102     op_bind.fault.each do |fault|
103       op_fault = {}
104       soapfault = fault.soapfault
105       next if soapfault.nil?
106       faultclass = mapped_class_name(fault.name, @modulepath)
107       op_fault[:ns] = fault.name.namespace
108       op_fault[:name] = fault.name.name
109       op_fault[:namespace] = soapfault.namespace
110       op_fault[:use] = soapfault.use || "literal"
111       op_fault[:encodingstyle] = soapfault.encodingstyle || "document"
112       op_faults[faultclass] = op_fault
113     end
114     op_faults_str = op_faults.inspect
115     name = assign_method_name(op_bind)
116     style = op_bind.soapoperation_style
117     inputuse = op_bind.soapbody_use_input
118     outputuse = op_bind.soapbody_use_output
119     if style == :rpc
120       qname = op_bind.soapoperation_name
121       paramstr = param2str(collect_rpcparameter(operation))
122     else
123       qname = nil
124       paramstr = param2str(collect_documentparameter(operation))
125     end
126     if paramstr.empty?
127       paramstr = '[]'
128     else
129       paramstr = "[ " << paramstr.split(/\r?\n/).join("\n    ") << " ]"
130     end
131     definitions = <<__EOD__
132 #{ndq(op_bind.soapaction)},
133   #{dq(name)},
134   #{paramstr},
135   { :request_style =>  #{nsym(style)}, :request_use =>  #{nsym(inputuse)},
136     :response_style => #{nsym(style)}, :response_use => #{nsym(outputuse)},
137     :faults => #{op_faults_str} }
138 __EOD__
139     if inputuse == :encoded or outputuse == :encoded
140       @encoded = true
141     end
142     if inputuse == :literal or outputuse == :literal
143       @literal = true
144     end
145     if style == :rpc
146       assign_const(qname.namespace, 'Ns')
147       return <<__EOD__
148 [ #{dqname(qname)},
149   #{definitions}]
150 __EOD__
151     else
152       return <<__EOD__
153 [ #{definitions}]
154 __EOD__
155     end
156   end
157
158   def assign_method_name(op_bind)
159     method_name = safemethodname(op_bind.name)
160     i = 1 # starts from _2
161     while @assigned_method.value?(method_name)
162       i += 1
163       method_name = safemethodname("#{op_bind.name}_#{i}")
164     end
165     @assigned_method[op_bind.boundid] = method_name
166     method_name
167   end
168
169   def rpcdefinedtype(part)
170     if mapped = basetype_mapped_class(part.type)
171       ['::' + mapped.name]
172     elsif definedtype = @simpletypes[part.type]
173       [nil, definedtype.name.namespace, definedtype.name.name]
174     elsif definedtype = @elements[part.element]
175       [nil, part.element.namespace, part.element.name]
176     elsif definedtype = @complextypes[part.type]
177       case definedtype.compoundtype
178       when :TYPE_STRUCT, :TYPE_EMPTY, :TYPE_ARRAY, :TYPE_SIMPLE
179         type = mapped_class_name(part.type, @modulepath)
180         [type, part.type.namespace, part.type.name]
181       when :TYPE_MAP
182         [Hash.name, part.type.namespace, part.type.name]
183       else
184         raise NotImplementedError.new("must not reach here: #{definedtype.compoundtype}")
185       end
186     elsif part.type == XSD::AnyTypeName
187       [nil]
188     else
189       raise RuntimeError.new("part: #{part.name} cannot be resolved")
190     end
191   end
192
193   def documentdefinedtype(part)
194     if mapped = basetype_mapped_class(part.type)
195       ['::' + mapped.name, nil, part.name]
196     elsif definedtype = @simpletypes[part.type]
197       if definedtype.base
198         ['::' + basetype_mapped_class(definedtype.base).name, nil, part.name]
199       else
200         raise RuntimeError.new("unsupported simpleType: #{definedtype}")
201       end
202     elsif definedtype = @elements[part.element]
203       ['::SOAP::SOAPElement', part.element.namespace, part.element.name]
204     elsif definedtype = @complextypes[part.type]
205       ['::SOAP::SOAPElement', part.type.namespace, part.type.name]
206     else
207       raise RuntimeError.new("part: #{part.name} cannot be resolved")
208     end
209   end
210
211   def param_set(io_type, name, type, ele = nil)
212     [io_type, name, type, ele]
213   end
214
215   def collect_type(type)
216     # ignore inline type definition.
217     return if type.nil?
218     return if @types.include?(type)
219     @types << type
220     return unless @complextypes[type]
221     collect_elements_type(@complextypes[type].elements)
222   end
223
224   def collect_elements_type(elements)
225     elements.each do |element|
226       case element
227       when WSDL::XMLSchema::Any
228         # nothing to do
229       when WSDL::XMLSchema::Element
230         collect_type(element.type)
231       when WSDL::XMLSchema::Sequence, WSDL::XMLSchema::Choice
232         collect_elements_type(element.elements)
233       else
234         raise RuntimeError.new("unknown type: #{element}")
235       end
236     end
237   end
238
239   def param2str(params)
240     params.collect { |param|
241       io, name, type, ele = param
242       unless ele.nil?
243         "[#{dq(io)}, #{dq(name)}, #{type2str(type)}, #{ele2str(ele)}]"
244       else
245         "[#{dq(io)}, #{dq(name)}, #{type2str(type)}]"
246       end
247     }.join(",\n")
248   end
249
250   def type2str(type)
251     if type.size == 1
252       "[#{ndq(type[0])}]"
253     else
254       "[#{ndq(type[0])}, #{ndq(type[1])}, #{dq(type[2])}]"
255     end
256   end
257
258   def ele2str(ele)
259     qualified = ele
260     if qualified
261       "true"
262     else
263       "false"
264     end
265   end
266
267   def cdr(ary)
268     result = ary.dup
269     result.shift
270     result
271   end
272 end
273
274
275 end
276 end
Note: See TracBrowser for help on using the browser.