diff options
Diffstat (limited to 'lib/soap/mapping/wsdlliteralregistry.rb')
-rw-r--r-- | lib/soap/mapping/wsdlliteralregistry.rb | 337 |
1 files changed, 225 insertions, 112 deletions
diff --git a/lib/soap/mapping/wsdlliteralregistry.rb b/lib/soap/mapping/wsdlliteralregistry.rb index c190c9d904..59acf2f658 100644 --- a/lib/soap/mapping/wsdlliteralregistry.rb +++ b/lib/soap/mapping/wsdlliteralregistry.rb @@ -1,5 +1,5 @@ # SOAP4R - WSDL literal mapping registry. -# Copyright (C) 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2004, 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; @@ -10,48 +10,55 @@ require 'soap/baseData' require 'soap/mapping/mapping' require 'soap/mapping/typeMap' require 'xsd/codegen/gensupport' +require 'xsd/namedelements' module SOAP module Mapping -class WSDLLiteralRegistry +class WSDLLiteralRegistry < Registry attr_reader :definedelements attr_reader :definedtypes attr_accessor :excn_handler_obj2soap attr_accessor :excn_handler_soap2obj - def initialize(definedelements = nil, definedtypes = nil) - @definedelements = definedelements + def initialize(definedtypes = XSD::NamedElements::Empty, + definedelements = XSD::NamedElements::Empty) @definedtypes = definedtypes - @rubytype_factory = RubytypeFactory.new(:allow_original_mapping => false) + @definedelements = definedelements + @excn_handler_obj2soap = nil + @excn_handler_soap2obj = nil @schema_element_cache = {} + @schema_attribute_cache = {} end def obj2soap(obj, qname) - ret = nil - if !@definedelements.nil? && ele = @definedelements[qname] - ret = _obj2soap(obj, ele) - elsif !@definedtypes.nil? && type = @definedtypes[qname] - ret = obj2type(obj, type) + soap_obj = nil + if ele = @definedelements[qname] + soap_obj = obj2elesoap(obj, ele) + elsif type = @definedtypes[qname] + soap_obj = obj2typesoap(obj, type) else - ret = unknownobj2soap(obj, qname) + soap_obj = any2soap(obj, qname) end - return ret if ret + return soap_obj if soap_obj if @excn_handler_obj2soap - ret = @excn_handler_obj2soap.call(obj) { |yield_obj| + soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| Mapping._obj2soap(yield_obj, self) } - return ret if ret + return soap_obj if soap_obj end - raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.") + raise MappingError.new("cannot map #{obj.class.name} as #{qname}") end # node should be a SOAPElement - def soap2obj(node) + def soap2obj(node, obj_class = nil) + unless obj_class.nil? + raise MappingError.new("must not reach here") + end begin - return soapele2obj(node) + return any2obj(node) rescue MappingError end if @excn_handler_soap2obj @@ -62,108 +69,164 @@ class WSDLLiteralRegistry rescue Exception end end - raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.") + raise MappingError.new("cannot map #{node.type.name} to Ruby object") end private - def _obj2soap(obj, ele) + def obj2elesoap(obj, ele) o = nil if ele.type if type = @definedtypes[ele.type] - o = obj2type(obj, type) + o = obj2typesoap(obj, type) elsif type = TypeMap[ele.type] o = base2soap(obj, type) else - raise MappingError.new("Cannot find type #{ele.type}.") + raise MappingError.new("cannot find type #{ele.type}") end o.elename = ele.name elsif ele.local_complextype - o = SOAPElement.new(ele.name) - ele.local_complextype.each_element do |child_ele| - o.add(_obj2soap(Mapping.find_attribute(obj, child_ele.name.name), - child_ele)) - end + o = obj2typesoap(obj, ele.local_complextype) + o.elename = ele.name + add_attributes2soap(obj, o) + elsif ele.local_simpletype + o = obj2typesoap(obj, ele.local_simpletype) + o.elename = ele.name else - raise MappingError.new('Illegal schema?') + raise MappingError.new('illegal schema?') end o end - def obj2type(obj, type) + def obj2typesoap(obj, type) if type.is_a?(::WSDL::XMLSchema::SimpleType) - simple2soap(obj, type) + simpleobj2soap(obj, type) else - complex2soap(obj, type) + complexobj2soap(obj, type) end end - def simple2soap(obj, type) - o = base2soap(obj, TypeMap[type.base]) - if type.restriction.enumeration.empty? - STDERR.puts( - "#{type.name}: simpleType which is not enum type not supported.") - return o - end + def simpleobj2soap(obj, type) type.check_lexical_format(obj) + return SOAPNil.new if obj.nil? # ToDo: check nillable. + o = base2soap(obj, TypeMap[type.base]) o end - def complex2soap(obj, type) + def complexobj2soap(obj, type) o = SOAPElement.new(type.name) type.each_element do |child_ele| - o.add(_obj2soap(Mapping.find_attribute(obj, child_ele.name.name), - child_ele)) + child = Mapping.get_attribute(obj, child_ele.name.name) + if child.nil? + if child_ele.nillable + # ToDo: test + # add empty element + o.add(obj2elesoap(nil)) + elsif Integer(child_ele.minoccurs) == 0 + # nothing to do + else + raise MappingError.new("nil not allowed: #{child_ele.name.name}") + end + elsif child_ele.map_as_array? + child.each do |item| + o.add(obj2elesoap(item, child_ele)) + end + else + o.add(obj2elesoap(child, child_ele)) + end end o end - def unknownobj2soap(obj, name) - if obj.class.class_variables.include?('@@schema_element') - ele = SOAPElement.new(name) - add_elements2soap(obj, ele) - add_attributes2soap(obj, ele) - ele + def any2soap(obj, qname) + if obj.is_a?(SOAPElement) + obj + elsif obj.class.class_variables.include?('@@schema_element') + stubobj2soap(obj, qname) + elsif obj.is_a?(SOAP::Mapping::Object) + mappingobj2soap(obj, qname) elsif obj.is_a?(Hash) ele = SOAPElement.from_obj(obj) - ele.elename = name + ele.elename = qname ele - else # expected to be a basetype or an anyType. - o = Mapping.obj2soap(obj) - o.elename = name - o + else + # expected to be a basetype or an anyType. + # SOAPStruct, etc. is used instead of SOAPElement. + begin + ele = Mapping.obj2soap(obj) + ele.elename = qname + ele + rescue MappingError + ele = SOAPElement.new(qname, obj.to_s) + end + if obj.respond_to?(:__xmlattr) + obj.__xmlattr.each do |key, value| + ele.extraattr[key] = value + end + end + ele + end + end + + def stubobj2soap(obj, qname) + ele = SOAPElement.new(qname) + add_elements2soap(obj, ele) + add_attributes2soap(obj, ele) + ele + end + + def mappingobj2soap(obj, qname) + ele = SOAPElement.new(qname) + obj.__xmlele.each do |key, value| + if value.is_a?(::Array) + value.each do |item| + ele.add(obj2soap(item, key)) + end + else + ele.add(obj2soap(value, key)) + end + end + obj.__xmlattr.each do |key, value| + ele.extraattr[key] = value end + ele end def add_elements2soap(obj, ele) elements, as_array = schema_element_definition(obj.class) - elements.each do |elename, type| - child = Mapping.find_attribute(obj, elename) - name = ::XSD::QName.new(nil, elename) - if as_array.include?(type) - child.each do |item| - ele.add(obj2soap(item, name)) + if elements + elements.each do |elename, type| + child = Mapping.get_attribute(obj, elename) + unless child.nil? + name = XSD::QName.new(nil, elename) + if as_array.include?(type) + child.each do |item| + ele.add(obj2soap(item, name)) + end + else + ele.add(obj2soap(child, name)) + end end - else - ele.add(obj2soap(child, name)) end end end def add_attributes2soap(obj, ele) attributes = schema_attribute_definition(obj.class) - attributes.each do |attrname, param| - attr = Mapping.find_attribute(obj, 'attr_' + attrname) - ele.extraattr[attrname] = attr + if attributes + attributes.each do |qname, param| + attr = obj.__send__('xmlattr_' + + XSD::CodeGen::GenSupport.safevarname(qname.name)) + ele.extraattr[qname] = attr + end end end def base2soap(obj, type) soap_obj = nil - if type <= ::XSD::XSDString - soap_obj = type.new(::XSD::Charset.is_ces(obj, $KCODE) ? - ::XSD::Charset.encoding_conv(obj, $KCODE, ::XSD::Charset.encoding) : - obj) + if type <= XSD::XSDString + soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ? + XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj) else soap_obj = type.new(obj) end @@ -176,35 +239,41 @@ private end klass = ::SOAP::Mapping::Object obj = klass.new - node.each do |name, value| - obj.__soap_set_property(name, Mapping.soap2obj(value)) - end obj end - def soapele2obj(node, obj_class = nil) + def any2obj(node, obj_class = nil) unless obj_class - typestr = ::XSD::CodeGen::GenSupport.safeconstname(node.elename.name) + typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name) obj_class = Mapping.class_from_name(typestr) end if obj_class and obj_class.class_variables.include?('@@schema_element') - soapele2definedobj(node, obj_class) - elsif node.is_a?(SOAPElement) - node.to_obj + soapele2stubobj(node, obj_class) + elsif node.is_a?(SOAPElement) or node.is_a?(SOAPStruct) + # SOAPArray for literal? + soapele2plainobj(node) else - result, obj = @rubytype_factory.soap2obj(nil, node, nil, self) + obj = Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class) + add_attributes2plainobj(node, obj) obj end end - def soapele2definedobj(node, obj_class) + def soapele2stubobj(node, obj_class) obj = Mapping.create_empty_object(obj_class) - add_elements2obj(node, obj) - add_attributes2obj(node, obj) + add_elements2stubobj(node, obj) + add_attributes2stubobj(node, obj) obj end - def add_elements2obj(node, obj) + def soapele2plainobj(node) + obj = anytype2obj(node) + add_elements2plainobj(node, obj) + add_attributes2plainobj(node, obj) + obj + end + + def add_elements2stubobj(node, obj) elements, as_array = schema_element_definition(obj.class) vars = {} node.each do |name, value| @@ -217,13 +286,13 @@ private child = klass.new(nil).data end else - child = soapele2obj(value, klass) + child = any2obj(value, klass) end else - raise MappingError.new("Unknown class: #{class_name}") + raise MappingError.new("unknown class: #{class_name}") end else # untyped element is treated as anyType. - child = anytype2obj(value) + child = any2obj(value) end if as_array.include?(class_name) (vars[name] ||= []) << child @@ -231,48 +300,92 @@ private vars[name] = child end end - Mapping.set_instance_vars(obj, vars) + Mapping.set_attributes(obj, vars) end - def add_attributes2obj(node, obj) - Mapping.set_instance_vars(obj, {'__soap_attribute' => {}}) - vars = {} - attributes = schema_attribute_definition(obj.class) - attributes.each do |attrname, class_name| - attr = node.extraattr[::XSD::QName.new(nil, attrname)] - next if attr.nil? or attr.empty? - klass = Mapping.class_from_name(class_name) - if klass.ancestors.include?(::SOAP::SOAPBasetype) - child = klass.new(attr).data - else - child = attr + def add_attributes2stubobj(node, obj) + if attributes = schema_attribute_definition(obj.class) + define_xmlattr(obj) + attributes.each do |qname, class_name| + attr = node.extraattr[qname] + next if attr.nil? or attr.empty? + klass = Mapping.class_from_name(class_name) + if klass.ancestors.include?(::SOAP::SOAPBasetype) + child = klass.new(attr).data + else + child = attr + end + obj.__xmlattr[qname] = child + define_xmlattr_accessor(obj, qname) end - vars['attr_' + attrname] = child end - Mapping.set_instance_vars(obj, vars) end - # it caches @@schema_element. this means that @@schema_element must not be - # changed while a lifetime of a WSDLLiteralRegistry. - def schema_element_definition(klass) - if @schema_element_cache.key?(klass) - return @schema_element_cache[klass] + def add_elements2plainobj(node, obj) + node.each do |name, value| + obj.__add_xmlele_value(XSD::QName.new(nil, name), any2obj(value)) + end + end + + def add_attributes2plainobj(node, obj) + return if node.extraattr.empty? + define_xmlattr(obj) + node.extraattr.each do |qname, value| + obj.__xmlattr[qname] = value + define_xmlattr_accessor(obj, qname) + end + end + + if RUBY_VERSION > "1.7.0" + def define_xmlattr_accessor(obj, qname) + name = XSD::CodeGen::GenSupport.safemethodname(qname.name) + Mapping.define_attr_accessor(obj, 'xmlattr_' + name, + proc { @__xmlattr[qname] }, + proc { |value| @__xmlattr[qname] = value }) + end + else + def define_xmlattr_accessor(obj, qname) + name = XSD::CodeGen::GenSupport.safemethodname(qname.name) + obj.instance_eval <<-EOS + def #{name} + @__xmlattr[#{qname.dump}] + end + + def #{name}=(value) + @__xmlattr[#{qname.dump}] = value + end + EOS + end + end + + if RUBY_VERSION > "1.7.0" + def define_xmlattr(obj) + obj.instance_variable_set('@__xmlattr', {}) + unless obj.respond_to?(:__xmlattr) + Mapping.define_attr_accessor(obj, :__xmlattr, proc { @__xmlattr }) + end end - elements = {} - as_array = [] - klass.class_eval('@@schema_element').each do |name, class_name| - if /\[\]$/ =~ class_name - class_name = class_name.sub(/\[\]$/, '') - as_array << class_name + else + def define_xmlattr(obj) + obj.instance_variable_set('@__xmlattr', {}) + unless obj.respond_to?(:__xmlattr) + obj.instance_eval <<-EOS + def __xmlattr + @__xmlattr + end + EOS end - elements[name] = class_name end - @schema_element_cache[klass] = [elements, as_array] - return @schema_element_cache[klass] + end + + # it caches @@schema_element. this means that @@schema_element must not be + # changed while a lifetime of a WSDLLiteralRegistry. + def schema_element_definition(klass) + @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass) end def schema_attribute_definition(klass) - attributes = klass.class_eval('@@schema_attribute') + @schema_attribute_cache[klass] ||= Mapping.schema_attribute_definition(klass) end end |