PageRenderTime 233ms CodeModel.GetById 176ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 1ms

/tools/Ruby/lib/ruby/1.8/soap/mapping/registry.rb

http://github.com/agross/netopenspace
Ruby | 541 lines | 464 code | 62 blank | 15 comment | 35 complexity | e301efe2b01f4464e05afa6b3e37781f MD5 | raw file
  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
  9require 'soap/baseData'
 10require 'soap/mapping/mapping'
 11require 'soap/mapping/typeMap'
 12require 'soap/mapping/factory'
 13require 'soap/mapping/rubytypeFactory'
 14
 15
 16module SOAP
 17
 18
 19module Marshallable
 20  # @@type_ns = Mapping::RubyCustomTypeNamespace
 21end
 22
 23
 24module Mapping
 25
 26  
 27module MappedException; end
 28
 29
 30RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
 31RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends')
 32RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars')
 33
 34
 35# Inner class to pass an exception.
 36class 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
 60end
 61
 62
 63# For anyType object: SOAP::Mapping::Object not ::Object
 64class 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
134private
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
170end
171
172
173class MappingError < Error; end
174
175
176class 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
444private
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
533end
534
535
536DefaultRegistry = Registry.new
537RubyOriginalRegistry = Registry.new(:allow_original_mapping => true)
538
539
540end
541end