~ubuntu-branches/ubuntu/hardy/ruby1.8/hardy-updates

« back to all changes in this revision

Viewing changes to lib/soap/mapping/registry.rb

  • Committer: Bazaar Package Importer
  • Author(s): akira yamada
  • Date: 2007-03-13 22:11:58 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070313221158-h3oql37brlaf2go2
Tags: 1.8.6-1
* new upstream version, 1.8.6.
* libruby1.8 conflicts with libopenssl-ruby1.8 (< 1.8.6) (closes: #410018)
* changed packaging style to cdbs from dbs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# SOAP4R - Mapping registry.
 
2
# Copyright (C) 2000, 2001, 2002, 2003  NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
 
3
 
 
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.
 
7
 
 
8
 
 
9
require 'soap/baseData'
 
10
require 'soap/mapping/mapping'
 
11
require 'soap/mapping/typeMap'
 
12
require 'soap/mapping/factory'
 
13
require 'soap/mapping/rubytypeFactory'
 
14
 
 
15
 
 
16
module SOAP
 
17
 
 
18
 
 
19
module Marshallable
 
20
  # @@type_ns = Mapping::RubyCustomTypeNamespace
 
21
end
 
22
 
 
23
 
 
24
module Mapping
 
25
 
 
26
  
 
27
module MappedException; end
 
28
 
 
29
 
 
30
RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
 
31
RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends')
 
32
RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars')
 
33
 
 
34
 
 
35
# Inner class to pass an exception.
 
36
class SOAPException; include Marshallable
 
37
  attr_reader :excn_type_name, :cause
 
38
  def initialize(e)
 
39
    @excn_type_name = Mapping.name2elename(e.class.to_s)
 
40
    @cause = e
 
41
  end
 
42
 
 
43
  def to_e
 
44
    if @cause.is_a?(::Exception)
 
45
      @cause.extend(::SOAP::Mapping::MappedException)
 
46
      return @cause
 
47
    elsif @cause.respond_to?(:message) and @cause.respond_to?(:backtrace)
 
48
      e = RuntimeError.new(@cause.message)
 
49
      e.set_backtrace(@cause.backtrace)
 
50
      return e
 
51
    end
 
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)
 
55
    end
 
56
    obj = klass.new(@cause.message)
 
57
    obj.extend(::SOAP::Mapping::MappedException)
 
58
    obj
 
59
  end
 
60
end
 
61
 
 
62
 
 
63
# For anyType object: SOAP::Mapping::Object not ::Object
 
64
class Object; include Marshallable
 
65
  def initialize
 
66
    @__xmlele_type = {}
 
67
    @__xmlele = []
 
68
    @__xmlattr = {}
 
69
  end
 
70
 
 
71
  def inspect
 
72
    sprintf("#<%s:0x%x%s>", self.class.name, __id__,
 
73
      @__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join)
 
74
  end
 
75
 
 
76
  def __xmlattr
 
77
    @__xmlattr
 
78
  end
 
79
 
 
80
  def __xmlele
 
81
    @__xmlele
 
82
  end
 
83
 
 
84
  def [](qname)
 
85
    unless qname.is_a?(XSD::QName)
 
86
      qname = XSD::QName.new(nil, qname)
 
87
    end
 
88
    @__xmlele.each do |k, v|
 
89
      return v if k == qname
 
90
    end
 
91
    # fallback
 
92
    @__xmlele.each do |k, v|
 
93
      return v if k.name == qname.name
 
94
    end
 
95
    nil
 
96
  end
 
97
 
 
98
  def []=(qname, value)
 
99
    unless qname.is_a?(XSD::QName)
 
100
      qname = XSD::QName.new(nil, qname)
 
101
    end
 
102
    found = false
 
103
    @__xmlele.each do |pair|
 
104
      if pair[0] == qname
 
105
        found = true
 
106
        pair[1] = value
 
107
      end
 
108
    end
 
109
    unless found
 
110
      __define_attr_accessor(qname)
 
111
      @__xmlele << [qname, value]
 
112
    end
 
113
    @__xmlele_type[qname] = :single
 
114
  end
 
115
 
 
116
  def __add_xmlele_value(qname, value)
 
117
    found = false
 
118
    @__xmlele.map! do |k, v|
 
119
      if k == qname
 
120
        found = true
 
121
        [k, __set_xmlele_value(k, v, value)]
 
122
      else
 
123
        [k, v]
 
124
      end
 
125
    end
 
126
    unless found
 
127
      __define_attr_accessor(qname)
 
128
      @__xmlele << [qname, value]
 
129
      @__xmlele_type[qname] = :single
 
130
    end
 
131
    value
 
132
  end
 
133
 
 
134
private
 
135
 
 
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 })
 
142
    end
 
143
  else
 
144
    def __define_attr_accessor(qname)
 
145
      name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
 
146
      instance_eval <<-EOS
 
147
        def #{name}
 
148
          self[#{qname.dump}]
 
149
        end
 
150
 
 
151
        def #{name}=(value)
 
152
          self[#{qname.dump}] = value
 
153
        end
 
154
      EOS
 
155
    end
 
156
  end
 
157
 
 
158
  def __set_xmlele_value(key, org, value)
 
159
    case @__xmlele_type[key]
 
160
    when :multi
 
161
      org << value
 
162
      org
 
163
    when :single
 
164
      @__xmlele_type[key] = :multi
 
165
      [org, value]
 
166
    else
 
167
      raise RuntimeError.new("unknown type")
 
168
    end
 
169
  end
 
170
end
 
171
 
 
172
 
 
173
class MappingError < Error; end
 
174
 
 
175
 
 
176
class Registry
 
177
  class Map
 
178
    def initialize(registry)
 
179
      @obj2soap = {}
 
180
      @soap2obj = {}
 
181
      @registry = registry
 
182
    end
 
183
 
 
184
    def obj2soap(obj)
 
185
      klass = obj.class
 
186
      if map = @obj2soap[klass]
 
187
        map.each do |soap_class, factory, info|
 
188
          ret = factory.obj2soap(soap_class, obj, info, @registry)
 
189
          return ret if ret
 
190
        end
 
191
      end
 
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)
 
201
              return ret if ret
 
202
            end
 
203
          end
 
204
        end
 
205
      end
 
206
      nil
 
207
    end
 
208
 
 
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
 
215
        end
 
216
      end
 
217
      return false, nil
 
218
    end
 
219
 
 
220
    # Give priority to former entry.
 
221
    def init(init_map = [])
 
222
      clear
 
223
      init_map.reverse_each do |obj_class, soap_class, factory, info|
 
224
        add(obj_class, soap_class, factory, info)
 
225
      end
 
226
    end
 
227
 
 
228
    # Give priority to latter entry.
 
229
    def add(obj_class, soap_class, factory, info)
 
230
      info ||= {}
 
231
      (@obj2soap[obj_class] ||= []).unshift([soap_class, factory, info])
 
232
      (@soap2obj[soap_class] ||= []).unshift([obj_class, factory, info])
 
233
    end
 
234
 
 
235
    def clear
 
236
      @obj2soap.clear
 
237
      @soap2obj.clear
 
238
    end
 
239
 
 
240
    def find_mapped_soap_class(target_obj_class)
 
241
      map = @obj2soap[target_obj_class]
 
242
      map.empty? ? nil : map[0][1]
 
243
    end
 
244
 
 
245
    def find_mapped_obj_class(target_soap_class)
 
246
      map = @soap2obj[target_soap_class]
 
247
      map.empty? ? nil : map[0][0]
 
248
    end
 
249
  end
 
250
 
 
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
 
259
 
 
260
  HashFactory = HashFactory_.new
 
261
 
 
262
  SOAPBaseMap = [
 
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],
 
313
 
 
314
    [::Hash,         ::SOAP::SOAPArray,      HashFactory],
 
315
    [::Hash,         ::SOAP::SOAPStruct,     HashFactory],
 
316
 
 
317
    [::Array,        ::SOAP::SOAPArray,      ArrayFactory,
 
318
      {:derived_class => true}],
 
319
 
 
320
    [::SOAP::Mapping::SOAPException,
 
321
                     ::SOAP::SOAPStruct,     TypedStructFactory,
 
322
      {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
 
323
 ]
 
324
 
 
325
  RubyOriginalMap = [
 
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],
 
376
 
 
377
    [::Hash,         ::SOAP::SOAPArray,      HashFactory],
 
378
    [::Hash,         ::SOAP::SOAPStruct,     HashFactory],
 
379
 
 
380
    # Does not allow Array's subclass here.
 
381
    [::Array,        ::SOAP::SOAPArray,      ArrayFactory],
 
382
 
 
383
    [::SOAP::Mapping::SOAPException,
 
384
                     ::SOAP::SOAPStruct,     TypedStructFactory,
 
385
      {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
 
386
  ]
 
387
 
 
388
  attr_accessor :default_factory
 
389
  attr_accessor :excn_handler_obj2soap
 
390
  attr_accessor :excn_handler_soap2obj
 
391
 
 
392
  def initialize(config = {})
 
393
    @config = config
 
394
    @map = Map.new(self)
 
395
    if @config[:allow_original_mapping]
 
396
      @allow_original_mapping = true
 
397
      @map.init(RubyOriginalMap)
 
398
    else
 
399
      @allow_original_mapping = false
 
400
      @map.init(SOAPBaseMap)
 
401
    end
 
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
 
407
    )
 
408
    @default_factory = @rubytype_factory
 
409
    @excn_handler_obj2soap = nil
 
410
    @excn_handler_soap2obj = nil
 
411
  end
 
412
 
 
413
  def add(obj_class, soap_class, factory, info = nil)
 
414
    @map.add(obj_class, soap_class, factory, info)
 
415
  end
 
416
  alias set add
 
417
 
 
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)
 
423
    end
 
424
    soap
 
425
  end
 
426
 
 
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])
 
432
    end
 
433
    obj
 
434
  end
 
435
 
 
436
  def find_mapped_soap_class(obj_class)
 
437
    @map.find_mapped_soap_class(obj_class)
 
438
  end
 
439
 
 
440
  def find_mapped_obj_class(soap_class)
 
441
    @map.find_mapped_obj_class(soap_class)
 
442
  end
 
443
 
 
444
private
 
445
 
 
446
  def _obj2soap(obj)
 
447
    ret = nil
 
448
    if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray)
 
449
      obj.replace do |ele|
 
450
        Mapping._obj2soap(ele, self)
 
451
      end
 
452
      return obj
 
453
    elsif obj.is_a?(SOAPBasetype)
 
454
      return obj
 
455
    end
 
456
    begin 
 
457
      ret = @map.obj2soap(obj) ||
 
458
        @default_factory.obj2soap(nil, obj, nil, self)
 
459
      return ret if ret
 
460
    rescue MappingError
 
461
    end
 
462
    if @excn_handler_obj2soap
 
463
      ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
 
464
        Mapping._obj2soap(yield_obj, self)
 
465
      }
 
466
      return ret if ret
 
467
    end
 
468
    raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.")
 
469
  end
 
470
 
 
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)
 
475
      return obj if conv
 
476
    else
 
477
      conv, obj = @map.soap2obj(node, klass)
 
478
      return obj if conv
 
479
      conv, obj = @default_factory.soap2obj(nil, node, nil, self)
 
480
      return obj if conv
 
481
    end
 
482
    if @excn_handler_soap2obj
 
483
      begin
 
484
        return @excn_handler_soap2obj.call(node) { |yield_node|
 
485
            Mapping._soap2obj(yield_node, self)
 
486
          }
 
487
      rescue Exception
 
488
      end
 
489
    end
 
490
    raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.")
 
491
  end
 
492
 
 
493
  def addiv2obj(obj, attr)
 
494
    return unless attr
 
495
    vars = {}
 
496
    attr.__getobj__.each do |name, value|
 
497
      vars[name] = Mapping._soap2obj(value, self)
 
498
    end
 
499
    Mapping.set_attributes(obj, vars)
 
500
  end
 
501
 
 
502
  if RUBY_VERSION >= '1.8.0'
 
503
    def addextend2obj(obj, attr)
 
504
      return unless attr
 
505
      attr.split(/ /).reverse_each do |mstr|
 
506
        obj.extend(Mapping.module_from_name(mstr))
 
507
      end
 
508
    end
 
509
  else
 
510
    # (class < false; self; end).ancestors includes "TrueClass" under 1.6...
 
511
    def addextend2obj(obj, attr)
 
512
      return unless attr
 
513
      attr.split(/ /).reverse_each do |mstr|
 
514
        m = Mapping.module_from_name(mstr)
 
515
        obj.extend(m)
 
516
      end
 
517
    end
 
518
  end
 
519
 
 
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
 
523
    unless list.empty?
 
524
      node.extraattr[RubyExtendName] = list.collect { |c|
 
525
        if c.name.empty?
 
526
          raise TypeError.new("singleton can't be dumped #{ obj }")
 
527
        end
 
528
        c.name
 
529
      }.join(" ")
 
530
    end
 
531
  end
 
532
 
 
533
end
 
534
 
 
535
 
 
536
DefaultRegistry = Registry.new
 
537
RubyOriginalRegistry = Registry.new(:allow_original_mapping => true)
 
538
 
 
539
 
 
540
end
 
541
end