diff options
author | (no author) <(no author)@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-12-20 14:41:10 +0000 |
---|---|---|
committer | (no author) <(no author)@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-12-20 14:41:10 +0000 |
commit | 330a8e51c56f5386753f55ba8e656a62471a36ba (patch) | |
tree | 9baa48b1a2dfad4b0d1d9580248177be8c0e9802 /lib/soap | |
parent | 50651e957a10a0cbc782841116ae576018a72160 (diff) |
This commit was manufactured by cvs2svn to create branch 'ruby_1_8'.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@7616 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/soap')
-rw-r--r-- | lib/soap/mapping/wsdlencodedregistry.rb | 173 | ||||
-rw-r--r-- | lib/soap/mapping/wsdlliteralregistry.rb | 281 |
2 files changed, 454 insertions, 0 deletions
diff --git a/lib/soap/mapping/wsdlencodedregistry.rb b/lib/soap/mapping/wsdlencodedregistry.rb new file mode 100644 index 0000000000..4433c73cf0 --- /dev/null +++ b/lib/soap/mapping/wsdlencodedregistry.rb @@ -0,0 +1,173 @@ +# SOAP4R - WSDL encoded mapping registry. +# Copyright (C) 2000, 2001, 2002, 2003 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 'soap/baseData' +require 'soap/mapping/mapping' +require 'soap/mapping/typeMap' + + +module SOAP +module Mapping + + +class WSDLEncodedRegistry + include TraverseSupport + + attr_reader :definedtypes + attr_accessor :excn_handler_obj2soap + + def initialize(definedtypes, config = {}) + @definedtypes = definedtypes + @config = config + @excn_handler_obj2soap = nil + # For mapping AnyType element. + @rubytype_factory = RubytypeFactory.new( + :allow_untyped_struct => true, + :allow_original_mapping => true + ) + end + + def obj2soap(obj, type_qname = nil) + soap_obj = nil + if obj.nil? + soap_obj = SOAPNil.new + elsif type_qname.nil? or type_qname == XSD::AnyTypeName + soap_obj = @rubytype_factory.obj2soap(nil, obj, nil, self) + elsif obj.is_a?(XSD::NSDBase) + soap_obj = soap2soap(obj, type_qname) + elsif type = @definedtypes[type_qname] + soap_obj = obj2type(obj, type) + elsif (type = TypeMap[type_qname]) + soap_obj = base2soap(obj, type) + end + return soap_obj if soap_obj + if @excn_handler_obj2soap + soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| + Mapping._obj2soap(yield_obj, self) + } + return soap_obj if soap_obj + end + raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.") + end + + def soap2obj(node) + raise RuntimeError.new("#{ self } is for obj2soap only.") + end + +private + + def soap2soap(obj, type_qname) + if obj.is_a?(SOAPBasetype) + obj + elsif obj.is_a?(SOAPStruct) && (type = @definedtypes[type_qname]) + soap_obj = obj + mark_marshalled_obj(obj, soap_obj) + elements2soap(obj, soap_obj, type.content.elements) + soap_obj + elsif obj.is_a?(SOAPArray) && (type = @definedtypes[type_qname]) + soap_obj = obj + contenttype = type.child_type + mark_marshalled_obj(obj, soap_obj) + obj.replace do |ele| + Mapping._obj2soap(ele, self, contenttype) + end + soap_obj + else + nil + end + end + + def obj2type(obj, type) + if type.is_a?(::WSDL::XMLSchema::SimpleType) + simple2soap(obj, type) + else + complex2soap(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 + type.check_lexical_format(obj) + o + end + + def complex2soap(obj, type) + case type.compoundtype + when :TYPE_STRUCT + struct2soap(obj, type.name, type) + when :TYPE_ARRAY + array2soap(obj, type.name, type) + when :TYPE_MAP + map2soap(obj, type.name, type) + else + raise MappingError.new("Unknown compound type: #{ type.compoundtype }") + 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) + mark_marshalled_obj(obj, soap_obj) + else + soap_obj = type.new(obj) + end + soap_obj + end + + def struct2soap(obj, type_qname, type) + soap_obj = SOAPStruct.new(type_qname) + mark_marshalled_obj(obj, soap_obj) + elements2soap(obj, soap_obj, type.content.elements) + soap_obj + end + + def array2soap(obj, type_qname, type) + arytype = type.child_type + soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) + mark_marshalled_obj(obj, soap_obj) + obj.each do |item| + soap_obj.add(Mapping._obj2soap(item, self, arytype)) + end + soap_obj + end + + MapKeyName = XSD::QName.new(nil, "key") + MapValueName = XSD::QName.new(nil, "value") + def map2soap(obj, type_qname, type) + keytype = type.child_type(MapKeyName) || XSD::AnyTypeName + valuetype = type.child_type(MapValueName) || XSD::AnyTypeName + soap_obj = SOAPStruct.new(MapQName) + mark_marshalled_obj(obj, soap_obj) + obj.each do |key, value| + elem = SOAPStruct.new + elem.add("key", Mapping._obj2soap(key, self, keytype)) + elem.add("value", Mapping._obj2soap(value, self, valuetype)) + # ApacheAxis allows only 'item' here. + soap_obj.add("item", elem) + end + soap_obj + end + + def elements2soap(obj, soap_obj, elements) + elements.each do |element| + name = element.name.name + child_obj = obj.instance_eval("@#{ name }") + soap_obj.add(name, Mapping._obj2soap(child_obj, self, element.type)) + end + end +end + + +end +end diff --git a/lib/soap/mapping/wsdlliteralregistry.rb b/lib/soap/mapping/wsdlliteralregistry.rb new file mode 100644 index 0000000000..c190c9d904 --- /dev/null +++ b/lib/soap/mapping/wsdlliteralregistry.rb @@ -0,0 +1,281 @@ +# SOAP4R - WSDL literal mapping registry. +# Copyright (C) 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; +# either the dual license version in 2003, or any later version. + + +require 'soap/baseData' +require 'soap/mapping/mapping' +require 'soap/mapping/typeMap' +require 'xsd/codegen/gensupport' + + +module SOAP +module Mapping + + +class WSDLLiteralRegistry + attr_reader :definedelements + attr_reader :definedtypes + attr_accessor :excn_handler_obj2soap + attr_accessor :excn_handler_soap2obj + + def initialize(definedelements = nil, definedtypes = nil) + @definedelements = definedelements + @definedtypes = definedtypes + @rubytype_factory = RubytypeFactory.new(:allow_original_mapping => false) + @schema_element_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) + else + ret = unknownobj2soap(obj, qname) + end + return ret if ret + if @excn_handler_obj2soap + ret = @excn_handler_obj2soap.call(obj) { |yield_obj| + Mapping._obj2soap(yield_obj, self) + } + return ret if ret + end + raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.") + end + + # node should be a SOAPElement + def soap2obj(node) + begin + return soapele2obj(node) + rescue MappingError + end + if @excn_handler_soap2obj + begin + return @excn_handler_soap2obj.call(node) { |yield_node| + Mapping._soap2obj(yield_node, self) + } + rescue Exception + end + end + raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.") + end + +private + + def _obj2soap(obj, ele) + o = nil + if ele.type + if type = @definedtypes[ele.type] + o = obj2type(obj, type) + elsif type = TypeMap[ele.type] + o = base2soap(obj, type) + else + 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 + else + raise MappingError.new('Illegal schema?') + end + o + end + + def obj2type(obj, type) + if type.is_a?(::WSDL::XMLSchema::SimpleType) + simple2soap(obj, type) + else + complex2soap(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 + type.check_lexical_format(obj) + o + end + + def complex2soap(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)) + 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 + elsif obj.is_a?(Hash) + ele = SOAPElement.from_obj(obj) + ele.elename = name + ele + else # expected to be a basetype or an anyType. + o = Mapping.obj2soap(obj) + o.elename = name + o + end + 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)) + 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 + 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) + else + soap_obj = type.new(obj) + end + soap_obj + end + + def anytype2obj(node) + if node.is_a?(::SOAP::SOAPBasetype) + return node.data + 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) + unless obj_class + 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 + else + result, obj = @rubytype_factory.soap2obj(nil, node, nil, self) + obj + end + end + + def soapele2definedobj(node, obj_class) + obj = Mapping.create_empty_object(obj_class) + add_elements2obj(node, obj) + add_attributes2obj(node, obj) + obj + end + + def add_elements2obj(node, obj) + elements, as_array = schema_element_definition(obj.class) + vars = {} + node.each do |name, value| + if class_name = elements[name] + if klass = Mapping.class_from_name(class_name) + if klass.ancestors.include?(::SOAP::SOAPBasetype) + if value.respond_to?(:data) + child = klass.new(value.data).data + else + child = klass.new(nil).data + end + else + child = soapele2obj(value, klass) + end + else + raise MappingError.new("Unknown class: #{class_name}") + end + else # untyped element is treated as anyType. + child = anytype2obj(value) + end + if as_array.include?(class_name) + (vars[name] ||= []) << child + else + vars[name] = child + end + end + Mapping.set_instance_vars(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 + 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] + 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 + end + elements[name] = class_name + end + @schema_element_cache[klass] = [elements, as_array] + return @schema_element_cache[klass] + end + + def schema_attribute_definition(klass) + attributes = klass.class_eval('@@schema_attribute') + end +end + + +end +end |