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

root/branches/1_5/lib/soap/mapping/registry.rb

Revision 1979, 6.8 kB (checked in by nahi, 1 year ago)
  • when there are 2 unqualified anonymous elements which have the same name in a SOAP message, mapper cannot decode it to the correct object. introduced :is_anonymous in mapping_registry and do not search registry with anonymous element. closes #355.
  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1 # SOAP4R - Mapping registry.
2 # Copyright (C) 2000-2007  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
12
13 module SOAP
14
15
16 module Marshallable
17   # @@type_ns = Mapping::RubyCustomTypeNamespace
18 end
19
20
21 module Mapping
22
23  
24 module MappedException; end
25
26
27 RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
28 RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends')
29 RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars')
30
31
32 # For anyType object: SOAP::Mapping::Object not ::Object
33 class Object
34   def initialize
35     @__xmlele_type = {}
36     @__xmlele = []
37     @__xmlattr = {}
38   end
39
40   def inspect
41     sprintf("#<%s:0x%x%s>", self.class.name, __id__,
42       @__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join)
43   end
44
45   def __xmlattr
46     @__xmlattr
47   end
48
49   def __xmlele
50     @__xmlele
51   end
52
53   def [](qname)
54     qname = Mapping.to_qname(qname)
55     @__xmlele.each do |k, v|
56       return v if k == qname
57     end
58     # fallback
59     @__xmlele.each do |k, v|
60       return v if k.name == qname.name
61     end
62     nil
63   end
64
65   def []=(qname, value)
66     qname = Mapping.to_qname(qname)
67     found = false
68     @__xmlele.each do |pair|
69       if pair[0] == qname
70         found = true
71         pair[1] = value
72       end
73     end
74     unless found
75       __define_attr_accessor(qname)
76       @__xmlele << [qname, value]
77     end
78     @__xmlele_type[qname] = :single
79   end
80
81   def __add_xmlele_value(qname, value)
82     found = false
83     @__xmlele.map! do |k, v|
84       if k == qname
85         found = true
86         [k, __set_xmlele_value(k, v, value)]
87       else
88         [k, v]
89       end
90     end
91     unless found
92       __define_attr_accessor(qname)
93       @__xmlele << [qname, value]
94       @__xmlele_type[qname] = :single
95     end
96     value
97   end
98
99   def marshal_load(dumpobj)
100     __import(dumpobj)
101   end
102
103 private
104
105   # Mapping.define_attr_accessor calls define_method with proc and it exhausts
106   # much memory for each singleton Object.  just instance_eval instead of it.
107   def __define_attr_accessor(qname)
108     # untaint depends GenSupport.safemethodname
109     name = Mapping.safemethodname(qname.name).untaint
110     # untaint depends on QName#dump
111     qnamedump = qname.dump.untaint
112     singleton = false
113     unless self.respond_to?(name)
114       singleton = true
115       instance_eval <<-EOS
116         def #{name}
117           self[#{qnamedump}]
118         end
119       EOS
120     end
121     unless self.respond_to?(name + "=")
122       singleton = true
123       instance_eval <<-EOS
124         def #{name}=(value)
125           self[#{qnamedump}] = value
126         end
127       EOS
128     end
129     if singleton && !self.respond_to?(:marshal_dump)
130       instance_eval <<-EOS
131         def marshal_dump
132           __export
133         end
134       EOS
135     end
136   end
137
138   def __set_xmlele_value(key, org, value)
139     case @__xmlele_type[key]
140     when :multi
141       org << value
142       org
143     when :single
144       @__xmlele_type[key] = :multi
145       [org, value]
146     else
147       raise RuntimeError.new("unknown type")
148     end
149   end
150
151   def __export
152     dumpobj = ::SOAP::Mapping::Object.new
153     dumpobj.__xmlele.replace(@__xmlele)
154     dumpobj.__xmlattr.replace(@__xmlattr)
155     dumpobj
156   end
157
158   def __import(dumpobj)
159     @__xmlele_type = {}
160     @__xmlele = []
161     @__xmlattr = {}
162     dumpobj.__xmlele.each do |qname, value|
163       __add_xmlele_value(qname, value)
164     end
165     @__xmlattr.replace(dumpobj.__xmlattr)
166   end
167 end
168
169
170 class MappingError < Error; end
171
172
173 module RegistrySupport
174   def initialize
175     super()
176     @class_schema_definition = {}
177     @class_elename_schema_definition = {}
178     @elename_schema_definition = {}
179     @type_schema_definition = {}
180   end
181
182   def register(definition)
183     obj_class = definition[:class]
184     definition = Mapping.create_schema_definition(obj_class, definition)
185     # give complexType definition a priority explicitly
186     if !@class_schema_definition[obj_class] or definition.type
187       @class_schema_definition[obj_class] = definition
188     end
189     if definition.elename and !definition.is_anonymous?
190       @class_elename_schema_definition[obj_class] = definition
191       @elename_schema_definition[definition.elename] = definition
192     end
193     if definition.type
194       @type_schema_definition[definition.type] = definition
195     end
196   end
197
198   def schema_definition_from_class(klass)
199     @class_schema_definition[klass] || Mapping.schema_definition_classdef(klass)
200   end
201
202   def elename_schema_definition_from_class(klass)
203     @class_elename_schema_definition[klass]
204   end
205
206   def schema_definition_from_elename(qname)
207     @elename_schema_definition[qname]
208   end
209
210   def schema_definition_from_type(type)
211     @type_schema_definition[type]
212   end
213
214   def find_node_definition(node)
215     schema_definition_from_type(node.type) ||
216       schema_definition_from_elename(node.elename) ||
217       find_schema_definition(node.elename.name) ||
218       find_schema_definition(node.type.name)
219   end
220
221   def find_schema_definition(name)
222     return nil unless name
223     typestr = Mapping.safeconstname(name)
224     obj_class = Mapping.class_from_name(typestr)
225     if obj_class
226       schema_definition_from_class(obj_class)
227     end
228   end
229  
230   def add_attributes2soap(obj, ele)
231     if definition = Mapping.schema_definition_classdef(obj.class)
232       add_definedattributes2soap(obj, ele, definition)
233     elsif obj.respond_to?(:__xmlattr)
234       obj.__xmlattr.each do |key, value|
235         ele.extraattr[key] = value
236       end
237     end
238   end
239
240   def add_definedattributes2soap(obj, ele, typedef)
241     if typedef.attributes
242       typedef.attributes.each do |qname, param|
243         value = get_xmlattr_value(obj, qname)
244         ele.extraattr[qname] = value unless value.nil?
245       end
246     end
247   end
248
249   def get_xmlattr_value(obj, qname)
250     attrname = 'xmlattr_' + qname.name
251     value = Mapping.get_attribute(obj, attrname)
252     if value.nil?
253       attrname = Mapping.safemethodname('xmlattr_' + qname.name)
254       value = Mapping.get_attribute(obj, attrname)
255     end
256     value
257   end
258
259   def base2soap(obj, type, qualified = nil)
260     return SOAPNil.new if obj.nil?
261     soap_obj = nil
262     if type <= XSD::XSDString
263       str = XSD::Charset.encoding_conv(obj.to_s, Mapping.external_ces,
264         XSD::Charset.encoding)
265       soap_obj = type.new(str)
266     else
267       soap_obj = type.new(obj)
268     end
269     soap_obj.qualified = qualified
270     soap_obj
271   end
272
273   def base2obj(value, klass)
274     v = if value.respond_to?(:data)
275           value.data
276         elsif value.respond_to?(:text)
277           value.text
278         else
279           nil
280         end
281     if value.is_a?(klass)
282       v
283     else
284       klass.to_data(v)
285     end
286   end
287
288   def is_stubobj_elements_for_array(vars)
289     vars.keys.size == 1 and vars.values[0].is_a?(::Array)
290   end
291 end
292
293
294 end
295 end
Note: See TracBrowser for help on using the browser.