mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
e5a3aba50e
* lib/soap/mapping/wsdl*.rb * lib/wsdl/soap/element.rb * lib/wsdl/xmlSchema/simpleContent.rb * modified files: * lib/soap/* * lib/wsdl/* * lib/xsd/* * test/soap/* * test/wsdl/* * test/xsd/* * summary * imported from the soap4r repository. Version: 1.5.3-ruby1.8.2 * added several XSD basetype support: nonPositiveInteger, negativeInteger, nonNegativeInteger, unsignedLong, unsignedInt, unsignedShort, unsignedByte, positiveInteger * HTTP client connection/send/receive timeout support. * HTTP client/server gzipped content encoding support. * improved WSDL schema definition support; still is far from complete, but is making step by step improovement. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@7612 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
281 lines
7.5 KiB
Ruby
281 lines
7.5 KiB
Ruby
# 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
|