diff options
author | nahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2005-05-22 13:03:38 +0000 |
---|---|---|
committer | nahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2005-05-22 13:03:38 +0000 |
commit | eb3f829be932514064a983eb98fa7f840137f985 (patch) | |
tree | c17440206af25b52f47b1c391f818e126a994d0a /lib/wsdl/soap | |
parent | 7aea792d3bdf42c349170e710953d7de29de57ab (diff) | |
download | ruby-eb3f829be932514064a983eb98fa7f840137f985.tar.gz |
* lib/{soap,wsdl,xsd}, test/{soap,wsdl,xsd}: imported soap4r/1.5.4.
== SOAP client and server ==
=== for both client side and server side ===
* improved document/literal service support.
style(rpc,document)/use(encoding, literal) combination are all
supported. for the detail about combination, see
test/soap/test_style.rb.
* let WSDLEncodedRegistry#soap2obj map SOAP/OM to Ruby according to
WSDL as well as obj2soap. closes #70.
* let SOAP::Mapping::Object handle XML attribute for doc/lit service.
you can set/get XML attribute via accessor methods which as a name
'xmlattr_' prefixed (<foo name="bar"/> -> Foo#xmlattr_name).
=== client side ===
* WSDLDriver capitalized name operation bug fixed. from
1.5.3-ruby1.8.2, operation which has capitalized name (such as
KeywordSearchRequest in AWS) is defined as a method having
uncapitalized name. (converted with GenSupport.safemethodname
to handle operation name 'foo-bar'). it introduced serious
incompatibility; in the past, it was defined as a capitalized.
define capitalized method as well under that circumstance.
* added new factory interface 'WSDLDriverFactory#create_rpc_driver'
to create RPC::Driver, not WSDLDriver (RPC::Driver and WSDLDriver
are merged). 'WSDLDriverFactory#create_driver' still creates
WSDLDriver for compatibility but it warns that the method is
deprecated. please use create_rpc_driver instead of create_driver.
* allow to use an URI object as an endpoint_url even with net/http,
not http-access2.
=== server side ===
* added mod_ruby support to SOAP::CGIStub. rename a CGI script
server.cgi to server.rb and let mod_ruby's RubyHandler handles the
script. CGIStub detects if it's running under mod_ruby environment
or not.
* added fcgi support to SOAP::CGIStub. see the sample at
sample/soap/calc/server.fcgi. (almost same as server.cgi but has
fcgi handler at the bottom.)
* allow to return a SOAPFault object to respond customized SOAP fault.
* added the interface 'generate_explicit_type' for server side
(CGIStub, HTTPServer). call 'self.generate_explicit_type = true'
if you want to return simplified XML even if it's rpc/encoded
service.
== WSDL ==
=== WSDL definition ===
* improved XML Schema support such as extension, restriction,
simpleType, complexType + simpleContent, ref, length, import,
include.
* reduced "unknown element/attribute" warnings (warn only 1 time for
each QName).
* importing XSD file at schemaLocation with xsd:import.
=== code generation from WSDL ===
* generator crashed when there's '-' in defined element/attribute
name.
* added ApacheMap WSDL definition.
* sample/{soap,wsdl}: removed.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8500 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/wsdl/soap')
-rw-r--r-- | lib/wsdl/soap/cgiStubCreator.rb | 18 | ||||
-rw-r--r-- | lib/wsdl/soap/classDefCreator.rb | 226 | ||||
-rw-r--r-- | lib/wsdl/soap/classDefCreatorSupport.rb | 6 | ||||
-rw-r--r-- | lib/wsdl/soap/complexType.rb | 37 | ||||
-rw-r--r-- | lib/wsdl/soap/definitions.rb | 39 | ||||
-rw-r--r-- | lib/wsdl/soap/driverCreator.rb | 22 | ||||
-rw-r--r-- | lib/wsdl/soap/element.rb | 6 | ||||
-rw-r--r-- | lib/wsdl/soap/fault.rb | 4 | ||||
-rw-r--r-- | lib/wsdl/soap/header.rb | 13 | ||||
-rw-r--r-- | lib/wsdl/soap/mappingRegistryCreator.rb | 16 | ||||
-rw-r--r-- | lib/wsdl/soap/methodDefCreator.rb | 116 | ||||
-rw-r--r-- | lib/wsdl/soap/operation.rb | 6 | ||||
-rw-r--r-- | lib/wsdl/soap/servantSkeltonCreator.rb | 8 | ||||
-rw-r--r-- | lib/wsdl/soap/standaloneServerStubCreator.rb | 20 | ||||
-rw-r--r-- | lib/wsdl/soap/wsdl2ruby.rb | 176 |
15 files changed, 498 insertions, 215 deletions
diff --git a/lib/wsdl/soap/cgiStubCreator.rb b/lib/wsdl/soap/cgiStubCreator.rb index 68ecfaf0a4..0a76dc43a1 100644 --- a/lib/wsdl/soap/cgiStubCreator.rb +++ b/lib/wsdl/soap/cgiStubCreator.rb @@ -1,5 +1,5 @@ # WSDL4R - Creating CGI stub code from WSDL. -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -26,9 +26,7 @@ class CGIStubCreator end def dump(service_name) - STDERR.puts "!!! IMPORTANT !!!" - STDERR.puts "- CGI stub can only 1 port. Creating stub for the first port... Rests are ignored." - STDERR.puts "!!! IMPORTANT !!!" + warn("CGI stub can have only 1 port. Creating stub for the first port... Rests are ignored.") port = @definitions.service(service_name).ports[0] dump_porttype(port.porttype.name) end @@ -39,28 +37,28 @@ private class_name = create_class_name(name) methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) - c1 = ::XSD::CodeGen::ClassDef.new(class_name) + c1 = XSD::CodeGen::ClassDef.new(class_name) c1.def_require("soap/rpc/cgistub") c1.def_require("soap/mapping/registry") c1.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") c1.def_code(mr_creator.dump(types)) c1.def_code <<-EOD Methods = [ -#{ methoddef.gsub(/^/, " ") } +#{methoddef.gsub(/^/, " ")} ] EOD - c2 = ::XSD::CodeGen::ClassDef.new(class_name + "App", + c2 = XSD::CodeGen::ClassDef.new(class_name + "App", "::SOAP::RPC::CGIStub") c2.def_method("initialize", "*arg") do <<-EOD super(*arg) servant = #{class_name}.new #{class_name}::Methods.each do |name_as, name, param_def, soapaction, namespace, style| - qname = XSD::QName.new(namespace, name_as) if style == :document - @router.add_document_method(servant, qname, soapaction, name, param_def) + @router.add_document_operation(servant, soapaction, name, param_def) else - @router.add_rpc_method(servant, qname, soapaction, name, param_def) + qname = XSD::QName.new(namespace, name_as) + @router.add_rpc_operation(servant, qname, soapaction, name, param_def) end end self.mapping_registry = #{class_name}::MappingRegistry diff --git a/lib/wsdl/soap/classDefCreator.rb b/lib/wsdl/soap/classDefCreator.rb index 13f7802b72..deda4f131f 100644 --- a/lib/wsdl/soap/classDefCreator.rb +++ b/lib/wsdl/soap/classDefCreator.rb @@ -1,5 +1,5 @@ # WSDL4R - Creating class definition from WSDL -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -22,13 +22,16 @@ class ClassDefCreator @elements = definitions.collect_elements @simpletypes = definitions.collect_simpletypes @complextypes = definitions.collect_complextypes - @faulttypes = definitions.collect_faulttypes if definitions.respond_to?(:collect_faulttypes) + @faulttypes = nil + if definitions.respond_to?(:collect_faulttypes) + @faulttypes = definitions.collect_faulttypes + end end - def dump(class_name = nil) - result = '' - if class_name - result = dump_classdef(class_name) + def dump(type = nil) + result = "require 'xsd/qname'\n" + if type + result = dump_classdef(type.name, type) else str = dump_element unless str.empty? @@ -53,117 +56,129 @@ private def dump_element @elements.collect { |ele| - ele.local_complextype ? dump_classdef(ele) : '' - }.join("\n") + if ele.local_complextype + dump_classdef(ele.name, ele.local_complextype) + elsif ele.local_simpletype + dump_simpletypedef(ele.name, ele.local_simpletype) + else + nil + end + }.compact.join("\n") end def dump_simpletype @simpletypes.collect { |type| - dump_simpletypedef(type) - }.join("\n") + dump_simpletypedef(type.name, type) + }.compact.join("\n") end def dump_complextype @complextypes.collect { |type| case type.compoundtype - when :TYPE_STRUCT - dump_classdef(type) + when :TYPE_STRUCT, :TYPE_EMPTY + dump_classdef(type.name, type) when :TYPE_ARRAY dump_arraydef(type) when :TYPE_SIMPLE - STDERR.puts("not implemented: ToDo") + dump_simpleclassdef(type) + when :TYPE_MAP + # mapped as a general Hash + nil else raise RuntimeError.new( - "Unknown kind of complexContent: #{type.compoundtype}") + "unknown kind of complexContent: #{type.compoundtype}") end - }.join("\n") + }.compact.join("\n") end - def dump_simpletypedef(simpletype) - qname = simpletype.name - if simpletype.restriction.enumeration.empty? - STDERR.puts("#{qname}: simpleType which is not enum type not supported.") - return '' + def dump_simpletypedef(qname, simpletype) + if !simpletype.restriction or simpletype.restriction.enumeration.empty? + return nil end c = XSD::CodeGen::ModuleDef.new(create_class_name(qname)) - c.comment = "#{ qname.namespace }" + c.comment = "#{qname}" + const = {} simpletype.restriction.enumeration.each do |value| - c.def_const(safeconstname(value), value.dump) + constname = safeconstname(value) + const[constname] ||= 0 + if (const[constname] += 1) > 1 + constname += "_#{const[constname]}" + end + c.def_const(constname, ndq(value)) end c.dump end - def dump_classdef(type_or_element) + def dump_simpleclassdef(type_or_element) qname = type_or_element.name + base = create_class_name(type_or_element.simplecontent.base) + c = XSD::CodeGen::ClassDef.new(create_class_name(qname), base) + c.comment = "#{qname}" + c.dump + end + + def dump_classdef(qname, typedef) if @faulttypes and @faulttypes.index(qname) c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::StandardError') else c = XSD::CodeGen::ClassDef.new(create_class_name(qname)) end - c.comment = "#{ qname.namespace }" - c.def_classvar('schema_type', qname.name.dump) - c.def_classvar('schema_ns', qname.namespace.dump) - schema_attribute = [] + c.comment = "#{qname}" + c.def_classvar('schema_type', ndq(qname.name)) + c.def_classvar('schema_ns', ndq(qname.namespace)) schema_element = [] init_lines = '' params = [] - type_or_element.each_element do |element| - next unless element.name - name = element.name.name + typedef.each_element do |element| if element.type == XSD::AnyTypeName type = nil - elsif basetype = basetype_class(element.type) - type = basetype.name - else + elsif klass = element_basetype(element) + type = klass.name + elsif element.type type = create_class_name(element.type) + else + type = nil # means anyType. + # do we define a class for local complexType from it's name? + # type = create_class_name(element.name) + # <element> + # <complexType> + # <seq...> + # </complexType> + # </element> end + name = name_element(element).name attrname = safemethodname?(name) ? name : safemethodname(name) varname = safevarname(name) c.def_attr(attrname, true, varname) - init_lines << "@#{ varname } = #{ varname }\n" + init_lines << "@#{varname} = #{varname}\n" if element.map_as_array? - params << "#{ varname } = []" - type << '[]' + params << "#{varname} = []" + type << '[]' if type else - params << "#{ varname } = nil" + params << "#{varname} = nil" end - schema_element << [name, type] + eleqname = (varname == name) ? nil : element.name + schema_element << [varname, eleqname, type] end - unless type_or_element.attributes.empty? - type_or_element.attributes.each do |attribute| - name = attribute.name.name - if basetype = basetype_class(attribute.type) - type = basetype_class(attribute.type).name - else - type = nil - end - varname = safevarname('attr_' + name) - c.def_method(varname) do <<-__EOD__ - @__soap_attribute[#{name.dump}] - __EOD__ - end - c.def_method(varname + '=', 'value') do <<-__EOD__ - @__soap_attribute[#{name.dump}] = value - __EOD__ - end - schema_attribute << [name, type] - end - init_lines << "@__soap_attribute = {}\n" + unless typedef.attributes.empty? + define_attribute(c, typedef.attributes) + init_lines << "@__xmlattr = {}\n" end - c.def_classvar('schema_attribute', - '{' + - schema_attribute.collect { |name, type| - name.dump + ' => ' + ndq(type) - }.join(', ') + - '}' - ) c.def_classvar('schema_element', - '{' + - schema_element.collect { |name, type| - name.dump + ' => ' + ndq(type) + '[' + + schema_element.collect { |varname, name, type| + '[' + + ( + if name + varname.dump + ', [' + ndq(type) + ', ' + dqname(name) + ']' + else + varname.dump + ', ' + ndq(type) + end + ) + + ']' }.join(', ') + - '}' + ']' ) c.def_method('initialize', *params) do init_lines @@ -171,20 +186,83 @@ private c.dump end + def element_basetype(ele) + if klass = basetype_class(ele.type) + klass + elsif ele.local_simpletype + basetype_class(ele.local_simpletype.base) + else + nil + end + end + + def attribute_basetype(attr) + if klass = basetype_class(attr.type) + klass + elsif attr.local_simpletype + basetype_class(attr.local_simpletype.base) + else + nil + end + end + def basetype_class(type) - if @simpletypes[type] - basetype_mapped_class(@simpletypes[type].base) + return nil if type.nil? + if simpletype = @simpletypes[type] + basetype_mapped_class(simpletype.base) else basetype_mapped_class(type) end end + def define_attribute(c, attributes) + schema_attribute = [] + attributes.each do |attribute| + name = name_attribute(attribute) + if klass = attribute_basetype(attribute) + type = klass.name + else + type = nil + end + methodname = safemethodname('xmlattr_' + name.name) + c.def_method(methodname) do <<-__EOD__ + (@__xmlattr ||= {})[#{dqname(name)}] + __EOD__ + end + c.def_method(methodname + '=', 'value') do <<-__EOD__ + (@__xmlattr ||= {})[#{dqname(name)}] = value + __EOD__ + end + schema_attribute << [name, type] + end + c.def_classvar('schema_attribute', + '{' + + schema_attribute.collect { |name, type| + dqname(name) + ' => ' + ndq(type) + }.join(', ') + + '}' + ) + end + + def name_element(element) + return element.name if element.name + return element.ref if element.ref + raise RuntimeError.new("cannot define name of #{element}") + end + + def name_attribute(attribute) + return attribute.name if attribute.name + return attribute.ref if attribute.ref + raise RuntimeError.new("cannot define name of #{attribute}") + end + def dump_arraydef(complextype) qname = complextype.name c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::Array') - c.comment = "#{ qname.namespace }" - c.def_classvar('schema_type', qname.name.dump) - c.def_classvar('schema_ns', qname.namespace.dump) + c.comment = "#{qname}" + type = complextype.child_type + c.def_classvar('schema_type', ndq(type.name)) + c.def_classvar('schema_ns', ndq(type.namespace)) c.dump end end diff --git a/lib/wsdl/soap/classDefCreatorSupport.rb b/lib/wsdl/soap/classDefCreatorSupport.rb index 706c00d4f6..8f335653c8 100644 --- a/lib/wsdl/soap/classDefCreatorSupport.rb +++ b/lib/wsdl/soap/classDefCreatorSupport.rb @@ -21,7 +21,7 @@ module ClassDefCreatorSupport def create_class_name(qname) if klass = basetype_mapped_class(qname) - ::SOAP::Mapping::DefaultRegistry.find_mapped_obj_class(klass.name) + ::SOAP::Mapping::DefaultRegistry.find_mapped_obj_class(klass).name else safeconstname(qname.name) end @@ -71,6 +71,10 @@ __EOD__ ':' + ele end + def dqname(qname) + qname.dump + end + private def dump_inout_type(param) diff --git a/lib/wsdl/soap/complexType.rb b/lib/wsdl/soap/complexType.rb index 1bed059f7e..bba50fd153 100644 --- a/lib/wsdl/soap/complexType.rb +++ b/lib/wsdl/soap/complexType.rb @@ -31,42 +31,44 @@ class ComplexType < Info else :TYPE_STRUCT end - elsif complexcontent and complexcontent.base == ::SOAP::ValueArrayName - :TYPE_ARRAY + elsif complexcontent + if complexcontent.base == ::SOAP::ValueArrayName + :TYPE_ARRAY + else + complexcontent.basetype.check_type + end elsif simplecontent :TYPE_SIMPLE elsif !attributes.empty? :TYPE_STRUCT - else - raise NotImplementedError.new("Unknown kind of complexType.") + else # empty complexType definition (seen in partner.wsdl of salesforce) + :TYPE_EMPTY end end def child_type(name = nil) - type = nil case compoundtype when :TYPE_STRUCT if ele = find_element(name) - type = ele.type + ele.type elsif ele = find_element_by_name(name.name) - type = ele.type + ele.type end when :TYPE_ARRAY - type = @contenttype ||= content_arytype + @contenttype ||= content_arytype when :TYPE_MAP item_ele = find_element_by_name("item") or raise RuntimeError.new("'item' element not found in Map definition.") content = item_ele.local_complextype or raise RuntimeError.new("No complexType definition for 'item'.") if ele = content.find_element(name) - type = ele.type + ele.type elsif ele = content.find_element_by_name(name.name) - type = ele.type + ele.type end else raise NotImplementedError.new("Unknown kind of complexType.") end - type end def child_defined_complextype(name) @@ -103,16 +105,21 @@ class ComplexType < Info return attribute.arytype end end - elsif content.elements.size == 1 and content.elements[0].maxoccurs != '1' + if check_array_content(complexcontent.content) + return complexcontent.content.elements[0].type + end + elsif check_array_content(content) return content.elements[0].type - else - raise RuntimeError.new("Assert: Unknown array definition.") end - nil + raise RuntimeError.new("Assert: Unknown array definition.") end private + def check_array_content(content) + content.elements.size == 1 and content.elements[0].maxoccurs != '1' + end + def content_arytype if arytype = find_arytype ns = arytype.namespace diff --git a/lib/wsdl/soap/definitions.rb b/lib/wsdl/soap/definitions.rb index fced82bdec..b014d5af6b 100644 --- a/lib/wsdl/soap/definitions.rb +++ b/lib/wsdl/soap/definitions.rb @@ -1,5 +1,5 @@ # WSDL4R - WSDL additional definitions for SOAP. -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -77,13 +77,13 @@ class Definitions < Info def collect_faulttypes result = [] - collect_fault_messages.each do |m| - parts = message(m).parts - if parts.size != 1 - raise RuntimeError.new("Expecting fault message to have only 1 part.") + collect_fault_messages.each do |name| + faultparts = message(name).parts + if faultparts.size != 1 + raise RuntimeError.new("expecting fault message to have only 1 part") end - if result.index(parts[0].type).nil? - result << parts[0].type + if result.index(faultparts[0].type).nil? + result << faultparts[0].type end end result @@ -111,13 +111,13 @@ private if op_bind_rpc?(op_bind) operation = op_bind.find_operation if op_bind.input - type = XMLSchema::ComplexType.new(operation_input_name(operation)) + type = XMLSchema::ComplexType.new(op_bind.soapoperation_name) message = messages[operation.input.message] type.sequence_elements = elements_from_message(message) types << type end if op_bind.output - type = XMLSchema::ComplexType.new(operation_output_name(operation)) + type = XMLSchema::ComplexType.new(operation.outputname) message = messages[operation.output.message] type.sequence_elements = elements_from_message(message) types << type @@ -127,23 +127,20 @@ private types end - def operation_input_name(operation) - operation.input.name || operation.name - end - - def operation_output_name(operation) - operation.output.name || - XSD::QName.new(operation.name.namespace, operation.name.name + "Response") - end - def op_bind_rpc?(op_bind) - op_bind.soapoperation and op_bind.soapoperation.operation_style == :rpc + op_bind.soapoperation_style == :rpc end def elements_from_message(message) message.parts.collect { |part| - qname = XSD::QName.new(nil, part.name) - XMLSchema::Element.new(qname, part.type) + if part.element + collect_elements[part.element] + elsif part.name.nil? or part.type.nil? + raise RuntimeError.new("part of a message must be an element or typed") + else + qname = XSD::QName.new(nil, part.name) + XMLSchema::Element.new(qname, part.type) + end } end end diff --git a/lib/wsdl/soap/driverCreator.rb b/lib/wsdl/soap/driverCreator.rb index b752ee336d..dd504210f1 100644 --- a/lib/wsdl/soap/driverCreator.rb +++ b/lib/wsdl/soap/driverCreator.rb @@ -1,5 +1,5 @@ # WSDL4R - Creating driver code from WSDL. -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -46,16 +46,17 @@ private methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) binding = @definitions.bindings.find { |item| item.type == name } - addresses = @definitions.porttype(name).locations + return '' unless binding.soapbinding # not a SOAP binding + address = @definitions.porttype(name).locations[0] - c = ::XSD::CodeGen::ClassDef.new(class_name, "::SOAP::RPC::Driver") + c = XSD::CodeGen::ClassDef.new(class_name, "::SOAP::RPC::Driver") c.def_require("soap/rpc/driver") c.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") - c.def_const("DefaultEndpointUrl", addresses[0].dump) + c.def_const("DefaultEndpointUrl", ndq(address)) c.def_code(mr_creator.dump(types)) c.def_code <<-EOD Methods = [ -#{ methoddef.gsub(/^/, " ") } +#{methoddef.gsub(/^/, " ")} ] EOD c.def_method("initialize", "endpoint_url = nil") do @@ -69,14 +70,19 @@ Methods = [ c.def_privatemethod("init_methods") do <<-EOD Methods.each do |name_as, name, params, soapaction, namespace, style| - qname = ::XSD::QName.new(namespace, name_as) + qname = XSD::QName.new(namespace, name_as) if style == :document - @proxy.add_document_method(qname, soapaction, name, params) - add_document_method_interface(name, name_as) + @proxy.add_document_method(soapaction, name, params) + add_document_method_interface(name, params) else @proxy.add_rpc_method(qname, soapaction, name, params) add_rpc_method_interface(name, params) end + if name_as != name and name_as.capitalize == name.capitalize + ::SOAP::Mapping.define_singleton_method(self, name_as) do |*arg| + __send__(name, *arg) + end + end end EOD end diff --git a/lib/wsdl/soap/element.rb b/lib/wsdl/soap/element.rb index c39a00d25a..0fa6017c5b 100644 --- a/lib/wsdl/soap/element.rb +++ b/lib/wsdl/soap/element.rb @@ -21,12 +21,6 @@ class Element < Info def attributes @local_complextype.attributes end - - def each_element - @local_complextype.each_element do |element| - yield(element) - end - end end diff --git a/lib/wsdl/soap/fault.rb b/lib/wsdl/soap/fault.rb index 019c881f97..2862b659ab 100644 --- a/lib/wsdl/soap/fault.rb +++ b/lib/wsdl/soap/fault.rb @@ -27,6 +27,10 @@ class Fault < Info @namespace = nil end + def targetnamespace + parent.targetnamespace + end + def parse_element(element) nil end diff --git a/lib/wsdl/soap/header.rb b/lib/wsdl/soap/header.rb index 247531a76d..8d7c4e9d70 100644 --- a/lib/wsdl/soap/header.rb +++ b/lib/wsdl/soap/header.rb @@ -32,8 +32,12 @@ class Header < Info @headerfault = nil end + def targetnamespace + parent.targetnamespace + end + def find_message - root.message(@message) + root.message(@message) or raise RuntimeError.new("#{@message} not found") end def find_part @@ -42,7 +46,7 @@ class Header < Info return part end end - nil + raise RuntimeError.new("#{@part} not found") end def parse_element(element) @@ -59,7 +63,10 @@ class Header < Info def parse_attr(attr, value) case attr when MessageAttrName - @message = XSD::QName.new(targetnamespace, value.source) + if value.namespace.nil? + value = XSD::QName.new(targetnamespace, value.source) + end + @message = value when PartAttrName @part = value.source when UseAttrName diff --git a/lib/wsdl/soap/mappingRegistryCreator.rb b/lib/wsdl/soap/mappingRegistryCreator.rb index d3b28f47e0..8669339ce4 100644 --- a/lib/wsdl/soap/mappingRegistryCreator.rb +++ b/lib/wsdl/soap/mappingRegistryCreator.rb @@ -1,5 +1,5 @@ # WSDL4R - Creating MappingRegistry code from WSDL. -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -38,7 +38,7 @@ class MappingRegistryCreator end end end - end + end return map end @@ -51,8 +51,10 @@ private dump_struct_typemap(definedtype) when :TYPE_ARRAY dump_array_typemap(definedtype) + when :TYPE_MAP, :TYPE_EMPTY + nil else - raise NotImplementedError.new("Must not reach here.") + raise NotImplementedError.new("must not reach here") end end end @@ -61,10 +63,10 @@ private ele = definedtype.name return <<__EOD__ MappingRegistry.set( - #{ create_class_name(ele) }, + #{create_class_name(ele)}, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, - { :type => ::XSD::QName.new("#{ ele.namespace }", "#{ ele.name }") } + { :type => #{dqname(ele)} } ) __EOD__ end @@ -76,10 +78,10 @@ __EOD__ @types << type return <<__EOD__ MappingRegistry.set( - #{ create_class_name(ele) }, + #{create_class_name(ele)}, ::SOAP::SOAPArray, ::SOAP::Mapping::Registry::TypedArrayFactory, - { :type => ::XSD::QName.new("#{ type.namespace }", "#{ type.name }") } + { :type => #{dqname(type)} } ) __EOD__ end diff --git a/lib/wsdl/soap/methodDefCreator.rb b/lib/wsdl/soap/methodDefCreator.rb index 59b8ee4253..f256b42451 100644 --- a/lib/wsdl/soap/methodDefCreator.rb +++ b/lib/wsdl/soap/methodDefCreator.rb @@ -1,5 +1,5 @@ # WSDL4R - Creating driver code from WSDL. -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -8,6 +8,7 @@ require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' +require 'soap/rpc/element' module WSDL @@ -24,75 +25,80 @@ class MethodDefCreator @simpletypes = @definitions.collect_simpletypes @complextypes = @definitions.collect_complextypes @elements = @definitions.collect_elements - @types = nil + @types = [] end def dump(porttype) - @types = [] + @types.clear result = "" operations = @definitions.porttype(porttype).operations binding = @definitions.porttype_binding(porttype) operations.each do |operation| op_bind = binding.operations[operation.name] + next unless op_bind # no binding is defined + next unless op_bind.soapoperation # not a SOAP operation binding result << ",\n" unless result.empty? result << dump_method(operation, op_bind).chomp end return result, @types end -private - - def dump_method(operation, binding) - name = safemethodname(operation.name.name) - name_as = operation.name.name - stylestr = binding.soapoperation.operation_style.id2name - if binding.soapoperation.operation_style == :rpc - soapaction = binding.soapoperation.soapaction - namespace = binding.input.soapbody.namespace - params = collect_rpcparameter(operation) - else - soapaction = namespace = nil - params = collect_documentparameter(operation) - end - paramstr = param2str(params) - if paramstr.empty? - paramstr = '[]' - else - paramstr = "[\n" << paramstr.gsub(/^/, ' ') << "\n ]" - end - return <<__EOD__ -[#{ dq(name_as) }, #{ dq(name) }, - #{ paramstr }, - #{ ndq(soapaction) }, #{ ndq(namespace) }, #{ sym(stylestr) } -] -__EOD__ - end - def collect_rpcparameter(operation) result = operation.inputparts.collect { |part| collect_type(part.type) - param_set('in', rpcdefinedtype(part), part.name) + param_set(::SOAP::RPC::SOAPMethod::IN, rpcdefinedtype(part), part.name) } outparts = operation.outputparts if outparts.size > 0 retval = outparts[0] collect_type(retval.type) - result << param_set('retval', rpcdefinedtype(retval), retval.name) + result << param_set(::SOAP::RPC::SOAPMethod::RETVAL, + rpcdefinedtype(retval), retval.name) cdr(outparts).each { |part| collect_type(part.type) - result << param_set('out', rpcdefinedtype(part), part.name) + result << param_set(::SOAP::RPC::SOAPMethod::OUT, rpcdefinedtype(part), + part.name) } end result end def collect_documentparameter(operation) - input = operation.inputparts[0] - output = operation.outputparts[0] - [ - param_set('input', documentdefinedtype(input), input.name), - param_set('output', documentdefinedtype(output), output.name) - ] + param = [] + operation.inputparts.each do |input| + param << param_set(::SOAP::RPC::SOAPMethod::IN, + documentdefinedtype(input), input.name) + end + operation.outputparts.each do |output| + param << param_set(::SOAP::RPC::SOAPMethod::OUT, + documentdefinedtype(output), output.name) + end + param + end + +private + + def dump_method(operation, binding) + name = safemethodname(operation.name.name) + name_as = operation.name.name + style = binding.soapoperation_style + namespace = binding.input.soapbody.namespace + if style == :rpc + paramstr = param2str(collect_rpcparameter(operation)) + else + paramstr = param2str(collect_documentparameter(operation)) + end + if paramstr.empty? + paramstr = '[]' + else + paramstr = "[\n" << paramstr.gsub(/^/, ' ') << "\n ]" + end + return <<__EOD__ +[#{dq(name_as)}, #{dq(name)}, + #{paramstr}, + #{ndq(binding.soapaction)}, #{ndq(namespace)}, #{sym(style.id2name)} +] +__EOD__ end def rpcdefinedtype(part) @@ -101,33 +107,40 @@ __EOD__ elsif definedtype = @simpletypes[part.type] ['::' + basetype_mapped_class(definedtype.base).name] elsif definedtype = @elements[part.element] - ['::SOAP::SOAPStruct', part.element.namespace, part.element.name] + #['::SOAP::SOAPStruct', part.element.namespace, part.element.name] + ['nil', part.element.namespace, part.element.name] elsif definedtype = @complextypes[part.type] case definedtype.compoundtype - when :TYPE_STRUCT - ['::SOAP::SOAPStruct', part.type.namespace, part.type.name] + when :TYPE_STRUCT, :TYPE_EMPTY # ToDo: empty should be treated as void. + type = create_class_name(part.type) + [type, part.type.namespace, part.type.name] + when :TYPE_MAP + [Hash.name, part.type.namespace, part.type.name] when :TYPE_ARRAY arytype = definedtype.find_arytype || XSD::AnyTypeName ns = arytype.namespace name = arytype.name.sub(/\[(?:,)*\]$/, '') - ['::SOAP::SOAPArray', ns, name] + type = create_class_name(XSD::QName.new(ns, name)) + [type + '[]', ns, name] else - raise NotImplementedError.new("Must not reach here.") + raise NotImplementedError.new("must not reach here") end else - raise RuntimeError.new("Part: #{part.name} cannot be resolved.") + raise RuntimeError.new("part: #{part.name} cannot be resolved") end end def documentdefinedtype(part) - if definedtype = @simpletypes[part.type] + if mapped = basetype_mapped_class(part.type) + ['::' + mapped.name, nil, part.name] + elsif definedtype = @simpletypes[part.type] ['::' + basetype_mapped_class(definedtype.base).name, nil, part.name] elsif definedtype = @elements[part.element] ['::SOAP::SOAPElement', part.element.namespace, part.element.name] elsif definedtype = @complextypes[part.type] ['::SOAP::SOAPElement', part.type.namespace, part.type.name] else - raise RuntimeError.new("Part: #{part.name} cannot be resolved.") + raise RuntimeError.new("part: #{part.name} cannot be resolved") end end @@ -138,6 +151,7 @@ __EOD__ def collect_type(type) # ignore inline type definition. return if type.nil? + return if @types.include?(type) @types << type return unless @complextypes[type] @complextypes[type].each_element do |element| @@ -147,15 +161,15 @@ __EOD__ def param2str(params) params.collect { |param| - "[#{ dq(param[0]) }, #{ dq(param[2]) }, #{ type2str(param[1]) }]" + "[#{dq(param[0])}, #{dq(param[2])}, #{type2str(param[1])}]" }.join(",\n") end def type2str(type) if type.size == 1 - "[#{ type[0] }]" + "[#{dq(type[0])}]" else - "[#{ type[0] }, #{ ndq(type[1]) }, #{ dq(type[2]) }]" + "[#{dq(type[0])}, #{ndq(type[1])}, #{dq(type[2])}]" end end diff --git a/lib/wsdl/soap/operation.rb b/lib/wsdl/soap/operation.rb index 51bb2e9403..502d34a07d 100644 --- a/lib/wsdl/soap/operation.rb +++ b/lib/wsdl/soap/operation.rb @@ -101,8 +101,7 @@ private "EncodingStyle '#{ soapbody.encodingstyle }' not supported.") end if soapbody.namespace - op_name = op_name.dup - op_name.namespace = soapbody.namespace + op_name = XSD::QName.new(soapbody.namespace, op_name.name) end if soapbody.parts target = soapbody.parts.split(/\s+/) @@ -114,8 +113,7 @@ private end faultpart = nil - soapaction = parent.soapoperation.soapaction - OperationInfo.new(operation_style, op_name, optype_name, headerparts, bodyparts, faultpart, soapaction) + OperationInfo.new(operation_style, op_name, optype_name, headerparts, bodyparts, faultpart, parent.soapaction) end end diff --git a/lib/wsdl/soap/servantSkeltonCreator.rb b/lib/wsdl/soap/servantSkeltonCreator.rb index 12761ab5b4..88294ffed8 100644 --- a/lib/wsdl/soap/servantSkeltonCreator.rb +++ b/lib/wsdl/soap/servantSkeltonCreator.rb @@ -1,5 +1,5 @@ # WSDL4R - Creating servant skelton code from WSDL. -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -17,7 +17,7 @@ module SOAP class ServantSkeltonCreator include ClassDefCreatorSupport - include ::XSD::CodeGen::GenSupport + include XSD::CodeGen::GenSupport attr_reader :definitions @@ -42,7 +42,7 @@ private def dump_porttype(name) class_name = create_class_name(name) - c = ::XSD::CodeGen::ClassDef.new(class_name) + c = XSD::CodeGen::ClassDef.new(class_name) operations = @definitions.porttype(name).operations operations.each do |operation| name = safemethodname(operation.name.name) @@ -50,7 +50,7 @@ private params = input.find_message.parts.collect { |part| safevarname(part.name) } - m = ::XSD::CodeGen::MethodDef.new(name, params) do <<-EOD + m = XSD::CodeGen::MethodDef.new(name, params) do <<-EOD p [#{params.join(", ")}] raise NotImplementedError.new EOD diff --git a/lib/wsdl/soap/standaloneServerStubCreator.rb b/lib/wsdl/soap/standaloneServerStubCreator.rb index 779139a5f4..243ac12216 100644 --- a/lib/wsdl/soap/standaloneServerStubCreator.rb +++ b/lib/wsdl/soap/standaloneServerStubCreator.rb @@ -1,5 +1,5 @@ # WSDL4R - Creating standalone server stub code from WSDL. -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -26,10 +26,8 @@ class StandaloneServerStubCreator end def dump(service_name) - STDERR.puts "!!! IMPORTANT !!!" - STDERR.puts "- Standalone stub can have only 1 port for now. So creating stub for the first port and rests are ignored." - STDERR.puts "- Standalone server stub ignores port location defined in WSDL. Location is http://localhost:10080/ by default. Generated client from WSDL must be configured to point this endpoint by hand." - STDERR.puts "!!! IMPORTANT !!!" + warn("- Standalone stub can have only 1 port for now. So creating stub for the first port and rests are ignored.") + warn("- Standalone server stub ignores port location defined in WSDL. Location is http://localhost:10080/ by default. Generated client from WSDL must be configured to point this endpoint manually.") port = @definitions.service(service_name).ports[0] dump_porttype(port.porttype.name) end @@ -41,28 +39,28 @@ private methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) - c1 = ::XSD::CodeGen::ClassDef.new(class_name) + c1 = XSD::CodeGen::ClassDef.new(class_name) c1.def_require("soap/rpc/standaloneServer") c1.def_require("soap/mapping/registry") c1.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") c1.def_code(mr_creator.dump(types)) c1.def_code <<-EOD Methods = [ -#{ methoddef.gsub(/^/, " ") } +#{methoddef.gsub(/^/, " ")} ] EOD - c2 = ::XSD::CodeGen::ClassDef.new(class_name + "App", + c2 = XSD::CodeGen::ClassDef.new(class_name + "App", "::SOAP::RPC::StandaloneServer") c2.def_method("initialize", "*arg") do <<-EOD super(*arg) servant = #{class_name}.new #{class_name}::Methods.each do |name_as, name, param_def, soapaction, namespace, style| - qname = XSD::QName.new(namespace, name_as) if style == :document - @soaplet.app_scope_router.add_document_method(servant, qname, soapaction, name, param_def) + @router.add_document_operation(servant, soapaction, name, param_def) else - @soaplet.app_scope_router.add_rpc_method(servant, qname, soapaction, name, param_def) + qname = XSD::QName.new(namespace, name_as) + @router.add_rpc_operation(servant, qname, soapaction, name, param_def) end end self.mapping_registry = #{class_name}::MappingRegistry diff --git a/lib/wsdl/soap/wsdl2ruby.rb b/lib/wsdl/soap/wsdl2ruby.rb new file mode 100644 index 0000000000..16b05fb032 --- /dev/null +++ b/lib/wsdl/soap/wsdl2ruby.rb @@ -0,0 +1,176 @@ +# WSDL4R - WSDL to ruby mapping library. +# Copyright (C) 2002-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'logger' +require 'xsd/qname' +require 'wsdl/importer' +require 'wsdl/soap/classDefCreator' +require 'wsdl/soap/servantSkeltonCreator' +require 'wsdl/soap/driverCreator' +require 'wsdl/soap/clientSkeltonCreator' +require 'wsdl/soap/standaloneServerStubCreator' +require 'wsdl/soap/cgiStubCreator' + + +module WSDL +module SOAP + + +class WSDL2Ruby + attr_accessor :location + attr_reader :opt + attr_accessor :logger + attr_accessor :basedir + + def run + unless @location + raise RuntimeError, "WSDL location not given" + end + @wsdl = import(@location) + @name = @wsdl.name ? @wsdl.name.name : 'default' + create_file + end + +private + + def initialize + @location = nil + @opt = {} + @logger = Logger.new(STDERR) + @basedir = nil + @wsdl = nil + @name = nil + end + + def create_file + create_classdef if @opt.key?('classdef') + create_servant_skelton(@opt['servant_skelton']) if @opt.key?('servant_skelton') + create_cgi_stub(@opt['cgi_stub']) if @opt.key?('cgi_stub') + create_standalone_server_stub(@opt['standalone_server_stub']) if @opt.key?('standalone_server_stub') + create_driver(@opt['driver']) if @opt.key?('driver') + create_client_skelton(@opt['client_skelton']) if @opt.key?('client_skelton') + end + + def create_classdef + @logger.info { "Creating class definition." } + @classdef_filename = @name + '.rb' + check_file(@classdef_filename) or return + write_file(@classdef_filename) do |f| + f << WSDL::SOAP::ClassDefCreator.new(@wsdl).dump + end + end + + def create_client_skelton(servicename) + @logger.info { "Creating client skelton." } + servicename ||= @wsdl.services[0].name.name + @client_skelton_filename = servicename + 'Client.rb' + check_file(@client_skelton_filename) or return + write_file(@client_skelton_filename) do |f| + f << shbang << "\n" + f << "require '#{@driver_filename}'\n\n" if @driver_filename + f << WSDL::SOAP::ClientSkeltonCreator.new(@wsdl).dump( + create_name(servicename)) + end + end + + def create_servant_skelton(porttypename) + @logger.info { "Creating servant skelton." } + @servant_skelton_filename = (porttypename || @name + 'Servant') + '.rb' + check_file(@servant_skelton_filename) or return + write_file(@servant_skelton_filename) do |f| + f << "require '#{@classdef_filename}'\n\n" if @classdef_filename + f << WSDL::SOAP::ServantSkeltonCreator.new(@wsdl).dump( + create_name(porttypename)) + end + end + + def create_cgi_stub(servicename) + @logger.info { "Creating CGI stub." } + servicename ||= @wsdl.services[0].name.name + @cgi_stubFilename = servicename + '.cgi' + check_file(@cgi_stubFilename) or return + write_file(@cgi_stubFilename) do |f| + f << shbang << "\n" + if @servant_skelton_filename + f << "require '#{@servant_skelton_filename}'\n\n" + end + f << WSDL::SOAP::CGIStubCreator.new(@wsdl).dump(create_name(servicename)) + end + end + + def create_standalone_server_stub(servicename) + @logger.info { "Creating standalone stub." } + servicename ||= @wsdl.services[0].name.name + @standalone_server_stub_filename = servicename + '.rb' + check_file(@standalone_server_stub_filename) or return + write_file(@standalone_server_stub_filename) do |f| + f << shbang << "\n" + f << "require '#{@servant_skelton_filename}'\n\n" if @servant_skelton_filename + f << WSDL::SOAP::StandaloneServerStubCreator.new(@wsdl).dump( + create_name(servicename)) + end + end + + def create_driver(porttypename) + @logger.info { "Creating driver." } + @driver_filename = (porttypename || @name) + 'Driver.rb' + check_file(@driver_filename) or return + write_file(@driver_filename) do |f| + f << "require '#{@classdef_filename}'\n\n" if @classdef_filename + f << WSDL::SOAP::DriverCreator.new(@wsdl).dump( + create_name(porttypename)) + end + end + + def write_file(filename) + if @basedir + filename = File.join(basedir, filename) + end + File.open(filename, "w") do |f| + yield f + end + end + + def check_file(filename) + if @basedir + filename = File.join(basedir, filename) + end + if FileTest.exist?(filename) + if @opt.key?('force') + @logger.warn { + "File '#{filename}' exists but overrides it." + } + true + else + @logger.warn { + "File '#{filename}' exists. #{$0} did not override it." + } + false + end + else + @logger.info { "Creates file '#{filename}'." } + true + end + end + + def shbang + "#!/usr/bin/env ruby" + end + + def create_name(name) + name ? XSD::QName.new(@wsdl.targetnamespace, name) : nil + end + + def import(location) + WSDL::Importer.import(location) + end +end + + +end +end |