# encoding: UTF-8 require 'builder' #noinspection RubyArgCount,RubyResolve,RubyLiteralArrayInspection module Shapewear::WSDL # reference: http://www.w3.org/TR/wsdl def to_wsdl xm = Builder::XmlMarkup.new xm.instruct! xm.definitions :name => self.name, 'targetNamespace' => namespaces['tns'], 'xmlns' => namespaces['wsdl'], 'xmlns:soap' => namespaces['soap'], 'xmlns:soap12' => namespaces['soap12'], 'xmlns:xsd' => namespaces['xsd'], 'xmlns:tns' => namespaces['tns'] do |xdef| xdef.types do |xtypes| xtypes.schema 'xmlns' => namespaces['xsd'], :elementFormDefault => 'qualified', :targetNamespace => namespaces['tns'] do |xschema| # define elements for each defined method operations.each do |m, op_opts| build_type_elements_for_method(m, op_opts, xschema) end end end operations.each do |_, op_opts| xdef.message :name => "#{op_opts[:public_name]}SoapIn" do |xmsg| xmsg.part :name => :parameters, :element => "tns:#{op_opts[:public_name]}" end xdef.message :name => "#{op_opts[:public_name]}SoapOut" do |xmsg| xmsg.part :name => :parameters, :element => "tns:#{op_opts[:public_name]}Response" end end xdef.portType :name => "#{options[:service_name]}Soap" do |xpt| operations.each do |_, op_opts| xpt.operation :name => op_opts[:public_name] do |xop| xop.input :message => "tns:#{op_opts[:public_name]}SoapIn" xop.output :message => "tns:#{op_opts[:public_name]}SoapOut" end end end # bindings for soap 1.1 and 1.2 ['', '12'].each do |sv| xdef.binding :name => "#{options[:service_name]}Soap#{sv}", :type => "tns:#{options[:service_name]}Soap" do |xbind| xbind.tag! "soap#{sv}:binding", :transport => 'http://schemas.xmlsoap.org/soap/http' operations.each do |_, op_opts| xbind.operation :name => op_opts[:public_name] do |xop| doc = op_opts[:documentation] rescue nil xop.documentation doc unless doc.nil? xop.tag! "soap#{sv}:operation", :soapAction => "#{namespaces['tns']}/#{op_opts[:public_name]}", :style => 'document' xop.input { |xin| xin.tag! "soap#{sv}:body", :use => 'literal' } xop.output { |xout| xout.tag! "soap#{sv}:body", :use => 'literal' } end end end end # service definition for soap 1.1 and 1.2 xdef.service :name => "#{options[:service_name]}" do |xsrv| xsrv.documentation "WSDL auto-generated by shapewear." ['', '12'].each do |sv| xsrv.port :name => "#{options[:service_name]}Soap#{sv}", :binding => "tns:#{options[:service_name]}Soap#{sv}" do |xport| xport.tag! "soap#{sv}:address", :location => options[:endpoint_url] end end end end end def build_type_elements_for_method(m, op_options, xschema) # element for method arguments um = instance_method(m) xschema.element :name => "#{op_options[:public_name]}" do |xreq| xreq.complexType do |xct| xct.sequence do |xseq| params = op_options[:parameters] rescue nil if params.nil? if um.respond_to?(:parameters) # with Ruby 1.9, we can create the parameters with the correct names params = um.parameters.select { |p| p.first == :in }.map { |p| [p.first, Object] } else params = (0..um.arity).map { |i| ["arg#{i}", Object] } end end params.each do |p| t = p.last param_name = p.first param_name = param_name.camelize_if_symbol(false) if t.nil? xseq.element :name => param_name, :minOccurs => 0, :maxOccurs => 1, :type => 'xsd:any' elsif t.is_a?(Class) xseq.element :name => param_name, :minOccurs => 0, :maxOccurs => 1, :type => to_xsd_type(t) elsif t.is_a?(Hash) xseq.complexType do |xct2| xct2.sequence do |xseq2| t.each do |name, type| xseq2.element :name => name, :minOccurs => 0, :maxOccurs => 1, :type => to_xsd_type(type) end end end else raise "Could not interpret #{t.inspect} as a return type definition" end end end end end # element for method result ret = op_options[:returns] rescue nil xschema.element :name => "#{op_options[:public_name]}Response" do |xreq| xreq.complexType do |xct| xct.sequence do |xseq| xseq.element :name => "#{op_options[:public_name]}Result", :minOccurs => 0, :maxOccurs => 1, :type => case ret when NilClass then 'xsd:any' when Class then to_xsd_type(ret) when Hash then "tns:#{op_options[:public_name]}Struct" else raise "Could not interpret #{ret.inspect} as a return type definition" end end end end if ret.is_a?(Hash) xschema.complexType :name => "#{op_options[:public_name]}Struct" do |xctr| xctr.sequence do |xseqr| ret.each do |name, type| name = name.camelize_if_symbol xseqr.element :name => name, :minOccurs => 0, :maxOccurs => 1, :type => to_xsd_type(type) end end end end end # @param t [Class] def to_xsd_type(t) return 'xsd:string' if t == String return 'xsd:integer' if t == Fixnum return 'xsd:dateTime' if t == DateTime return 'xsd:any' if t.nil? || t == Object raise "Could not convert type #{t} to a valid XSD type" end end