1
# SOAP4R - WSDL encoded mapping registry.
2
# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
4
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
# redistribute it and/or modify it under the same terms of Ruby's license;
6
# either the dual license version in 2003, or any later version.
10
require 'xsd/namedelements'
11
require 'soap/baseData'
12
require 'soap/mapping/mapping'
13
require 'soap/mapping/typeMap'
20
class WSDLEncodedRegistry < Registry
21
include TraverseSupport
23
attr_reader :definedelements
24
attr_reader :definedtypes
25
attr_accessor :excn_handler_obj2soap
26
attr_accessor :excn_handler_soap2obj
28
def initialize(definedtypes = XSD::NamedElements::Empty)
29
@definedtypes = definedtypes
30
# @definedelements = definedelements needed?
31
@excn_handler_obj2soap = nil
32
@excn_handler_soap2obj = nil
33
# For mapping AnyType element.
34
@rubytype_factory = RubytypeFactory.new(
35
:allow_untyped_struct => true,
36
:allow_original_mapping => true
38
@schema_element_cache = {}
41
def obj2soap(obj, qname = nil)
43
if type = @definedtypes[qname]
44
soap_obj = obj2typesoap(obj, type)
46
soap_obj = any2soap(obj, qname)
48
return soap_obj if soap_obj
49
if @excn_handler_obj2soap
50
soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj|
51
Mapping._obj2soap(yield_obj, self)
53
return soap_obj if soap_obj
56
raise MappingError.new("cannot map #{obj.class.name} as #{qname}")
58
raise MappingError.new("cannot map #{obj.class.name} to SOAP/OM")
62
# map anything for now: must refer WSDL while mapping. [ToDo]
63
def soap2obj(node, obj_class = nil)
65
return any2obj(node, obj_class)
68
if @excn_handler_soap2obj
70
return @excn_handler_soap2obj.call(node) { |yield_node|
71
Mapping._soap2obj(yield_node, self)
76
raise MappingError.new("cannot map #{node.type.name} to Ruby object")
81
def any2soap(obj, qname)
84
elsif qname.nil? or qname == XSD::AnyTypeName
85
@rubytype_factory.obj2soap(nil, obj, nil, self)
86
elsif obj.is_a?(XSD::NSDBase)
88
elsif (type = TypeMap[qname])
95
def soap2soap(obj, type_qname)
96
if obj.is_a?(SOAPBasetype)
98
elsif obj.is_a?(SOAPStruct) && (type = @definedtypes[type_qname])
100
mark_marshalled_obj(obj, soap_obj)
101
elements2soap(obj, soap_obj, type.content.elements)
103
elsif obj.is_a?(SOAPArray) && (type = @definedtypes[type_qname])
105
contenttype = type.child_type
106
mark_marshalled_obj(obj, soap_obj)
108
Mapping._obj2soap(ele, self, contenttype)
116
def obj2typesoap(obj, type)
117
if type.is_a?(::WSDL::XMLSchema::SimpleType)
118
simpleobj2soap(obj, type)
120
complexobj2soap(obj, type)
124
def simpleobj2soap(obj, type)
125
type.check_lexical_format(obj)
126
return SOAPNil.new if obj.nil? # ToDo: check nillable.
127
o = base2soap(obj, TypeMap[type.base])
131
def complexobj2soap(obj, type)
132
case type.compoundtype
134
struct2soap(obj, type.name, type)
136
array2soap(obj, type.name, type)
138
map2soap(obj, type.name, type)
140
simpleobj2soap(obj, type.simplecontent)
142
raise MappingError.new("should be empty") unless obj.nil?
145
raise MappingError.new("unknown compound type: #{type.compoundtype}")
149
def base2soap(obj, type)
151
if type <= XSD::XSDString
152
str = XSD::Charset.encoding_conv(obj.to_s,
153
Thread.current[:SOAPExternalCES], XSD::Charset.encoding)
154
soap_obj = type.new(str)
155
mark_marshalled_obj(obj, soap_obj)
157
soap_obj = type.new(obj)
162
def struct2soap(obj, type_qname, type)
163
return SOAPNil.new if obj.nil? # ToDo: check nillable.
164
soap_obj = SOAPStruct.new(type_qname)
166
mark_marshalled_obj(obj, soap_obj)
167
elements2soap(obj, soap_obj, type.content.elements)
172
def array2soap(obj, type_qname, type)
173
return SOAPNil.new if obj.nil? # ToDo: check nillable.
174
arytype = type.child_type
175
soap_obj = SOAPArray.new(ValueArrayName, 1, arytype)
177
mark_marshalled_obj(obj, soap_obj)
179
soap_obj.add(Mapping._obj2soap(item, self, arytype))
185
MapKeyName = XSD::QName.new(nil, "key")
186
MapValueName = XSD::QName.new(nil, "value")
187
def map2soap(obj, type_qname, type)
188
return SOAPNil.new if obj.nil? # ToDo: check nillable.
189
keytype = type.child_type(MapKeyName) || XSD::AnyTypeName
190
valuetype = type.child_type(MapValueName) || XSD::AnyTypeName
191
soap_obj = SOAPStruct.new(MapQName)
193
mark_marshalled_obj(obj, soap_obj)
194
obj.each do |key, value|
195
elem = SOAPStruct.new
196
elem.add("key", Mapping._obj2soap(key, self, keytype))
197
elem.add("value", Mapping._obj2soap(value, self, valuetype))
198
# ApacheAxis allows only 'item' here.
199
soap_obj.add("item", elem)
205
def elements2soap(obj, soap_obj, elements)
206
elements.each do |element|
207
name = element.name.name
208
child_obj = Mapping.get_attribute(obj, name)
210
Mapping._obj2soap(child_obj, self, element.type || element.name))
214
def any2obj(node, obj_class)
216
typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name)
217
obj_class = Mapping.class_from_name(typestr)
219
if obj_class and obj_class.class_variables.include?('@@schema_element')
220
soap2stubobj(node, obj_class)
222
Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class)
226
def soap2stubobj(node, obj_class)
227
obj = Mapping.create_empty_object(obj_class)
228
unless node.is_a?(SOAPNil)
229
add_elements2stubobj(node, obj)
234
def add_elements2stubobj(node, obj)
235
elements, as_array = schema_element_definition(obj.class)
237
node.each do |name, value|
238
item = elements.find { |k, v| k.name == name }
240
elename, class_name = item
241
if klass = Mapping.class_from_name(class_name)
242
# klass must be a SOAPBasetype or a class
243
if klass.ancestors.include?(::SOAP::SOAPBasetype)
244
if value.respond_to?(:data)
245
child = klass.new(value.data).data
247
child = klass.new(nil).data
250
child = Mapping._soap2obj(value, self, klass)
252
elsif klass = Mapping.module_from_name(class_name)
254
if value.respond_to?(:data)
257
raise MappingError.new(
258
"cannot map to a module value: #{class_name}")
261
raise MappingError.new("unknown class: #{class_name}")
263
else # untyped element is treated as anyType.
264
child = Mapping._soap2obj(value, self)
268
Mapping.set_attributes(obj, vars)
271
# it caches @@schema_element. this means that @@schema_element must not be
272
# changed while a lifetime of a WSDLLiteralRegistry.
273
def schema_element_definition(klass)
274
@schema_element_cache[klass] ||= Mapping.schema_element_definition(klass)