Welcome to the "trac"-ing site of soap4r!
[soap4r] [httpclient] [openpgp4u] [pkcs1] [logger] [csv] [vtr]

Changeset 1720

Show
Ignore:
Timestamp:
09/10/06 20:46:24 (2 years ago)
Author:
nahi
Message:

soap/mapping/* refactoring.
registry.rb -> split into registry.rb (common) and encodedregistry.rb.
wsdlliteralregistry.rb -> split into literalregistry.rb and wsdlliteralregistry.rb

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/lib/soap/mapping/encodedregistry.rb

    r1706 r1720  
    1 # SOAP4R - Mapping registry. 
    2 # Copyright (C) 2000, 2001, 2002, 2003  NAKAMURA, Hiroshi <nahi@ruby-lang.org>. 
     1# SOAP4R - encoded mapping registry. 
     2# Copyright (C) 2000-2003, 2006  NAKAMURA, Hiroshi <nahi@ruby-lang.org>. 
    33 
    44# This program is copyrighted free software by NAKAMURA, Hiroshi.  You can 
     
    1515 
    1616module SOAP 
    17  
    18  
    19 module Marshallable 
    20   # @@type_ns = Mapping::RubyCustomTypeNamespace 
    21 end 
    22  
    23  
    2417module Mapping 
    2518 
    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  
    3419 
    3520# Inner class to pass an exception. 
    36 class SOAPException; include Marshallable 
     21class SOAPException 
    3722  attr_reader :excn_type_name, :cause 
     23 
    3824  def initialize(e) 
    3925    @excn_type_name = Mapping.name2elename(e.class.to_s) 
     
    6147 
    6248 
    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   # Mapping.define_attr_accessor calls define_method with proc and it exhausts 
    137   # much memory for each singleton Object.  just instance_eval instead of it. 
    138   def __define_attr_accessor(qname) 
    139     # untaint depends GenSupport.safemethodname 
    140     name = XSD::CodeGen::GenSupport.safemethodname(qname.name).untaint 
    141     # untaint depends QName#dump 
    142     qnamedump = qname.dump.untaint 
    143     unless self.respond_to?(name) 
    144       instance_eval <<-EOS 
    145         def #{name} 
    146           self[#{qnamedump}] 
    147         end 
    148       EOS 
    149     end 
    150     unless self.respond_to?(name + "=") 
    151       instance_eval <<-EOS 
    152         def #{name}=(value) 
    153           self[#{qnamedump}] = value 
    154         end 
    155       EOS 
    156     end 
    157   end 
    158  
    159   def __set_xmlele_value(key, org, value) 
    160     case @__xmlele_type[key] 
    161     when :multi 
    162       org << value 
    163       org 
    164     when :single 
    165       @__xmlele_type[key] = :multi 
    166       [org, value] 
    167     else 
    168       raise RuntimeError.new("unknown type") 
    169     end 
    170   end 
    171 end 
    172  
    173  
    174 class MappingError < Error; end 
    175  
    176  
    177 class Registry 
     49class EncodedRegistry 
    17850  class Map 
    17951    def initialize(registry) 
     
    532404    end 
    533405  end 
    534  
    535406end 
    536  
    537  
    538 DefaultRegistry = Registry.new 
    539 RubyOriginalRegistry = Registry.new(:allow_original_mapping => true) 
    540407 
    541408 
  • trunk/lib/soap/mapping/factory.rb

    r1706 r1720  
    5555  def setdefinediv2soap(ele, obj, map) 
    5656    # cache needed? 
    57     definition = Mapping.schema_element_definition(obj.class) 
     57    definition = Mapping.schema_definition_classdef(obj.class) 
    5858    definition.elements.each do |eledef| 
    5959      child = Mapping.get_attribute(obj, eledef.varname) 
     
    107107    end 
    108108    begin 
    109       unless XSD::Charset.is_ces(obj, Thread.current[:SOAPExternalCES]) 
     109      externalces = Thread.current[:SOAPMapping][:ExternalCES] 
     110      unless XSD::Charset.is_ces(obj, externalces) 
    110111        return nil 
    111112      end 
    112       encoded = XSD::Charset.encoding_conv(obj, 
    113         Thread.current[:SOAPExternalCES], XSD::Charset.encoding) 
     113      encoded = XSD::Charset.encoding_conv(obj, externalces, 
     114        XSD::Charset.encoding) 
    114115      soap_obj = soap_class.new(encoded) 
    115116    rescue XSD::ValueSpaceError 
     
    123124    obj = Mapping.create_empty_object(obj_class) 
    124125    decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, 
    125       Thread.current[:SOAPExternalCES]) 
     126      Thread.current[:SOAPMapping][:ExternalCES]) 
    126127    obj.replace(decoded) 
    127128    mark_unmarshalled_obj(node, obj) 
  • trunk/lib/soap/mapping/literalregistry.rb

    r1719 r1720  
    1 # SOAP4R - WSDL literal mapping registry. 
     1# SOAP4R - literal mapping registry. 
    22# Copyright (C) 2004-2006  NAKAMURA, Hiroshi <nahi@ruby-lang.org>. 
    33 
     
    1818 
    1919 
    20 class WSDLLiteralRegistry < Registry 
    21   attr_reader :definedelements 
    22   attr_reader :definedtypes 
     20class LiteralRegistry 
     21  include RegistrySupport 
     22 
    2323  attr_accessor :excn_handler_obj2soap 
    2424  attr_accessor :excn_handler_soap2obj 
    2525 
    26   def initialize(definedtypes = XSD::NamedElements::Empty, 
    27       definedelements = XSD::NamedElements::Empty) 
    28     @definedtypes = definedtypes 
    29     @definedelements = definedelements 
     26  def initialize 
     27    super() 
    3028    @excn_handler_obj2soap = nil 
    3129    @excn_handler_soap2obj = nil 
    32     @schema_element_cache = {} 
    33     @schema_attribute_cache = {} 
    3430  end 
    3531 
     
    3834    if obj.is_a?(SOAPElement) 
    3935      soap_obj = obj 
    40     elsif eledef = @definedelements[qname] 
    41       soap_obj = obj2elesoap(obj, eledef) 
    42     elsif type = @definedtypes[qname] 
    43       soap_obj = obj2typesoap(obj, type, true) 
    4436    else 
    4537      soap_obj = any2soap(obj, qname) 
     
    8072 
    8173  MAPPING_OPT = { :no_reference => true } 
    82  
    83   def obj2elesoap(obj, eledef) 
    84     ele = nil 
    85     qualified = (eledef.elementform == 'qualified') 
    86     if eledef.type 
    87       if type = @definedtypes[eledef.type] 
    88         ele = obj2typesoap(obj, type, qualified) 
    89       elsif type = TypeMap[eledef.type] 
    90         ele = base2soap(obj, type) 
    91       else 
    92         raise MappingError.new("cannot find type #{eledef.type}") 
    93       end 
    94     elsif eledef.local_complextype 
    95       ele = obj2typesoap(obj, eledef.local_complextype, qualified) 
    96     elsif eledef.local_simpletype 
    97       ele = obj2typesoap(obj, eledef.local_simpletype, qualified) 
    98     else 
    99       raise MappingError.new('illegal schema?') 
    100     end 
    101     ele.elename = eledef.name 
    102     ele 
    103   end 
    104  
    105   def obj2typesoap(obj, type, qualified) 
    106     ele = nil 
    107     if type.is_a?(::WSDL::XMLSchema::SimpleType) 
    108       ele = simpleobj2soap(obj, type) 
    109     elsif type.simplecontent 
    110       ele = simpleobj2soap(obj, type.simplecontent) 
    111     else 
    112       ele = complexobj2soap(obj, type, qualified) 
    113     end 
    114     add_attributes2soap(obj, ele) 
    115     ele 
    116   end 
    117  
    118   def simpleobj2soap(obj, type) 
    119     type.check_lexical_format(obj) 
    120     return SOAPNil.new if obj.nil?      # TODO: check nillable. 
    121     if type.base 
    122       ele = base2soap(obj, TypeMap[type.base]) 
    123     elsif type.list 
    124       value = obj.is_a?(Array) ? obj.join(" ") : obj.to_s 
    125       ele = base2soap(value, SOAP::SOAPString) 
    126     else 
    127       raise MappingError.new("unsupported simpleType: #{type}") 
    128     end 
    129     ele 
    130   end 
    131  
    132   def complexobj2soap(obj, type, qualified) 
    133     ele = SOAPElement.new(type.name) 
    134     ele.qualified = qualified 
    135     if type.choice? 
    136       complexobj2choicesoap(obj, ele, type) 
    137     else 
    138       complexobj2sequencesoap(obj, ele, type) 
    139     end 
    140   end 
    141  
    142   def complexobj2sequencesoap(obj, ele, type) 
    143     elements = type.elements 
    144     any = nil 
    145     if type.have_any? 
    146       any = Mapping.get_attributes_for_any(obj, elements) 
    147     end 
    148     elements.each do |child_ele| 
    149       case child_ele 
    150       when WSDL::XMLSchema::Any 
    151         if any 
    152           SOAPElement.from_objs(any).each do |child| 
    153             ele.add(child) 
    154           end 
    155         end 
    156       when WSDL::XMLSchema::Element 
    157         complexobj2soapchildren(obj, ele, child_ele) 
    158       when WSDL::XMLSchema::Sequence 
    159         complexobj2sequencesoap(obj, child_ele, type) 
    160       when WSDL::XMLSchema::Choice 
    161         complexobj2choicesoap(obj, child_ele, type) 
    162       else 
    163         raise MappingError.new("unknown type: #{child_ele}") 
    164       end 
    165     end 
    166     ele 
    167   end 
    168  
    169   def complexobj2choicesoap(obj, ele, type) 
    170     elements = type.elements 
    171     any = nil 
    172     if type.have_any? 
    173       raise MappingError.new( 
    174         "<any/> in <choice/> is not supported: #{ele.name.name}") 
    175     end 
    176     elements.each do |child_ele| 
    177       break if complexobj2soapchildren(obj, ele, child_ele, true) 
    178     end 
    179     ele 
    180   end 
    181  
    182   def complexobj2soapchildren(obj, ele, child_ele, allow_nil_value = false) 
    183     if child_ele.map_as_array? 
    184       complexobj2soapchildren_array(obj, ele, child_ele, allow_nil_value) 
    185     else 
    186       complexobj2soapchildren_single(obj, ele, child_ele, allow_nil_value) 
    187     end 
    188   end 
    189  
    190   def complexobj2soapchildren_array(obj, ele, child_ele, allow_nil_value) 
    191     child = Mapping.get_attribute(obj, child_ele.name.name) 
    192     if child.nil? and obj.respond_to?(:each) 
    193       child = obj 
    194     end 
    195     if child.nil? 
    196       return false if allow_nil_value 
    197       if child_soap = nil2soap(child_ele) 
    198         ele.add(child_soap) 
    199         return true 
    200       else 
    201         return false 
    202       end 
    203     end 
    204     unless child.respond_to?(:each) 
    205       return false 
    206     end 
    207     child.each do |item| 
    208       if item.is_a?(SOAPElement) 
    209         ele.add(item) 
    210       else 
    211         child_soap = obj2elesoap(item, child_ele) 
    212         ele.add(child_soap) 
    213       end 
    214     end 
    215     true 
    216   end 
    217  
    218   def complexobj2soapchildren_single(obj, ele, child_ele, allow_nil_value) 
    219     child = Mapping.get_attribute(obj, child_ele.name.name) 
    220     case child 
    221     when NilClass 
    222       return false if allow_nil_value 
    223       if child_soap = nil2soap(child_ele) 
    224         ele.add(child_soap) 
    225         true 
    226       else 
    227         false 
    228       end 
    229     when SOAPElement 
    230       ele.add(child) 
    231       true 
    232     else 
    233       child_soap = obj2elesoap(child, child_ele) 
    234       ele.add(child_soap) 
    235       true 
    236     end 
    237   end 
    238  
    239   def nil2soap(ele) 
    240     if ele.nillable 
    241       obj2elesoap(nil, ele)     # add an empty element 
    242     elsif Integer(ele.minoccurs) == 0 
    243       nil       # intends no element 
    244     else 
    245       raise MappingError.new("nil not allowed: #{ele.name.name}") 
    246     end 
    247   end 
    24874 
    24975  def any2soap(obj, qname) 
     
    281107      (obj.class.class_variables.include?('@@schema_qualified') and 
    282108      obj.class.class_eval('@@schema_qualified')) 
    283     definition = schema_element_definition(obj.class) 
     109    definition = Mapping.schema_definition_classdef(obj.class) 
    284110    ele.extraattr[XSD::AttrTypeName] = 
    285111      XSD::QName.new(definition.ns, definition.type) 
     
    325151    ele 
    326152  end 
    327    
    328   def add_attributes2soap(obj, ele) 
    329     attributes = schema_attribute_definition(obj.class) 
    330     if attributes 
    331       attributes.each do |qname, param| 
    332         at = obj.__send__( 
    333           XSD::CodeGen::GenSupport.safemethodname('xmlattr_' + qname.name)) 
    334         ele.extraattr[qname] = at 
    335       end 
    336     elsif obj.respond_to?(:__xmlattr) 
    337       obj.__xmlattr.each do |key, value| 
    338         ele.extraattr[key] = value 
    339       end 
    340     end 
    341   end 
    342  
    343   def base2soap(obj, type) 
    344     soap_obj = nil 
    345     if type <= XSD::XSDString 
    346       str = XSD::Charset.encoding_conv(obj.to_s, 
    347         Thread.current[:SOAPExternalCES], XSD::Charset.encoding) 
    348       soap_obj = type.new(str) 
    349     else 
    350       soap_obj = type.new(obj) 
    351     end 
    352     soap_obj 
    353   end 
    354153 
    355154  def any2obj(node, obj_class = nil) 
     
    396195 
    397196  def add_elesoap2stubobj(node, obj) 
    398     definition = schema_element_definition(obj.class) 
     197    definition = Mapping.schema_definition_classdef(obj.class) 
    399198    vars = {} 
    400199    node.each do |name, value| 
     
    439238 
    440239  def add_attributes2stubobj(node, obj) 
    441     if attributes = schema_attribute_definition(obj.class) 
     240    schema_definition = Mapping.schema_definition_classdef(obj.class) 
     241    if schema_definition && attributes = schema_definition.attributes 
    442242      define_xmlattr(obj) 
    443243      attributes.each do |qname, class_name| 
     
    501301    end 
    502302  end 
    503  
    504   # it caches @@schema_element.  this means that @@schema_element must not be 
    505   # changed while a lifetime of a WSDLLiteralRegistry. 
    506   def schema_element_definition(klass) 
    507     @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass) 
    508   end 
    509  
    510   def schema_attribute_definition(klass) 
    511     @schema_attribute_cache[klass] ||= 
    512       Mapping.schema_attribute_definition(klass) 
    513   end 
    514303end 
    515304 
  • trunk/lib/soap/mapping/mapping.rb

    r1719 r1720  
    2121 
    2222 
    23   # TraverseSupport breaks following thread variables. 
    24   #   Thread.current[:SOAPMarshalDataKey] 
    2523  module TraverseSupport 
    2624    def mark_marshalled_obj(obj, soap_obj) 
    2725      raise if obj.nil? 
    28       Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj 
     26      Thread.current[:SOAPMapping][:MarshalKey][obj.__id__] = soap_obj 
    2927    end 
    3028 
     
    3230      return if obj.nil? 
    3331      # node.id is not Object#id but SOAPReference#id 
    34       Thread.current[:SOAPMarshalDataKey][node.id] = obj 
    35     end 
    36   end 
    37  
    38  
    39   EMPTY_OPT = {} 
     32      Thread.current[:SOAPMapping][:MarshalKey][node.id] = obj 
     33    end 
     34  end 
     35 
     36 
     37  EMPTY_OPT = {}.freeze 
    4038  def self.obj2soap(obj, registry = nil, type = nil, opt = EMPTY_OPT) 
    4139    registry ||= Mapping::DefaultRegistry 
    4240    soap_obj = nil 
    43     protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do 
    44       Thread.current[:SOAPMarshalDataKey] = {} 
    45       Thread.current[:SOAPExternalCES] = 
    46         opt[:external_ces] || XSD::Charset.encoding 
    47       Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] 
     41    protect_mapping(opt) do 
    4842      soap_obj = _obj2soap(obj, registry, type) 
    4943    end 
     
    5448    registry ||= Mapping::DefaultRegistry 
    5549    obj = nil 
    56     protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do 
    57       Thread.current[:SOAPMarshalDataKey] = {} 
    58       Thread.current[:SOAPExternalCES] = 
    59         opt[:external_ces] || XSD::Charset.encoding 
    60       Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] 
     50    protect_mapping(opt) do 
    6151      obj = _soap2obj(node, registry, klass) 
    6252    end 
     
    6858    type = XSD::QName.new(type_ns, typename) 
    6959    soap_ary = SOAPArray.new(ValueArrayName, 1, type) 
    70     protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do 
    71       Thread.current[:SOAPMarshalDataKey] = {} 
    72       Thread.current[:SOAPExternalCES] = 
    73         opt[:external_ces] || XSD::Charset.encoding 
    74       Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] 
     60    protect_mapping(opt) do 
    7561      ary.each do |ele| 
    7662        soap_ary.add(_obj2soap(ele, registry, type)) 
     
    8470    type = XSD::QName.new(type_ns, typename) 
    8571    md_ary = SOAPArray.new(ValueArrayName, rank, type) 
    86     protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do 
    87       Thread.current[:SOAPMarshalDataKey] = {} 
    88       Thread.current[:SOAPExternalCES] = 
    89         opt[:external_ces] || XSD::Charset.encoding 
    90       Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] 
     72    protect_mapping(opt) do 
    9173      add_md_ary(md_ary, ary, [], registry) 
    9274    end 
     
    125107 
    126108  def self._obj2soap(obj, registry, type = nil) 
    127     if referent = Thread.current[:SOAPMarshalDataKey][obj.__id__] and 
    128         !Thread.current[:SOAPMarshalNoReference] 
     109    if referent = Thread.current[:SOAPMapping][:MarshalKey][obj.__id__] and 
     110        !Thread.current[:SOAPMapping][:NoReference] 
    129111      SOAPReference.new(referent) 
    130112    elsif registry 
     
    141123      target = node.__getobj__ 
    142124      # target.id is not Object#id but SOAPReference#id 
    143       if referent = Thread.current[:SOAPMarshalDataKey][target.id] and 
    144           !Thread.current[:SOAPMarshalNoReference] 
     125      if referent = Thread.current[:SOAPMapping][:MarshalKey][target.id] and 
     126          !Thread.current[:SOAPMapping][:NoReference] 
    145127        return referent 
    146128      else 
     
    377359 
    378360  def self.schema_element_definition(klass) 
    379     schema_element = class_schema_variable(:schema_element, klass) 
    380     return nil unless schema_element 
    381     parse_schema_element_definition(klass, schema_element) 
    382   end 
    383  
    384   class SchemaElementDefinition 
    385     attr_reader :varname, :elename, :type 
    386  
    387     def initialize(varname, elename, type, as_array) 
    388       @varname = varname 
    389       @elename = elename 
    390       @type = type 
    391       @as_array = as_array 
    392     end 
    393  
    394     def as_array? 
    395       @as_array 
    396     end 
    397   end 
    398  
    399   class SchemaDefinition 
    400     attr_reader :ns, :type, :elements 
    401  
    402     def initialize(ns, type) 
    403       @ns = ns 
    404       @type = type 
    405       @elements = [] 
    406       @choice = false 
    407       @any = false 
    408     end 
    409  
    410     def choice? 
    411       @choice 
    412     end 
    413  
    414     def have_any? 
    415       @any 
    416     end 
    417  
    418     def set_choice 
    419       @choice = true 
    420     end 
    421  
    422     def set_any 
    423       @any = true 
    424     end 
     361    class_schema_variable(:schema_element, klass) 
    425362  end 
    426363 
     
    429366  end 
    430367 
    431   class << Mapping 
    432   private 
    433  
    434     def parse_schema_element_definition(klass, schema_element) 
    435       schema_ns = schema_ns_definition(klass) 
    436       schema_type = schema_type_definition(klass) 
    437       definition = SchemaDefinition.new(schema_ns, schema_type) 
     368  def self.schema_definition_classdef(klass) 
     369    if definition = Thread.current[:SOAPMapping][:SchemaDefinition][klass] 
     370      return definition 
     371    end 
     372    ns = schema_ns_definition(klass) 
     373    type = schema_type_definition(klass) 
     374    elements = schema_element_definition(klass) 
     375    attributes = schema_attribute_definition(klass) 
     376    return nil if ns.nil? and type.nil? and elements.nil? and attributes.nil? 
     377    definition = create_schema_definition(klass, ns, type, elements, attributes) 
     378    Thread.current[:SOAPMapping][:SchemaDefinition][klass] = definition 
     379    definition 
     380  end 
     381 
     382  def self.create_schema_definition(klass, schema_ns, schema_type, 
     383      schema_element, schema_attributes) 
     384    definition = SchemaDefinition.new(schema_ns, schema_type) 
     385    definition.attributes = schema_attributes 
     386    if schema_element 
    438387      if schema_element[0] == :choice 
    439388        schema_element.shift 
     
    462411          ) 
    463412      end 
    464       definition 
    465     end 
     413    end 
     414    definition 
     415  end 
     416 
     417  class SchemaElementDefinition 
     418    attr_reader :varname, :elename, :type 
     419 
     420    def initialize(varname, elename, type, as_array) 
     421      @varname = varname 
     422      @elename = elename 
     423      @type = type 
     424      @as_array = as_array 
     425    end 
     426 
     427    def as_array? 
     428      @as_array 
     429    end 
     430  end 
     431 
     432  class SchemaDefinition 
     433    attr_reader :ns, :type, :elements 
     434    attr_accessor :attributes 
     435 
     436    def initialize(ns, type) 
     437      @ns = ns 
     438      @type = type 
     439      @elements = [] 
     440      @attributes = nil 
     441      @choice = false 
     442      @any = false 
     443    end 
     444 
     445    def choice? 
     446      @choice 
     447    end 
     448 
     449    def have_any? 
     450      @any 
     451    end 
     452 
     453    def set_choice 
     454      @choice = true 
     455    end 
     456 
     457    def set_any 
     458      @any = true 
     459    end 
     460  end 
     461 
     462  class << Mapping 
     463  private 
    466464 
    467465    def class_schema_variable(sym, klass) 
    468466      var = "@@#{sym}" 
    469467      klass.class_variables.include?(var) ? klass.class_eval(var) : nil 
     468    end 
     469 
     470    def protect_mapping(opt) 
     471      protect_threadvars(:SOAPMapping) do 
     472        data = Thread.current[:SOAPMapping] = {} 
     473        data[:MarshalKey] = {} 
     474        data[:ExternalCES] = opt[:external_ces] || XSD::Charset.encoding 
     475        data[:NoReference] = opt[:no_reference] 
     476        data[:SchemaDefinition] = {} 
     477        yield 
     478      end 
    470479    end 
    471480 
  • trunk/lib/soap/mapping/registry.rb

    <
    r1706 r1720  
    11# SOAP4R - Mapping registry. 
    2 # Copyright (C) 2000, 2001, 2002, 2003  NAKAMURA, Hiroshi <nahi@ruby-lang.org>. 
     2# Copyright (C) 2000-2003, 2006  NAKAMURA, Hiroshi <nahi@ruby-lang.org>. 
    33 
    44# This program is copyrighted free software by NAKAMURA, Hiroshi.  You can 
     
    99require 'soap/baseData' 
    1010require 'soap/mapping/mapping' 
    11 require 'soap/mapping/typeMap' 
    12 require 'soap/mapping/factory' 
    13 require 'soap/mapping/rubytypeFactory' 
     11require 'soap/mapping/encodedregistry.rb' 
    1412 
    1513 
     
    3129RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends') 
    3230RubyIVarName = 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 
    6131 
    6232 
     
    175145 
    176146 
    177 class Registry 
    178   class Map 
    179     def initialize(registry) 
    180       @obj2soap = {} 
    181       @soap2obj = {} 
    182       @registry = registry 
    183     end 
    184  
    185     def obj2soap(obj) 
    186       klass = obj.class 
    187       if map = @obj2soap[klass] 
    188         map.each do |soap_class, factory, info| 
    189           ret = factory.obj2soap(soap_class, obj, info, @registry) 
    190           return ret if ret 
    191         end 
     147module RegistrySupport 
     148  def initialize 
     149    super() 
     150  end 
     151   
     152  def add_attributes2soap(obj, ele) 
     153    schema_definition = Mapping.schema_definition_classdef(obj.class) 
     154    if schema_definition && attributes = schema_definition.attributes 
     155      attributes.each do |qname, param| 
     156        at = obj.__send__( 
     157          XSD::CodeGen::GenSupport.safemethodname('xmlattr_' + qname.name)) 
     158        ele.extraattr[qname] = at 
    192159      end 
    193       ancestors = klass.ancestors 
    194       ancestors.delete(klass) 
    195       ancestors.delete(::Object) 
    196       ancestors.delete(::Kernel) 
    197       ancestors.each do |klass| 
    198         if map = @obj2soap[klass] 
    199           map.each do |soap_class, factory, info| 
    200             if info[:derived_class] 
    201               ret = factory.obj2soap(soap_class, obj, info, @registry) 
    202               return ret if ret 
    203             end 
    204           end 
    205         end 
    206       end 
    207       nil 
    208     end 
    209  
    210     def soap2obj(node, klass = nil) 
    211       if map = @soap2obj[node.class] 
    212         map.each do |obj_class, factory, info| 
    213           next if klass and obj_class != klass 
    214           conv, obj = factory.soap2obj(obj_class, node, info, @registry) 
    215           return true, obj if conv 
    216         end 
    217       end 
    218       return false, nil 
    219     end 
    220  
    221     # Give priority to former entry. 
    222     def init(init_map = []) 
    223       clear 
    224       init_map.reverse_each do |obj_class, soap_class, factory, info| 
    225         add(obj_class, soap_class, factory, info) 
    226       end 
    227     end 
    228  
    229     # Give priority to latter entry. 
    230     def add(obj_class, soap_class, factory, info) 
    231       info ||= {} 
    232       (@obj2soap[obj_class] ||= []).unshift([soap_class, factory, info]) 
    233       (@soap2obj[soap_class] ||= []).unshift([obj_class, factory, info]) 
    234     end 
    235  
    236     def clear 
    237       @obj2soap.clear 
    238       @soap2obj.clear 
    239     end 
    240  
    241     def find_mapped_soap_class(target_obj_class) 
    242       map = @obj2soap[target_obj_class] 
    243       map.empty? ? nil : map[0][1] 
    244     end 
    245  
    246     def find_mapped_obj_class(target_soap_class) 
    247       map = @soap2obj[target_soap_class] 
    248       map.empty? ? nil : map[0][0] 
    249     end 
    250   end 
    251  
    252   StringFactory = StringFactory_.new 
    253   BasetypeFactory = BasetypeFactory_.new 
    254   DateTimeFactory = DateTimeFactory_.new 
    255   ArrayFactory = ArrayFactory_.new 
    256   Base64Factory = Base64Factory_.new 
    257   URIFactory = URIFactory_.new 
    258   TypedArrayFactory = TypedArrayFactory_.new 
    259   TypedStructFactory = TypedStructFactory_.new 
    260  
    261   HashFactory = HashFactory_.new 
    262  
    263   SOAPBaseMap = [ 
    264     [::NilClass,     ::SOAP::SOAPNil,        BasetypeFactory], 
    265     [::TrueClass,    ::SOAP::SOAPBoolean,    BasetypeFactory], 
    266     [::FalseClass,   ::SOAP::SOAPBoolean,    BasetypeFactory], 
    267     [::String,       ::SOAP::SOAPString,     StringFactory], 
    268     [::DateTime,     ::SOAP::SOAPDateTime,   DateTimeFactory], 
    269     [::Date,         ::SOAP::SOAPDate,       DateTimeFactory], 
    270     [::Time,         ::SOAP::SOAPDateTime,   DateTimeFactory], 
    271     [::Time,         ::SOAP::SOAPTime,       DateTimeFactory], 
    272     [::Float,        ::SOAP::SOAPDouble,     BasetypeFactory, 
    273       {:derived_class => true}], 
    274     [::Float,        ::SOAP::SOAPFloat,      BasetypeFactory, 
    275       {:derived_class => true}], 
    276     [::Integer,      ::SOAP::SOAPInt,        BasetypeFactory, 
    277       {:derived_class => true}], 
    278     [::Integer,      ::SOAP::SOAPLong,       BasetypeFactory, 
    279       {:derived_class => true}], 
    280     [::Integer,      ::SOAP::SOAPInteger,    BasetypeFactory, 
    281       {:derived_class => true}], 
    282     [::Integer,      ::SOAP::SOAPShort,      BasetypeFactory, 
    283       {:derived_class => true}], 
    284     [::Integer,      ::SOAP::SOAPByte,       BasetypeFactory, 
    285       {:derived_class => true}], 
    286     [::Integer,      ::SOAP::SOAPNonPositiveInteger, BasetypeFactory, 
    287       {:derived_class => true}], 
    288     [::Integer,      ::SOAP::SOAPNegativeInteger, BasetypeFactory, 
    289       {:derived_class => true}], 
    290     [::Integer,      ::SOAP::SOAPNonNegativeInteger, BasetypeFactory, 
    291       {:derived_class => true}], 
    292     [::Integer,      ::SOAP::SOAPPositiveInteger, BasetypeFactory, 
    293       {:derived_class => true}], 
    294     [::Integer,      ::SOAP::SOAPUnsignedLong, BasetypeFactory, 
    295       {:derived_class => true}], 
    296     [::Integer,      ::SOAP::SOAPUnsignedInt, BasetypeFactory, 
    297       {:derived_class => true}], 
    298     [::Integer,      ::SOAP::SOAPUnsignedShort, BasetypeFactory, 
    299       {:derived_class => true}], 
    300     [::Integer,      ::SOAP::SOAPUnsignedByte, BasetypeFactory, 
    301       {:derived_class => true}], 
    302     [::URI::Generic, ::SOAP::SOAPAnyURI,     URIFactory, 
    303       {:derived_class => true}], 
    304     [::String,       ::SOAP::SOAPBase64,     Base64Factory], 
    305     [::String,       ::SOAP::SOAPHexBinary,  Base64Factory], 
    306     [::String,       ::SOAP::SOAPDecimal,    BasetypeFactory], 
    307     [::String,       ::SOAP::SOAPDuration,   BasetypeFactory], 
    308     [::String,       ::SOAP::SOAPGYearMonth, BasetypeFactory], 
    309     [::String,       ::SOAP::SOAPGYear,      BasetypeFactory], 
    310     [::String,       ::SOAP::SOAPGMonthDay,  BasetypeFactory], 
    311     [::String,       ::SOAP::SOAPGDay,       BasetypeFactory], 
    312     [::String,       ::SOAP::SOAPGMonth,     BasetypeFactory], 
    313     [::String,       ::SOAP::SOAPQName,      BasetypeFactory], 
    314  
    315     [::Hash,         ::SOAP::SOAPArray,      HashFactory], 
    316     [::Hash,         ::SOAP::SOAPStruct,     HashFactory], 
    317  
    318     [::Array,        ::SOAP::SOAPArray,      ArrayFactory, 
    319       {:derived_class => true}], 
    320  
    321     [::SOAP::Mapping::SOAPException, 
    322                      ::SOAP::SOAPStruct,     TypedStructFactory, 
    323       {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}], 
    324  ] 
    325  
    326   RubyOriginalMap = [ 
    327     [::NilClass,     ::SOAP::SOAPNil,        BasetypeFactory], 
    328     [::TrueClass,    ::SOAP::SOAPBoolean,    BasetypeFactory], 
    329     [::FalseClass,   ::SOAP::SOAPBoolean,    BasetypeFactory], 
    330     [::String,       ::SOAP::SOAPString,     StringFactory], 
    331     [::DateTime,     ::SOAP::SOAPDateTime,   DateTimeFactory], 
    332     [::Date,         ::SOAP::SOAPDate,       DateTimeFactory], 
    333     [::Time,         ::SOAP::SOAPDateTime,   DateTimeFactory], 
    334     [::Time,         ::SOAP::SOAPTime,       DateTimeFactory], 
    335     [::Float,        ::SOAP::SOAPDouble,     BasetypeFactory, 
    336       {:derived_class => true}], 
    337     [::Float,        ::SOAP::SOAPFloat,      BasetypeFactory, 
    338       {:derived_class => true}], 
    339     [::Integer,      ::SOAP::SOAPInt,        BasetypeFactory, 
    340       {:derived_class => true}], 
    341     [::Integer,      ::SOAP::SOAPLong,       BasetypeFactory, 
    342       {:derived_class => true}], 
    343     [::Integer,      ::SOAP::SOAPInteger,    BasetypeFactory, 
    344       {:derived_class => true}], 
    345     [::Integer,      ::SOAP::SOAPShort,      BasetypeFactory, 
    346       {:derived_class => true}], 
    347     [::Integer,      ::SOAP::SOAPByte,       BasetypeFactory, 
    348       {:derived_class => true}], 
    349     [::Integer,      ::SOAP::SOAPNonPositiveInteger, BasetypeFactory, 
    350       {:derived_class => true}], 
    351     [::Integer,      ::SOAP::SOAPNegativeInteger, BasetypeFactory, 
    352       {:derived_class => true}], 
    353     [::Integer,      ::SOAP::SOAPNonNegativeInteger, BasetypeFactory, 
    354       {:derived_class => true}], 
    355     [::Integer,      ::SOAP::SOAPPositiveInteger, BasetypeFactory, 
    356       {:derived_class => true}], 
    357     [::Integer,      ::SOAP::SOAPUnsignedLong, BasetypeFactory, 
    358       {:derived_class => true}], 
    359     [::Integer,      ::SOAP::SOAPUnsignedInt, BasetypeFactory, 
    360       {:derived_class => true}], 
    361     [::Integer,      ::SOAP::SOAPUnsignedShort, BasetypeFactory, 
    362       {:derived_class => true}], 
    363     [::Integer,      ::SOAP::SOAPUnsignedByte, BasetypeFactory, 
    364       {:derived_class => true}], 
    365     [::URI::Generic, ::SOAP::SOAPAnyURI,     URIFactory, 
    366       {:derived_class => true}], 
    367     [::String,       ::SOAP::SOAPBase64,     Base64Factory], 
    368     [::String,       ::SOAP::SOAPHexBinary,  Base64Factory], 
    369     [::String,       ::SOAP::SOAPDecimal,    BasetypeFactory], 
    370     [::String,       ::SOAP::SOAPDuration,   BasetypeFactory], 
    371     [::String,       ::SOAP::SOAPGYearMonth, BasetypeFactory], 
    372     [::String,       ::SOAP::SOAPGYear,      BasetypeFactory], 
    373     [::String,       ::SOAP::SOAPGMonthDay,  BasetypeFactory], 
    374     [::String,       ::SOAP::SOAPGDay,       BasetypeFactory], 
    375     [::String,       ::SOAP::SOAPGMonth,     BasetypeFactory], 
    376     [::String,       ::SOAP::SOAPQName,      BasetypeFactory], 
    377  
    378     [::Hash,         ::SOAP::SOAPArray,      HashFactory], 
    379     [::Hash,         ::SOAP::SOAPStruct,     HashFactory], 
    380  
    381     # Does not allow Array's subclass here. 
    382     [::Array,        ::SOAP::SOAPArray,      ArrayFactory], 
    383  
    384     [::SOAP::Mapping::SOAPException, 
    385                      ::SOAP::SOAPStruct,     TypedStructFactory, 
    386       {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}], 
    387   ] 
    388  
    389   attr_accessor :default_factory 
    390   attr_accessor :excn_handler_obj2soap 
    391   attr_accessor :excn_handler_soap2obj 
    392  
    393   def initialize(config = {}) 
    394     @config = config 
    395     @map = Map.new(self) 
    396     if @config[:allow_original_mapping] 
    397       @allow_original_mapping = true 
    398       @map.init(RubyOriginalMap) 
    399     else 
    400       @allow_original_mapping = false 
    401       @map.init(SOAPBaseMap) 
    402     end 
    403     @allow_untyped_struct = @config.key?(:allow_untyped_struct) ? 
    404       @config[:allow_untyped_struct] : true 
    405     @rubytype_factory = RubytypeFactory.new( 
    406       :allow_untyped_struct => @allow_untyped_struct, 
    407       :allow_original_mapping => @allow_original_mapping 
    408     ) 
    409     @default_factory = @rubytype_factory 
    410     @excn_handler_obj2soap = nil 
    411     @excn_handler_soap2obj = nil 
    412   end 
    413  
    414   def add(obj_class, soap_class, factory, info = nil) 
    415     @map.add(obj_class, soap_class, factory, info) 
    416   end 
    417   alias set add 
    418  
    419