summaryrefslogtreecommitdiff
path: root/lib/soap/mapping
diff options
context:
space:
mode:
authornahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-09-24 15:18:44 +0000
committernahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-09-24 15:18:44 +0000
commitdb9445103c082a306ba085f7677da02ea94b8841 (patch)
treea311d59f031ae5def87f68be71ed1f58abadc031 /lib/soap/mapping
parent8c2fb77787d1f20b4c19c9c52552856c339b86e9 (diff)
* lib/soap/* (29 files): SOAP4R added.
* lib/wsdl/* (42 files): WSDL4R added. * lib/xsd/* (12 files): XSD4R added. * test/soap/* (16 files): added. * test/wsdl/* (2 files): added. * test/xsd/* (3 files): added. * sample/soap/* (27 files): added. * sample/wsdl/* (13 files): added. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4591 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/soap/mapping')
-rw-r--r--lib/soap/mapping/factory.rb310
-rw-r--r--lib/soap/mapping/mapping.rb218
-rw-r--r--lib/soap/mapping/registry.rb408
-rw-r--r--lib/soap/mapping/rubytypeFactory.rb437
-rw-r--r--lib/soap/mapping/typeMap.rb52
-rw-r--r--lib/soap/mapping/wsdlRegistry.rb146
6 files changed, 1571 insertions, 0 deletions
diff --git a/lib/soap/mapping/factory.rb b/lib/soap/mapping/factory.rb
new file mode 100644
index 0000000000..2e5ddc1f15
--- /dev/null
+++ b/lib/soap/mapping/factory.rb
@@ -0,0 +1,310 @@
+=begin
+SOAP4R - Mapping factory.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+module Mapping
+
+
+class Factory
+ include TraverseSupport
+
+ def obj2soap(soap_class, obj, info, map)
+ raise NotImplementError.new
+ # return soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ raise NotImplementError.new
+ # return convert_succeeded_or_not, obj
+ end
+
+ if Object.respond_to?(:allocate)
+ # ruby/1.7 or later.
+ def create_empty_object(klass)
+ klass.allocate
+ end
+ else
+ def create_empty_object(klass)
+ name = klass.name
+ # Below line is from TANAKA, Akira's amarshal.rb.
+ # See http://cvs.m17n.org/cgi-bin/viewcvs/amarshal/?cvsroot=ruby
+ ::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name))
+ end
+ end
+
+ def set_instance_vars(obj, values)
+ values.each do |name, value|
+ setter = name + "="
+ if obj.respond_to?(setter)
+ obj.__send__(setter, value)
+ else
+ obj.instance_eval("@#{ name } = value")
+ end
+ end
+ end
+
+ def setiv2obj(obj, node, map)
+ return if node.nil?
+ vars = {}
+ node.each do |name, value|
+ vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
+ end
+ set_instance_vars(obj, vars)
+ end
+
+ def setiv2soap(node, obj, map)
+ obj.instance_variables.each do |var|
+ name = var.sub(/^@/, '')
+ node.add(Mapping.name2elename(name),
+ Mapping._obj2soap(obj.instance_eval(var), map))
+ end
+ end
+
+ def addiv2soap(node, obj, map)
+ return if obj.instance_variables.empty?
+ ivars = SOAPStruct.new # Undefined type.
+ setiv2soap(ivars, obj, map)
+ node.add('ivars', ivars)
+ end
+
+ # It breaks Thread.current[:SOAPMarshalDataKey].
+ def mark_marshalled_obj(obj, soap_obj)
+ Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
+ end
+
+ # It breaks Thread.current[:SOAPMarshalDataKey].
+ def mark_unmarshalled_obj(node, obj)
+ Thread.current[:SOAPMarshalDataKey][node.id] = obj
+ end
+
+ def name2typename(name)
+ capitalize(name)
+ end
+
+ def capitalize(target)
+ target.gsub(/^([a-z])/) { $1.tr!('[a-z]', '[A-Z]') }
+ end
+end
+
+class StringFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ begin
+ if XSD::Charset.is_ces(obj, $KCODE)
+ encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
+ soap_obj = soap_class.new(encoded)
+ else
+ return nil
+ end
+ rescue XSD::ValueSpaceError
+ return nil
+ end
+ mark_marshalled_obj(obj, soap_obj)
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, $KCODE)
+ mark_unmarshalled_obj(node, obj)
+ return true, obj
+ end
+end
+
+class BasetypeFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ soap_obj = nil
+ begin
+ soap_obj = soap_class.new(obj)
+ rescue XSD::ValueSpaceError
+ return nil
+ end
+ # Basetype except String should not be multiref-ed in SOAP/1.1.
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = node.data
+ mark_unmarshalled_obj(node, obj)
+ return true, obj
+ end
+end
+
+class DateTimeFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ soap_obj = nil
+ begin
+ soap_obj = soap_class.new(obj)
+ rescue XSD::ValueSpaceError
+ return nil
+ end
+ mark_marshalled_obj(obj, soap_obj)
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = nil
+ if obj_class == Time
+ obj = node.to_time
+ if obj.nil?
+ # Is out of range as a Time
+ return false
+ end
+ elsif obj_class == Date
+ obj = node.data
+ else
+ return false
+ end
+ mark_unmarshalled_obj(node, obj)
+ return true, obj
+ end
+end
+
+class Base64Factory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ soap_obj = soap_class.new(obj)
+ mark_marshalled_obj(obj, soap_obj) if soap_obj
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = node.string
+ mark_unmarshalled_obj(node, obj)
+ return true, obj
+ end
+end
+
+class ArrayFactory_ < Factory
+ # [[1], [2]] is converted to Array of Array, not 2-D Array.
+ # To create M-D Array, you must call Mapping.ary2md.
+ def obj2soap(soap_class, obj, info, map)
+ arytype = Mapping.obj2element(obj)
+ if arytype.name
+ arytype.namespace ||= RubyTypeNamespace
+ else
+ arytype = XSD::AnyTypeName
+ end
+ param = SOAPArray.new(ValueArrayName, 1, arytype)
+ mark_marshalled_obj(obj, param)
+ obj.each do |var|
+ param.add(Mapping._obj2soap(var, map))
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = create_empty_object(obj_class)
+ mark_unmarshalled_obj(node, obj)
+ node.soap2array(obj) do |elem|
+ elem ? Mapping._soap2obj(elem, map) : nil
+ end
+ return true, obj
+ end
+end
+
+class TypedArrayFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ arytype = info[:type] || info[0]
+ param = SOAPArray.new(ValueArrayName, 1, arytype)
+ mark_marshalled_obj(obj, param)
+ obj.each do |var|
+ param.add(Mapping._obj2soap(var, map))
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ if node.rank > 1
+ return false
+ end
+ arytype = info[:type] || info[0]
+ unless node.arytype == arytype
+ return false
+ end
+ obj = create_empty_object(obj_class)
+ mark_unmarshalled_obj(node, obj)
+ node.soap2array(obj) do |elem|
+ elem ? Mapping._soap2obj(elem, map) : nil
+ end
+ return true, obj
+ end
+end
+
+class TypedStructFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ type = info[:type] || info[0]
+ param = soap_class.new(type)
+ mark_marshalled_obj(obj, param)
+ if obj.class <= SOAP::Marshallable
+ setiv2soap(param, obj, map)
+ else
+ setiv2soap(param, obj, map)
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ type = info[:type] || info[0]
+ unless node.type == type
+ return false
+ end
+ obj = create_empty_object(obj_class)
+ mark_unmarshalled_obj(node, obj)
+ setiv2obj(obj, node, map)
+ return true, obj
+ end
+end
+
+MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map')
+class HashFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ if obj.default or
+ (obj.respond_to?(:default_proc) and obj.default_proc)
+ return nil
+ end
+ param = SOAPStruct.new(MapQName)
+ mark_marshalled_obj(obj, param)
+ obj.each do |key, value|
+ elem = SOAPStruct.new
+ elem.add("key", Mapping._obj2soap(key, map))
+ elem.add("value", Mapping._obj2soap(value, map))
+ # ApacheAxis allows only 'item' here.
+ param.add("item", elem)
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ unless node.type == MapQName
+ return false
+ end
+ if node.key?('default')
+ return false
+ end
+ obj = create_empty_object(obj_class)
+ mark_unmarshalled_obj(node, obj)
+ node.each do |key, value|
+ obj[Mapping._soap2obj(value['key'], map)] =
+ Mapping._soap2obj(value['value'], map)
+ end
+ return true, obj
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/mapping/mapping.rb b/lib/soap/mapping/mapping.rb
new file mode 100644
index 0000000000..19eca5dab0
--- /dev/null
+++ b/lib/soap/mapping/mapping.rb
@@ -0,0 +1,218 @@
+=begin
+SOAP4R - Ruby type mapping utility.
+Copyright (C) 2000, 2001, 2003 NAKAMURA Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+
+
+module Mapping
+ RubyTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/1.6'
+ RubyTypeInstanceNamespace =
+ 'http://www.ruby-lang.org/xmlns/ruby/type-instance'
+ RubyCustomTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/custom'
+ ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap'
+
+
+ # TraverseSupport breaks Thread.current[:SOAPMarshalDataKey].
+ module TraverseSupport
+ def mark_marshalled_obj(obj, soap_obj)
+ Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
+ end
+
+ def mark_unmarshalled_obj(node, obj)
+ # node.id is not Object#id but SOAPReference#id
+ Thread.current[:SOAPMarshalDataKey][node.id] = obj
+ end
+ end
+
+
+ def self.obj2soap(obj, registry = nil, type = nil)
+ registry ||= Mapping::DefaultRegistry
+ Thread.current[:SOAPMarshalDataKey] = {}
+ soap_obj = _obj2soap(obj, registry, type)
+ Thread.current[:SOAPMarshalDataKey] = nil
+ soap_obj
+ end
+
+ def self.soap2obj(node, registry = nil)
+ registry ||= Mapping::DefaultRegistry
+ Thread.current[:SOAPMarshalDataKey] = {}
+ obj = _soap2obj(node, registry)
+ Thread.current[:SOAPMarshalDataKey] = nil
+ obj
+ end
+
+ def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil)
+ registry ||= Mapping::DefaultRegistry
+ type = XSD::QName.new(type_ns, typename)
+ soap_ary = SOAPArray.new(ValueArrayName, 1, type)
+ Thread.current[:SOAPMarshalDataKey] = {}
+ ary.each do |ele|
+ soap_ary.add(_obj2soap(ele, registry, type))
+ end
+ Thread.current[:SOAPMarshalDataKey] = nil
+ soap_ary
+ end
+
+ def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil)
+ registry ||= Mapping::DefaultRegistry
+ type = XSD::QName.new(type_ns, typename)
+ md_ary = SOAPArray.new(ValueArrayName, rank, type)
+ Thread.current[:SOAPMarshalDataKey] = {}
+ add_md_ary(md_ary, ary, [], registry)
+ Thread.current[:SOAPMarshalDataKey] = nil
+ md_ary
+ end
+
+ def self.fault2exception(e, registry = nil)
+ registry ||= Mapping::DefaultRegistry
+ detail = if e.detail
+ soap2obj(e.detail, registry) || ""
+ else
+ ""
+ end
+ if detail.is_a?(Mapping::SOAPException)
+ begin
+ raise detail.to_e
+ rescue Exception => e2
+ detail.set_backtrace(e2)
+ raise
+ end
+ else
+ e.detail = detail
+ e.set_backtrace(
+ if detail.is_a?(Array)
+ detail
+ else
+ [detail.to_s]
+ end
+ )
+ raise
+ end
+ end
+
+ def self._obj2soap(obj, registry, type = nil)
+ if referent = Thread.current[:SOAPMarshalDataKey][obj.__id__]
+ soap_obj = SOAPReference.new
+ soap_obj.__setobj__(referent)
+ soap_obj
+ else
+ registry.obj2soap(obj.class, obj, type)
+ end
+ end
+
+ def self._soap2obj(node, registry)
+ if node.is_a?(SOAPReference)
+ target = node.__getobj__
+ # target.id is not Object#id but SOAPReference#id
+ if referent = Thread.current[:SOAPMarshalDataKey][target.id]
+ return referent
+ else
+ return _soap2obj(target, registry)
+ end
+ end
+ return registry.soap2obj(node.class, node)
+ end
+
+
+ # Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here.
+ # Caution: '.' is not allowed here.
+ # To follow XML spec., it should be NCName.
+ # (denied chars) => .[0-F][0-F]
+ # ex. a.b => a.2eb
+ #
+ def self.name2elename(name)
+ name.gsub(/([^a-zA-Z0-9:_\-]+)/n) {
+ '.' << $1.unpack('H2' * $1.size).join('.')
+ }.gsub(/::/n, '..')
+ end
+
+ def self.elename2name(name)
+ name.gsub(/\.\./n, '::').gsub(/((?:\.[0-9a-fA-F]{2})+)/n) {
+ [$1.delete('.')].pack('H*')
+ }
+ end
+
+ def self.class_from_name(name)
+ if /^[A-Z]/ !~ name
+ return nil
+ end
+ klass = ::Object
+ name.split('::').each do |klass_str|
+ if klass.const_defined?(klass_str)
+ klass = klass.const_get(klass_str)
+ else
+ return nil
+ end
+ end
+ klass
+ end
+
+ def self.class2qname(klass)
+ name = if klass.class_variables.include?("@@schema_type")
+ klass.class_eval("@@schema_type")
+ else
+ nil
+ end
+ namespace = if klass.class_variables.include?("@@schema_ns")
+ klass.class_eval("@@schema_ns")
+ else
+ nil
+ end
+ XSD::QName.new(namespace, name)
+ end
+
+ def self.class2element(klass)
+ type = Mapping.class2qname(klass)
+ type.name ||= Mapping.name2elename(klass.name)
+ type.namespace ||= RubyCustomTypeNamespace
+ type
+ end
+
+ def self.obj2element(obj)
+ name = namespace = nil
+ ivars = obj.instance_variables
+ if ivars.include?("@schema_type")
+ name = obj.instance_eval("@schema_type")
+ end
+ if ivars.include?("@schema_ns")
+ namespace = obj.instance_eval("@schema_ns")
+ end
+ if !name or !namespace
+ class2qname(obj.class)
+ else
+ XSD::QName.new(namespace, name)
+ end
+ end
+
+ class << Mapping
+ private
+ def add_md_ary(md_ary, ary, indices, registry)
+ for idx in 0..(ary.size - 1)
+ if ary[idx].is_a?(Array)
+ add_md_ary(md_ary, ary[idx], indices + [idx], registry)
+ else
+ md_ary[*(indices + [idx])] = _obj2soap(ary[idx], registry)
+ end
+ end
+ end
+ end
+end
+
+
+end
diff --git a/lib/soap/mapping/registry.rb b/lib/soap/mapping/registry.rb
new file mode 100644
index 0000000000..568f34ac3e
--- /dev/null
+++ b/lib/soap/mapping/registry.rb
@@ -0,0 +1,408 @@
+=begin
+SOAP4R - Mapping registry.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/baseData'
+require 'soap/mapping/mapping'
+require 'soap/mapping/typeMap'
+require 'soap/mapping/factory'
+require 'soap/mapping/rubytypeFactory'
+
+
+module SOAP
+
+
+module Marshallable
+ # @@type_ns = Mapping::RubyCustomTypeNamespace
+end
+
+
+module Mapping
+
+
+module MappedException; end
+
+
+RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
+
+
+# Inner class to pass an exception.
+class SOAPException; include Marshallable
+ attr_reader :excn_type_name, :message, :backtrace, :cause
+ def initialize(e)
+ @excn_type_name = Mapping.name2elename(e.class.to_s)
+ @message = e.message
+ @backtrace = e.backtrace
+ @cause = e
+ end
+
+ def to_e
+ if @cause.is_a?(::Exception)
+ @cause.extend(::SOAP::Mapping::MappedException)
+ return @cause
+ end
+ klass = Mapping.class_from_name(
+ Mapping.elename2name(@excn_type_name.to_s))
+ if klass.nil?
+ raise RuntimeError.new(@message)
+ end
+ unless klass <= ::Exception
+ raise NameError.new
+ end
+ obj = klass.new(@message)
+ obj.extend(::SOAP::Mapping::MappedException)
+ obj
+ end
+
+ def set_backtrace(e)
+ e.set_backtrace(
+ if @backtrace.is_a?(Array)
+ @backtrace
+ else
+ [@backtrace.inspect]
+ end
+ )
+ end
+end
+
+
+# For anyType object: SOAP::Mapping::Object not ::Object
+class Object; include Marshallable
+ def set_property(name, value)
+ var_name = name
+ begin
+ instance_eval <<-EOS
+ def #{ var_name }
+ @#{ var_name }
+ end
+
+ def #{ var_name }=(value)
+ @#{ var_name } = value
+ end
+ EOS
+ self.send(var_name + '=', value)
+ rescue SyntaxError
+ var_name = safe_name(var_name)
+ retry
+ end
+
+ var_name
+ end
+
+ def members
+ instance_variables.collect { |str| str[1..-1] }
+ end
+
+ def [](name)
+ if self.respond_to?(name)
+ self.send(name)
+ else
+ self.send(safe_name(name))
+ end
+ end
+
+ def []=(name, value)
+ if self.respond_to?(name)
+ self.send(name + '=', value)
+ else
+ self.send(safe_name(name) + '=', value)
+ end
+ end
+
+private
+
+ def safe_name(name)
+ require 'md5'
+ "var_" << MD5.new(name).hexdigest
+ end
+end
+
+
+class MappingError < Error; end
+
+
+class Registry
+ class Map
+ def initialize(registry)
+ @map = []
+ @registry = registry
+ end
+
+ def obj2soap(klass, obj)
+ @map.each do |obj_class, soap_class, factory, info|
+ if klass == obj_class or
+ (info[:derived_class] and klass <= obj_class)
+ ret = factory.obj2soap(soap_class, obj, info, @registry)
+ return ret if ret
+ end
+ end
+ nil
+ end
+
+ def soap2obj(klass, node)
+ @map.each do |obj_class, soap_class, factory, info|
+ if klass == soap_class or
+ (info[:derived_class] and klass <= soap_class)
+ conv, obj = factory.soap2obj(obj_class, node, info, @registry)
+ return true, obj if conv
+ end
+ end
+ return false
+ end
+
+ # Give priority to former entry.
+ def init(init_map = [])
+ clear
+ init_map.reverse_each do |obj_class, soap_class, factory, info|
+ add(obj_class, soap_class, factory, info)
+ end
+ end
+
+ # Give priority to latter entry.
+ def add(obj_class, soap_class, factory, info)
+ info ||= {}
+ @map.unshift([obj_class, soap_class, factory, info])
+ end
+
+ def clear
+ @map.clear
+ end
+
+ def find_mapped_soap_class(target_obj_class)
+ @map.each do |obj_class, soap_class, factory, info|
+ if obj_class == target_obj_class
+ return soap_class
+ end
+ end
+ nil
+ end
+
+ def find_mapped_obj_class(target_soap_class)
+ @map.each do |obj_class, soap_class, factory, info|
+ if soap_class == target_soap_class
+ return obj_class
+ end
+ end
+ nil
+ end
+ end
+
+ StringFactory = StringFactory_.new
+ BasetypeFactory = BasetypeFactory_.new
+ DateTimeFactory = DateTimeFactory_.new
+ ArrayFactory = ArrayFactory_.new
+ Base64Factory = Base64Factory_.new
+ TypedArrayFactory = TypedArrayFactory_.new
+ TypedStructFactory = TypedStructFactory_.new
+
+ HashFactory = HashFactory_.new
+
+ SOAPBaseMap = [
+ [::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
+ [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
+ [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
+ [::String, ::SOAP::SOAPString, StringFactory],
+ [::DateTime, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Date, ::SOAP::SOAPDate, BasetypeFactory],
+ [::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Time, ::SOAP::SOAPTime, BasetypeFactory],
+ [::Float, ::SOAP::SOAPDouble, BasetypeFactory,
+ {:derived_class => true}],
+ [::Float, ::SOAP::SOAPFloat, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPInt, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPLong, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPShort, BasetypeFactory,
+ {:derived_class => true}],
+ [::URI::Generic, ::SOAP::SOAPAnyURI, BasetypeFactory,
+ {:derived_class => true}],
+ [::String, ::SOAP::SOAPBase64, Base64Factory],
+ [::String, ::SOAP::SOAPHexBinary, Base64Factory],
+ [::String, ::SOAP::SOAPDecimal, BasetypeFactory],
+ [::String, ::SOAP::SOAPDuration, BasetypeFactory],
+ [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
+ [::String, ::SOAP::SOAPGYear, BasetypeFactory],
+ [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
+ [::String, ::SOAP::SOAPGDay, BasetypeFactory],
+ [::String, ::SOAP::SOAPGMonth, BasetypeFactory],
+ [::String, ::SOAP::SOAPQName, BasetypeFactory],
+
+ [::Array, ::SOAP::SOAPArray, ArrayFactory,
+ {:derived_class => true}],
+
+ [::Hash, ::SOAP::SOAPStruct, HashFactory],
+ [::SOAP::Mapping::SOAPException,
+ ::SOAP::SOAPStruct, TypedStructFactory,
+ {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
+ ]
+
+ RubyOriginalMap = [
+ [::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
+ [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
+ [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
+ [::String, ::SOAP::SOAPString, StringFactory],
+ [::DateTime, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Date, ::SOAP::SOAPDate, BasetypeFactory],
+ [::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Time, ::SOAP::SOAPTime, BasetypeFactory],
+ [::Float, ::SOAP::SOAPDouble, BasetypeFactory,
+ {:derived_class => true}],
+ [::Float, ::SOAP::SOAPFloat, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPInt, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPLong, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPShort, BasetypeFactory,
+ {:derived_class => true}],
+ [::URI::Generic, ::SOAP::SOAPAnyURI, BasetypeFactory,
+ {:derived_class => true}],
+ [::String, ::SOAP::SOAPBase64, Base64Factory],
+ [::String, ::SOAP::SOAPHexBinary, Base64Factory],
+ [::String, ::SOAP::SOAPDecimal, BasetypeFactory],
+ [::String, ::SOAP::SOAPDuration, BasetypeFactory],
+ [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
+ [::String, ::SOAP::SOAPGYear, BasetypeFactory],
+ [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
+ [::String, ::SOAP::SOAPGDay, BasetypeFactory],
+ [::String, ::SOAP::SOAPGMonth, BasetypeFactory],
+ [::String, ::SOAP::SOAPQName, BasetypeFactory],
+
+ # Does not allow Array's subclass here.
+ [::Array, ::SOAP::SOAPArray, ArrayFactory],
+
+ [::Hash, ::SOAP::SOAPStruct, HashFactory],
+ [::SOAP::Mapping::SOAPException,
+ ::SOAP::SOAPStruct, TypedStructFactory,
+ {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
+ ]
+
+ def initialize(config = {})
+ @config = config
+ @map = Map.new(self)
+ if @config[:allow_original_mapping]
+ allow_original_mapping = true
+ @map.init(RubyOriginalMap)
+ else
+ allow_original_mapping = false
+ @map.init(SOAPBaseMap)
+ end
+
+ allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
+ @config[:allow_untyped_struct] : true
+ @rubytype_factory = RubytypeFactory.new(
+ :allow_untyped_struct => allow_untyped_struct,
+ :allow_original_mapping => allow_original_mapping
+ )
+ @default_factory = @rubytype_factory
+ @excn_handler_obj2soap = nil
+ @excn_handler_soap2obj = nil
+ end
+
+ def add(obj_class, soap_class, factory, info = nil)
+ @map.add(obj_class, soap_class, factory, info)
+ end
+ alias :set :add
+
+ # This mapping registry ignores type hint.
+ def obj2soap(klass, obj, type = nil)
+ ret = nil
+ if obj.is_a?(SOAPStruct) || obj.is_a?(SOAPArray)
+ obj.replace do |ele|
+ Mapping._obj2soap(ele, self)
+ end
+ return obj
+ elsif obj.is_a?(SOAPBasetype)
+ return obj
+ end
+ begin
+ ret = @map.obj2soap(klass, obj) ||
+ @default_factory.obj2soap(klass, obj, nil, self)
+ rescue MappingError
+ end
+ return ret if ret
+
+ if @excn_handler_obj2soap
+ ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
+ Mapping._obj2soap(yield_obj, self)
+ }
+ end
+ return ret if ret
+
+ raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
+ end
+
+ def soap2obj(klass, node)
+ if node.extraattr.key?(RubyTypeName)
+ conv, obj = @rubytype_factory.soap2obj(klass, node, nil, self)
+ return obj if conv
+ else
+ conv, obj = @map.soap2obj(klass, node)
+ return obj if conv
+ conv, obj = @default_factory.soap2obj(klass, node, nil, self)
+ return obj if conv
+ 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
+
+ def default_factory=(factory)
+ @default_factory = factory
+ end
+
+ def excn_handler_obj2soap=(handler)
+ @excn_handler_obj2soap = handler
+ end
+
+ def excn_handler_soap2obj=(handler)
+ @excn_handler_soap2obj = handler
+ end
+
+ def find_mapped_soap_class(obj_class)
+ @map.find_mapped_soap_class(obj_class)
+ end
+
+ def find_mapped_obj_class(soap_class)
+ @map.find_mapped_obj_class(soap_class)
+ end
+end
+
+
+DefaultRegistry = Registry.new
+RubyOriginalRegistry = Registry.new(:allow_original_mapping => true)
+
+
+end
+end
diff --git a/lib/soap/mapping/rubytypeFactory.rb b/lib/soap/mapping/rubytypeFactory.rb
new file mode 100644
index 0000000000..0a3f502dfe
--- /dev/null
+++ b/lib/soap/mapping/rubytypeFactory.rb
@@ -0,0 +1,437 @@
+=begin
+SOAP4R - Ruby type mapping factory.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+module Mapping
+
+
+class RubytypeFactory < Factory
+ TYPE_STRING = 'String'
+ TYPE_ARRAY = 'Array'
+ TYPE_REGEXP = 'Regexp'
+ TYPE_RANGE = 'Range'
+ TYPE_CLASS = 'Class'
+ TYPE_MODULE = 'Module'
+ TYPE_SYMBOL = 'Symbol'
+ TYPE_STRUCT = 'Struct'
+ TYPE_HASH = 'Map'
+
+ def initialize(config = {})
+ @config = config
+ @allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
+ @config[:allow_untyped_struct] : true
+ @allow_original_mapping = @config.key?(:allow_original_mapping) ?
+ @config[:allow_original_mapping] : false
+ end
+
+ def obj2soap(soap_class, obj, info, map)
+ param = nil
+ case obj
+ when String
+ unless @allow_original_mapping
+ return nil
+ end
+ unless XSD::Charset.is_ces(obj, $KCODE)
+ return nil
+ end
+ encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRING))
+ mark_marshalled_obj(obj, param)
+ param.add('string', SOAPString.new(encoded))
+ if obj.class != String
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ addiv2soap(param, obj, map)
+ when Array
+ unless @allow_original_mapping
+ return nil
+ end
+ arytype = Mapping.obj2element(obj)
+ if arytype.name
+ arytype.namespace ||= RubyTypeNamespace
+ else
+ arytype = XSD::AnyTypeName
+ end
+ if obj.instance_variables.empty?
+ param = SOAPArray.new(ValueArrayName, 1, arytype)
+ mark_marshalled_obj(obj, param)
+ obj.each do |var|
+ param.add(Mapping._obj2soap(var, map))
+ end
+ else
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_ARRAY))
+ mark_marshalled_obj(obj, param)
+ ary = SOAPArray.new(ValueArrayName, 1, arytype)
+ obj.each do |var|
+ ary.add(Mapping._obj2soap(var, map))
+ end
+ param.add('array', ary)
+ addiv2soap(param, obj, map)
+ end
+ if obj.class != Array
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ when Regexp
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_REGEXP))
+ mark_marshalled_obj(obj, param)
+ if obj.class != Regexp
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ param.add('source', SOAPBase64.new(obj.source))
+ if obj.respond_to?('options')
+ # Regexp#options is from Ruby/1.7
+ options = obj.options
+ else
+ options = 0
+ obj.inspect.sub(/^.*\//, '').each_byte do |c|
+ options += case c
+ when ?i
+ 1
+ when ?x
+ 2
+ when ?m
+ 4
+ when ?n
+ 16
+ when ?e
+ 32
+ when ?s
+ 48
+ when ?u
+ 64
+ end
+ end
+ end
+ param.add('options', SOAPInt.new(options))
+ addiv2soap(param, obj, map)
+ when Range
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_RANGE))
+ mark_marshalled_obj(obj, param)
+ if obj.class != Range
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ param.add('begin', Mapping._obj2soap(obj.begin, map))
+ param.add('end', Mapping._obj2soap(obj.end, map))
+ param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?))
+ addiv2soap(param, obj, map)
+ when Hash
+ unless @allow_original_mapping
+ return nil
+ end
+ if obj.respond_to?(:default_proc) && obj.default_proc
+ raise TypeError.new("cannot dump hash with default proc")
+ end
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_HASH))
+ mark_marshalled_obj(obj, param)
+ if obj.class != Hash
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ obj.each do |key, value|
+ elem = SOAPStruct.new # Undefined type.
+ elem.add("key", Mapping._obj2soap(key, map))
+ elem.add("value", Mapping._obj2soap(value, map))
+ param.add("item", elem)
+ end
+ param.add('default', Mapping._obj2soap(obj.default, map))
+ addiv2soap(param, obj, map)
+ when Class
+ if obj.name.empty?
+ raise TypeError.new("Can't dump anonymous class #{ obj }.")
+ end
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_CLASS))
+ mark_marshalled_obj(obj, param)
+ param.add('name', SOAPString.new(obj.name))
+ addiv2soap(param, obj, map)
+ when Module
+ if obj.name.empty?
+ raise TypeError.new("Can't dump anonymous module #{ obj }.")
+ end
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_MODULE))
+ mark_marshalled_obj(obj, param)
+ param.add('name', SOAPString.new(obj.name))
+ addiv2soap(param, obj, map)
+ when Symbol
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_SYMBOL))
+ mark_marshalled_obj(obj, param)
+ param.add('id', SOAPString.new(obj.id2name))
+ addiv2soap(param, obj, map)
+ when Exception
+ typestr = Mapping.name2elename(obj.class.to_s)
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr))
+ mark_marshalled_obj(obj, param)
+ param.add('message', Mapping._obj2soap(obj.message, map))
+ param.add('backtrace', Mapping._obj2soap(obj.backtrace, map))
+ addiv2soap(param, obj, map)
+ when Struct
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRUCT))
+ mark_marshalled_obj(obj, param)
+ param.add('type', ele_type = SOAPString.new(obj.class.to_s))
+ ele_member = SOAPStruct.new
+ obj.members.each do |member|
+ ele_member.add(Mapping.name2elename(member),
+ Mapping._obj2soap(obj[member], map))
+ end
+ param.add('member', ele_member)
+ addiv2soap(param, obj, map)
+ when IO, Binding, Continuation, Data, Dir, File::Stat, MatchData, Method,
+ Proc, Thread, ThreadGroup
+ return nil
+ when ::SOAP::Mapping::Object
+ param = SOAPStruct.new(XSD::AnyTypeName)
+ mark_marshalled_obj(obj, param)
+ setiv2soap(param, obj, map) # addiv2soap?
+ else
+ if obj.class.name.empty?
+ raise TypeError.new("Can't dump anonymous class #{ obj }.")
+ end
+ if check_singleton(obj)
+ raise TypeError.new("singleton can't be dumped #{ obj }")
+ end
+ type = Mapping.class2element(obj.class)
+ param = SOAPStruct.new(type)
+ mark_marshalled_obj(obj, param)
+ if obj.class <= Marshallable
+ setiv2soap(param, obj, map)
+ else
+ setiv2soap(param, obj, map) # Should not be marshalled?
+ end
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ rubytype = node.extraattr[RubyTypeName]
+ if rubytype or node.type.namespace == RubyTypeNamespace
+ rubytype2obj(node, map, rubytype)
+ elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName
+ anytype2obj(node, map)
+ else
+ unknowntype2obj(node, map)
+ end
+ end
+
+private
+
+ def check_singleton(obj)
+ unless singleton_methods_true(obj).empty?
+ return true
+ end
+ singleton_class = class << obj; self; end
+ if !singleton_class.instance_variables.empty? or
+ !(singleton_class.ancestors - obj.class.ancestors).empty?
+ return true
+ end
+ false
+ end
+
+ if RUBY_VERSION >= '1.8.0'
+ def singleton_methods_true(obj)
+ obj.singleton_methods(true)
+ end
+ else
+ def singleton_methods_true(obj)
+ obj.singleton_methods
+ end
+ end
+
+ def rubytype2obj(node, map, rubytype)
+ obj = nil
+ case node.class
+ when SOAPString
+ obj = string2obj(node, map, rubytype)
+ obj.replace(node.data)
+ return true, obj
+ when SOAPArray
+ obj = array2obj(node, map, rubytype)
+ node.soap2array(obj) do |elem|
+ elem ? Mapping._soap2obj(elem, map) : nil
+ end
+ return true, obj
+ end
+
+ case node.type.name
+ when TYPE_STRING
+ obj = string2obj(node, map, rubytype)
+ obj.replace(node['string'].data)
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_ARRAY
+ obj = array2obj(node, map, rubytype)
+ node['array'].soap2array(obj) do |elem|
+ elem ? Mapping._soap2obj(elem, map) : nil
+ end
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_REGEXP
+ klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ source = node['source'].string
+ options = node['options'].data || 0
+ obj.instance_eval { initialize(source, options) }
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_RANGE
+ klass = rubytype ? Mapping.class_from_name(rubytype) : Range
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ first = Mapping._soap2obj(node['begin'], map)
+ last = Mapping._soap2obj(node['end'], map)
+ exclude_end = node['exclude_end'].data
+ obj.instance_eval { initialize(first, last, exclude_end) }
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_HASH
+ unless @allow_original_mapping
+ return false
+ end
+ klass = rubytype ? Mapping.class_from_name(rubytype) : Hash
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ node.each do |key, value|
+ next unless key == 'item'
+ obj[Mapping._soap2obj(value['key'], map)] =
+ Mapping._soap2obj(value['value'], map)
+ end
+ if node.key?('default')
+ obj.default = Mapping._soap2obj(node['default'], map)
+ end
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_CLASS
+ obj = Mapping.class_from_name(node['name'].data)
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_MODULE
+ obj = Mapping.class_from_name(node['name'].data)
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_SYMBOL
+ obj = node['id'].data.intern
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_STRUCT
+ typestr = Mapping.elename2name(node['type'].data)
+ klass = Mapping.class_from_name(typestr)
+ if klass.nil?
+ klass = Mapping.class_from_name(name2typename(typestr))
+ end
+ if klass.nil?
+ return false
+ end
+ unless klass <= ::Struct
+ return false
+ end
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ node['member'].each do |name, value|
+ obj[Mapping.elename2name(name)] =
+ Mapping._soap2obj(value, map)
+ end
+ setiv2obj(obj, node['ivars'], map)
+ else
+ conv, obj = exception2obj(node, map)
+ unless conv
+ return false
+ end
+ setiv2obj(obj, node['ivars'], map)
+ end
+ return true, obj
+ end
+
+ def exception2obj(node, map)
+ typestr = Mapping.elename2name(node.type.name)
+ klass = Mapping.class_from_name(typestr)
+ if klass.nil?
+ return false
+ end
+ unless klass <= Exception
+ return false
+ end
+ message = Mapping._soap2obj(node['message'], map)
+ backtrace = Mapping._soap2obj(node['backtrace'], map)
+ obj = create_empty_object(klass)
+ obj = obj.exception(message)
+ mark_unmarshalled_obj(node, obj)
+ obj.set_backtrace(backtrace)
+ setiv2obj(obj, node['ivars'], map)
+ return true, obj
+ end
+
+ def anytype2obj(node, map)
+ case node
+ when SOAPBasetype
+ return true, node.data
+ when SOAPStruct
+ klass = ::SOAP::Mapping::Object
+ obj = klass.new
+ mark_unmarshalled_obj(node, obj)
+ node.each do |name, value|
+ obj.set_property(name, Mapping._soap2obj(value, map))
+ end
+ return true, obj
+ else
+ return false
+ end
+ end
+
+ def unknowntype2obj(node, map)
+ if node.is_a?(SOAPStruct)
+ obj = struct2obj(node, map)
+ return true, obj if obj
+ if !@allow_untyped_struct
+ return false
+ end
+ return anytype2obj(node, map)
+ else
+ # Basetype which is not defined...
+ return false
+ end
+ end
+
+ def struct2obj(node, map)
+ obj = nil
+ typestr = Mapping.elename2name(node.type.name)
+ klass = Mapping.class_from_name(typestr)
+ if klass.nil?
+ klass = Mapping.class_from_name(name2typename(typestr))
+ end
+ if klass.nil?
+ return nil
+ end
+ klass_type = Mapping.class2qname(klass)
+ return nil unless node.type.match(klass_type)
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ setiv2obj(obj, node, map)
+ obj
+ end
+
+ # Only creates empty array. Do String#replace it with real string.
+ def array2obj(node, map, rubytype)
+ klass = rubytype ? Mapping.class_from_name(rubytype) : Array
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ obj
+ end
+
+ # Only creates empty string. Do String#replace it with real string.
+ def string2obj(node, map, rubytype)
+ klass = rubytype ? Mapping.class_from_name(rubytype) : String
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ obj
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/mapping/typeMap.rb b/lib/soap/mapping/typeMap.rb
new file mode 100644
index 0000000000..c62f1482c1
--- /dev/null
+++ b/lib/soap/mapping/typeMap.rb
@@ -0,0 +1,52 @@
+=begin
+SOAP4R - Base type mapping definition
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+
+
+TypeMap = {
+ XSD::XSDAnySimpleType::Type => SOAPAnySimpleType,
+ XSD::XSDString::Type => SOAPString,
+ XSD::XSDBoolean::Type => SOAPBoolean,
+ XSD::XSDDecimal::Type => SOAPDecimal,
+ XSD::XSDFloat::Type => SOAPFloat,
+ XSD::XSDDouble::Type => SOAPDouble,
+ XSD::XSDDuration::Type => SOAPDuration,
+ XSD::XSDDateTime::Type => SOAPDateTime,
+ XSD::XSDTime::Type => SOAPTime,
+ XSD::XSDDate::Type => SOAPDate,
+ XSD::XSDGYearMonth::Type => SOAPGYearMonth,
+ XSD::XSDGYear::Type => SOAPGYear,
+ XSD::XSDGMonthDay::Type => SOAPGMonthDay,
+ XSD::XSDGDay::Type => SOAPGDay,
+ XSD::XSDGMonth::Type => SOAPGMonth,
+ XSD::XSDHexBinary::Type => SOAPHexBinary,
+ XSD::XSDBase64Binary::Type => SOAPBase64,
+ XSD::XSDAnyURI::Type => SOAPAnyURI,
+ XSD::XSDQName::Type => SOAPQName,
+ XSD::XSDInteger::Type => SOAPInteger,
+ XSD::XSDLong::Type => SOAPLong,
+ XSD::XSDInt::Type => SOAPInt,
+ XSD::XSDShort::Type => SOAPShort,
+
+ SOAP::SOAPBase64::Type => SOAPBase64,
+}
+
+
+end
diff --git a/lib/soap/mapping/wsdlRegistry.rb b/lib/soap/mapping/wsdlRegistry.rb
new file mode 100644
index 0000000000..4b5beabe72
--- /dev/null
+++ b/lib/soap/mapping/wsdlRegistry.rb
@@ -0,0 +1,146 @@
+=begin
+SOAP4R - WSDL mapping registry.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/baseData'
+require 'soap/mapping/mapping'
+require 'soap/mapping/typeMap'
+
+
+module SOAP
+module Mapping
+
+
+class WSDLRegistry
+ include TraverseSupport
+
+ attr_reader :complextypes
+
+ def initialize(complextypes, config = {})
+ @complextypes = complextypes
+ @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(klass, obj, type_qname)
+ soap_obj = nil
+ if obj.nil?
+ soap_obj = SOAPNil.new
+ elsif obj.is_a?(XSD::NSDBase)
+ soap_obj = soap2soap(obj, type_qname)
+ elsif (type = @complextypes[type_qname])
+ case type.compoundtype
+ when :TYPE_STRUCT
+ soap_obj = struct2soap(obj, type_qname, type)
+ when :TYPE_ARRAY
+ soap_obj = array2soap(obj, type_qname, type)
+ end
+ elsif (type = TypeMap[type_qname])
+ soap_obj = base2soap(obj, type)
+ elsif type_qname == XSD::AnyTypeName
+ soap_obj = @rubytype_factory.obj2soap(nil, obj, nil, nil)
+ 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)
+ }
+ end
+ return soap_obj if soap_obj
+
+ raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
+ end
+
+ def soap2obj(klass, node)
+ raise RuntimeError.new("#{ self } is for obj2soap only.")
+ end
+
+ def excn_handler_obj2soap=(handler)
+ @excn_handler_obj2soap = handler
+ end
+
+private
+
+ def soap2soap(obj, type_qname)
+ if obj.is_a?(SOAPBasetype)
+ obj
+ elsif obj.is_a?(SOAPStruct) && (type = @complextypes[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 = @complextypes[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 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)
+ contenttype = type.child_type
+ soap_obj = SOAPArray.new(ValueArrayName, 1, contenttype)
+ mark_marshalled_obj(obj, soap_obj)
+ obj.each do |item|
+ soap_obj.add(Mapping._obj2soap(item, self, contenttype))
+ 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