summaryrefslogtreecommitdiff
path: root/lib/soap/mapping/rubytypeFactory.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/soap/mapping/rubytypeFactory.rb')
-rw-r--r--lib/soap/mapping/rubytypeFactory.rb437
1 files changed, 437 insertions, 0 deletions
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