1
# SOAP4R - Mapping registry.
2
# Copyright (C) 2000, 2001, 2002, 2003 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.
9
require 'soap/baseData'
10
require 'soap/mapping/mapping'
11
require 'soap/mapping/typeMap'
12
require 'soap/mapping/factory'
13
require 'soap/mapping/rubytypeFactory'
20
# @@type_ns = Mapping::RubyCustomTypeNamespace
27
module MappedException; end
30
RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
31
RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends')
32
RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars')
35
# Inner class to pass an exception.
36
class SOAPException; include Marshallable
37
attr_reader :excn_type_name, :cause
39
@excn_type_name = Mapping.name2elename(e.class.to_s)
44
if @cause.is_a?(::Exception)
45
@cause.extend(::SOAP::Mapping::MappedException)
47
elsif @cause.respond_to?(:message) and @cause.respond_to?(:backtrace)
48
e = RuntimeError.new(@cause.message)
49
e.set_backtrace(@cause.backtrace)
52
klass = Mapping.class_from_name(Mapping.elename2name(@excn_type_name.to_s))
53
if klass.nil? or not klass <= ::Exception
54
return RuntimeError.new(@cause.inspect)
56
obj = klass.new(@cause.message)
57
obj.extend(::SOAP::Mapping::MappedException)
63
# For anyType object: SOAP::Mapping::Object not ::Object
64
class Object; include Marshallable
72
sprintf("#<%s:0x%x%s>", self.class.name, __id__,
73
@__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join)
85
unless qname.is_a?(XSD::QName)
86
qname = XSD::QName.new(nil, qname)
88
@__xmlele.each do |k, v|
89
return v if k == qname
92
@__xmlele.each do |k, v|
93
return v if k.name == qname.name
99
unless qname.is_a?(XSD::QName)
100
qname = XSD::QName.new(nil, qname)
103
@__xmlele.each do |pair|
110
__define_attr_accessor(qname)
111
@__xmlele << [qname, value]
113
@__xmlele_type[qname] = :single
116
def __add_xmlele_value(qname, value)
118
@__xmlele.map! do |k, v|
121
[k, __set_xmlele_value(k, v, value)]
127
__define_attr_accessor(qname)
128
@__xmlele << [qname, value]
129
@__xmlele_type[qname] = :single
136
if RUBY_VERSION > "1.7.0"
137
def __define_attr_accessor(qname)
138
name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
139
Mapping.define_attr_accessor(self, name,
140
proc { self[qname] },
141
proc { |value| self[qname] = value })
144
def __define_attr_accessor(qname)
145
name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
152
self[#{qname.dump}] = value
158
def __set_xmlele_value(key, org, value)
159
case @__xmlele_type[key]
164
@__xmlele_type[key] = :multi
167
raise RuntimeError.new("unknown type")
173
class MappingError < Error; end
178
def initialize(registry)
186
if map = @obj2soap[klass]
187
map.each do |soap_class, factory, info|
188
ret = factory.obj2soap(soap_class, obj, info, @registry)
192
ancestors = klass.ancestors
193
ancestors.delete(klass)
194
ancestors.delete(::Object)
195
ancestors.delete(::Kernel)
196
ancestors.each do |klass|
197
if map = @obj2soap[klass]
198
map.each do |soap_class, factory, info|
199
if info[:derived_class]
200
ret = factory.obj2soap(soap_class, obj, info, @registry)
209
def soap2obj(node, klass = nil)
210
if map = @soap2obj[node.class]
211
map.each do |obj_class, factory, info|
212
next if klass and obj_class != klass
213
conv, obj = factory.soap2obj(obj_class, node, info, @registry)
214
return true, obj if conv
220
# Give priority to former entry.
221
def init(init_map = [])
223
init_map.reverse_each do |obj_class, soap_class, factory, info|
224
add(obj_class, soap_class, factory, info)
228
# Give priority to latter entry.
229
def add(obj_class, soap_class, factory, info)
231
(@obj2soap[obj_class] ||= []).unshift([soap_class, factory, info])
232
(@soap2obj[soap_class] ||= []).unshift([obj_class, factory, info])
240
def find_mapped_soap_class(target_obj_class)
241
map = @obj2soap[target_obj_class]
242
map.empty? ? nil : map[0][1]
245
def find_mapped_obj_class(target_soap_class)
246
map = @soap2obj[target_soap_class]
247
map.empty? ? nil : map[0][0]
251
StringFactory = StringFactory_.new
252
BasetypeFactory = BasetypeFactory_.new
253
DateTimeFactory = DateTimeFactory_.new
254
ArrayFactory = ArrayFactory_.new
255
Base64Factory = Base64Factory_.new
256
URIFactory = URIFactory_.new
257
TypedArrayFactory = TypedArrayFactory_.new
258
TypedStructFactory = TypedStructFactory_.new
260
HashFactory = HashFactory_.new
263
[::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
264
[::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
265
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
266
[::String, ::SOAP::SOAPString, StringFactory],
267
[::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
268
[::Date, ::SOAP::SOAPDate, DateTimeFactory],
269
[::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
270
[::Time, ::SOAP::SOAPTime, DateTimeFactory],
271
[::Float, ::SOAP::SOAPDouble, BasetypeFactory,
272
{:derived_class => true}],
273
[::Float, ::SOAP::SOAPFloat, BasetypeFactory,
274
{:derived_class => true}],
275
[::Integer, ::SOAP::SOAPInt, BasetypeFactory,
276
{:derived_class => true}],
277
[::Integer, ::SOAP::SOAPLong, BasetypeFactory,
278
{:derived_class => true}],
279
[::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
280
{:derived_class => true}],
281
[::Integer, ::SOAP::SOAPShort, BasetypeFactory,
282
{:derived_class => true}],
283
[::Integer, ::SOAP::SOAPByte, BasetypeFactory,
284
{:derived_class => true}],
285
[::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory,
286
{:derived_class => true}],
287
[::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory,
288
{:derived_class => true}],
289
[::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory,
290
{:derived_class => true}],
291
[::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory,
292
{:derived_class => true}],
293
[::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory,
294
{:derived_class => true}],
295
[::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory,
296
{:derived_class => true}],
297
[::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory,
298
{:derived_class => true}],
299
[::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory,
300
{:derived_class => true}],
301
[::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory,
302
{:derived_class => true}],
303
[::String, ::SOAP::SOAPBase64, Base64Factory],
304
[::String, ::SOAP::SOAPHexBinary, Base64Factory],
305
[::String, ::SOAP::SOAPDecimal, BasetypeFactory],
306
[::String, ::SOAP::SOAPDuration, BasetypeFactory],
307
[::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
308
[::String, ::SOAP::SOAPGYear, BasetypeFactory],
309
[::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
310
[::String, ::SOAP::SOAPGDay, BasetypeFactory],
311
[::String, ::SOAP::SOAPGMonth, BasetypeFactory],
312
[::String, ::SOAP::SOAPQName, BasetypeFactory],
314
[::Hash, ::SOAP::SOAPArray, HashFactory],
315
[::Hash, ::SOAP::SOAPStruct, HashFactory],
317
[::Array, ::SOAP::SOAPArray, ArrayFactory,
318
{:derived_class => true}],
320
[::SOAP::Mapping::SOAPException,
321
::SOAP::SOAPStruct, TypedStructFactory,
322
{:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
326
[::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
327
[::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
328
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
329
[::String, ::SOAP::SOAPString, StringFactory],
330
[::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
331
[::Date, ::SOAP::SOAPDate, DateTimeFactory],
332
[::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
333
[::Time, ::SOAP::SOAPTime, DateTimeFactory],
334
[::Float, ::SOAP::SOAPDouble, BasetypeFactory,
335
{:derived_class => true}],
336
[::Float, ::SOAP::SOAPFloat, BasetypeFactory,
337
{:derived_class => true}],
338
[::Integer, ::SOAP::SOAPInt, BasetypeFactory,
339
{:derived_class => true}],
340
[::Integer, ::SOAP::SOAPLong, BasetypeFactory,
341
{:derived_class => true}],
342
[::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
343
{:derived_class => true}],
344
[::Integer, ::SOAP::SOAPShort, BasetypeFactory,
345
{:derived_class => true}],
346
[::Integer, ::SOAP::SOAPByte, BasetypeFactory,
347
{:derived_class => true}],
348
[::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory,
349
{:derived_class => true}],
350
[::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory,
351
{:derived_class => true}],
352
[::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory,
353
{:derived_class => true}],
354
[::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory,
355
{:derived_class => true}],
356
[::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory,
357
{:derived_class => true}],
358
[::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory,
359
{:derived_class => true}],
360
[::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory,
361
{:derived_class => true}],
362
[::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory,
363
{:derived_class => true}],
364
[::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory,
365
{:derived_class => true}],
366
[::String, ::SOAP::SOAPBase64, Base64Factory],
367
[::String, ::SOAP::SOAPHexBinary, Base64Factory],
368
[::String, ::SOAP::SOAPDecimal, BasetypeFactory],
369
[::String, ::SOAP::SOAPDuration, BasetypeFactory],
370
[::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
371
[::String, ::SOAP::SOAPGYear, BasetypeFactory],
372
[::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
373
[::String, ::SOAP::SOAPGDay, BasetypeFactory],
374
[::String, ::SOAP::SOAPGMonth, BasetypeFactory],
375
[::String, ::SOAP::SOAPQName, BasetypeFactory],
377
[::Hash, ::SOAP::SOAPArray, HashFactory],
378
[::Hash, ::SOAP::SOAPStruct, HashFactory],
380
# Does not allow Array's subclass here.
381
[::Array, ::SOAP::SOAPArray, ArrayFactory],
383
[::SOAP::Mapping::SOAPException,
384
::SOAP::SOAPStruct, TypedStructFactory,
385
{:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
388
attr_accessor :default_factory
389
attr_accessor :excn_handler_obj2soap
390
attr_accessor :excn_handler_soap2obj
392
def initialize(config = {})
395
if @config[:allow_original_mapping]
396
@allow_original_mapping = true
397
@map.init(RubyOriginalMap)
399
@allow_original_mapping = false
400
@map.init(SOAPBaseMap)
402
@allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
403
@config[:allow_untyped_struct] : true
404
@rubytype_factory = RubytypeFactory.new(
405
:allow_untyped_struct => @allow_untyped_struct,
406
:allow_original_mapping => @allow_original_mapping
408
@default_factory = @rubytype_factory
409
@excn_handler_obj2soap = nil
410
@excn_handler_soap2obj = nil
413
def add(obj_class, soap_class, factory, info = nil)
414
@map.add(obj_class, soap_class, factory, info)
418
# general Registry ignores type_qname
419
def obj2soap(obj, type_qname = nil)
420
soap = _obj2soap(obj)
421
if @allow_original_mapping
422
addextend2soap(soap, obj)
427
def soap2obj(node, klass = nil)
428
obj = _soap2obj(node, klass)
429
if @allow_original_mapping
430
addextend2obj(obj, node.extraattr[RubyExtendName])
431
addiv2obj(obj, node.extraattr[RubyIVarName])
436
def find_mapped_soap_class(obj_class)
437
@map.find_mapped_soap_class(obj_class)
440
def find_mapped_obj_class(soap_class)
441
@map.find_mapped_obj_class(soap_class)
448
if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray)
450
Mapping._obj2soap(ele, self)
453
elsif obj.is_a?(SOAPBasetype)
457
ret = @map.obj2soap(obj) ||
458
@default_factory.obj2soap(nil, obj, nil, self)
462
if @excn_handler_obj2soap
463
ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
464
Mapping._obj2soap(yield_obj, self)
468
raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.")
471
# Might return nil as a mapping result.
472
def _soap2obj(node, klass = nil)
473
if node.extraattr.key?(RubyTypeName)
474
conv, obj = @rubytype_factory.soap2obj(nil, node, nil, self)
477
conv, obj = @map.soap2obj(node, klass)
479
conv, obj = @default_factory.soap2obj(nil, node, nil, self)
482
if @excn_handler_soap2obj
484
return @excn_handler_soap2obj.call(node) { |yield_node|
485
Mapping._soap2obj(yield_node, self)
490
raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.")
493
def addiv2obj(obj, attr)
496
attr.__getobj__.each do |name, value|
497
vars[name] = Mapping._soap2obj(value, self)
499
Mapping.set_attributes(obj, vars)
502
if RUBY_VERSION >= '1.8.0'
503
def addextend2obj(obj, attr)
505
attr.split(/ /).reverse_each do |mstr|
506
obj.extend(Mapping.module_from_name(mstr))
510
# (class < false; self; end).ancestors includes "TrueClass" under 1.6...
511
def addextend2obj(obj, attr)
513
attr.split(/ /).reverse_each do |mstr|
514
m = Mapping.module_from_name(mstr)
520
def addextend2soap(node, obj)
521
return if obj.is_a?(Symbol) or obj.is_a?(Fixnum)
522
list = (class << obj; self; end).ancestors - obj.class.ancestors
524
node.extraattr[RubyExtendName] = list.collect { |c|
526
raise TypeError.new("singleton can't be dumped #{ obj }")
536
DefaultRegistry = Registry.new
537
RubyOriginalRegistry = Registry.new(:allow_original_mapping => true)