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

root/trunk/lib/soap/mapping/factory.rb

Revision 1931, 9.5 kB (checked in by nahi, 1 year ago)
  • allow the Fixnum which have an instance variable to be marshalled. For Fixnum, ivars are not marshalled but allowed to be marshalled in Ruby's marshal. closes #406
  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1 # SOAP4R - Mapping factory.
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 module SOAP
10 module Mapping
11
12
13 class Factory
14   include TraverseSupport
15
16   def initialize
17     # nothing to do
18   end
19
20   def obj2soap(soap_class, obj, info, map)
21     raise NotImplementError.new
22     # return soap_obj
23   end
24
25   def soap2obj(obj_class, node, info, map)
26     raise NotImplementError.new
27     # return convert_succeeded_or_not, obj
28   end
29
30   def setiv2obj(obj, node, map)
31     return if node.nil?
32     if obj.is_a?(Array)
33       setiv2ary(obj, node, map)
34     else
35       setiv2struct(obj, node, map)
36     end
37   end
38
39   def setiv2soap(node, obj, map)
40     if obj.class.class_variables.include?('@@schema_element')
41       setdefinediv2soap(node, obj, map)
42     else
43       # should we sort instance_variables? how?
44       obj.instance_variables.each do |var|
45         name = var.sub(/^@/, '')
46         elename = Mapping.name2elename(name)
47         node.add(elename,
48           Mapping._obj2soap(obj.instance_variable_get(var), map))
49       end
50     end
51   end
52
53 private
54
55   def setdefinediv2soap(ele, obj, map)
56     definition = Mapping.schema_definition_classdef(obj.class)
57     definition.elements.each do |eledef|
58       child = Mapping.get_attribute(obj, eledef.varname)
59       # extract method
60       if child.nil?
61         value = SOAPNil.new
62       elsif child.is_a?(XSD::NSDBase)
63         value = child
64       else
65         klass = Mapping.class_from_name(eledef.type)
66         if klass && klass.include?(::SOAP::SOAPBasetype)
67           value = klass.new(child)
68         else
69           # should check klass matches an actual object?
70           value = Mapping._obj2soap(child, map)
71         end
72       end
73       ele.add(eledef.elename.name, value)
74     end
75   end
76
77   def setiv2ary(obj, node, map)
78     node.each do |name, value|
79       Array.instance_method(:<<).bind(obj).call(Mapping._soap2obj(value, map))
80     end
81   end
82
83   def setiv2struct(obj, node, map)
84     vars = {}
85     node.each do |name, value|
86       vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
87     end
88     Mapping.set_attributes(obj, vars)
89   end
90
91   def anonymous_class?(obj)
92     name = obj.class.name
93     name.nil? or name.empty?    # 1.8 returns ""
94   end
95 end
96
97 class StringFactory_ < Factory
98   def initialize(allow_original_mapping = false)
99     super()
100     @allow_original_mapping = allow_original_mapping
101   end
102
103   def obj2soap(soap_class, obj, info, map)
104     if !@allow_original_mapping and !obj.instance_variables.empty?
105       return nil
106     end
107     begin
108       encoded = XSD::Charset.encoding_conv(obj, Mapping.external_ces,
109         XSD::Charset.encoding)
110       soap_obj = soap_class.new(encoded)
111     rescue XSD::ValueSpaceError
112       return nil
113     end
114     mark_marshalled_obj(obj, soap_obj)
115     soap_obj
116   end
117
118   def soap2obj(obj_class, node, info, map)
119     obj = Mapping.create_empty_object(obj_class)
120     decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding,
121       Mapping.external_ces)
122     obj.replace(decoded)
123     mark_unmarshalled_obj(node, obj)
124     return true, obj
125   end
126 end
127
128 class FixnumFactory_ < Factory
129   def obj2soap(soap_class, obj, info, map)
130     soap_obj = nil
131     begin
132       soap_obj = soap_class.new(obj)
133     rescue XSD::ValueSpaceError
134       return nil
135     end
136     soap_obj
137   end
138
139   def soap2obj(obj_class, node, info, map)
140     obj = node.data
141     return true, obj
142   end
143 end
144
145 class BasetypeFactory_ < Factory
146   def initialize(allow_original_mapping = false)
147     super()
148     @allow_original_mapping = allow_original_mapping
149   end
150
151   def obj2soap(soap_class, obj, info, map)
152     if !@allow_original_mapping and !obj.instance_variables.empty?
153       return nil
154     end
155     soap_obj = nil
156     begin
157       soap_obj = soap_class.new(obj)
158     rescue XSD::ValueSpaceError
159       return nil
160     end
161     if @allow_original_mapping
162       # Basetype except String should not be multiref-ed in SOAP/1.1.
163       mark_marshalled_obj(obj, soap_obj)
164     end
165     soap_obj
166   end
167
168   def soap2obj(obj_class, node, info, map)
169     obj = node.data
170     mark_unmarshalled_obj(node, obj)
171     return true, obj
172   end
173 end
174
175 class DateTimeFactory_ < Factory
176   def initialize(allow_original_mapping = false)
177     super()
178     @allow_original_mapping = allow_original_mapping
179   end
180
181   def obj2soap(soap_class, obj, info, map)
182     if !@allow_original_mapping and
183         Time === obj and !obj.instance_variables.empty?
184       return nil
185     end
186     soap_obj = nil
187     begin
188       soap_obj = soap_class.new(obj)
189     rescue XSD::ValueSpaceError
190       return nil
191     end
192     mark_marshalled_obj(obj, soap_obj)
193     soap_obj
194   end
195
196   def soap2obj(obj_class, node, info, map)
197     if node.respond_to?(:to_obj)
198       obj = node.to_obj(obj_class)
199       return false if obj.nil?
200       mark_unmarshalled_obj(node, obj)
201       return true, obj
202     else
203       return false
204     end
205   end
206 end
207
208 class Base64Factory_ < Factory
209   def obj2soap(soap_class, obj, info, map)
210     return nil unless obj.instance_variables.empty?
211     soap_obj = soap_class.new(obj)
212     mark_marshalled_obj(obj, soap_obj) if soap_obj
213     soap_obj
214   end
215
216   def soap2obj(obj_class, node, info, map)
217     obj = node.string
218     mark_unmarshalled_obj(node, obj)
219     return true, obj
220   end
221 end
222
223 class URIFactory_ < Factory
224   def obj2soap(soap_class, obj, info, map)
225     soap_obj = soap_class.new(obj)
226     mark_marshalled_obj(obj, soap_obj) if soap_obj
227     soap_obj
228   end
229
230   def soap2obj(obj_class, node, info, map)
231     obj = node.data
232     mark_unmarshalled_obj(node, obj)
233     return true, obj
234   end
235 end
236
237 class ArrayFactory_ < Factory
238   def initialize(allow_original_mapping = false)
239     super()
240     @allow_original_mapping = allow_original_mapping
241   end
242
243   # [[1], [2]] is converted to Array of Array, not 2-D Array.
244   # To create M-D Array, you must call Mapping.ary2md.
245   def obj2soap(soap_class, obj, info, map)
246     if !@allow_original_mapping and !obj.instance_variables.empty?
247       return nil
248     end
249     arytype = Mapping.obj2element(obj)
250     if arytype.name
251       arytype.namespace ||= RubyTypeNamespace
252     else
253       arytype = XSD::AnyTypeName
254     end
255     soap_obj = SOAPArray.new(ValueArrayName, 1, arytype)
256     mark_marshalled_obj(obj, soap_obj)
257     obj.each do |item|
258       soap_obj.add(Mapping._obj2soap(item, map))
259     end
260     soap_obj
261   end
262
263   def soap2obj(obj_class, node, info, map)
264     obj = Mapping.create_empty_object(obj_class)
265     mark_unmarshalled_obj(node, obj)
266     node.soap2array(obj) do |elem|
267       elem ? Mapping._soap2obj(elem, map) : nil
268     end
269     return true, obj
270   end
271 end
272
273 class TypedArrayFactory_ < Factory
274   def initialize(allow_original_mapping = false)
275     super()
276     @allow_original_mapping = allow_original_mapping
277   end
278
279   def obj2soap(soap_class, obj, info, map)
280     if !@allow_original_mapping and !obj.instance_variables.empty?
281       return nil
282     end
283     arytype = info[:type] || info[0]
284     soap_obj = SOAPArray.new(ValueArrayName, 1, arytype)
285     mark_marshalled_obj(obj, soap_obj)
286     obj.each do |var|
287       soap_obj.add(Mapping._obj2soap(var, map))
288     end
289     soap_obj
290   end
291
292   def soap2obj(obj_class, node, info, map)
293     if node.rank > 1
294       return false
295     end
296     arytype = info[:type] || info[0]
297     unless node.arytype == arytype
298       return false
299     end
300     obj = Mapping.create_empty_object(obj_class)
301     mark_unmarshalled_obj(node, obj)
302     node.soap2array(obj) do |elem|
303       elem ? Mapping._soap2obj(elem, map) : nil
304     end
305     return true, obj
306   end
307 end
308
309 class TypedStructFactory_ < Factory
310   def obj2soap(soap_class, obj, info, map)
311     type = info[:type] || info[0]
312     soap_obj = soap_class.new(type)
313     mark_marshalled_obj(obj, soap_obj)
314     if obj.class <= SOAP::Marshallable
315       setiv2soap(soap_obj, obj, map)
316     else
317       # allow to serialize an instance of unmarked class
318       setiv2soap(soap_obj, obj, map)
319     end
320     soap_obj
321   end
322
323   def soap2obj(obj_class, node, info, map)
324     type = info[:type] || info[0]
325     unless node.type == type
326       return false
327     end
328     obj = Mapping.create_empty_object(obj_class)
329     mark_unmarshalled_obj(node, obj)
330     setiv2obj(obj, node, map)
331     return true, obj
332   end
333 end
334
335 MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map')
336 class HashFactory_ < Factory
337   def initialize(allow_original_mapping = false)
338     super()
339     @allow_original_mapping = allow_original_mapping
340   end
341
342   def obj2soap(soap_class, obj, info, map)
343     if !@allow_original_mapping and !obj.instance_variables.empty?
344       return nil
345     end
346     if !obj.default.nil? or
347         (obj.respond_to?(:default_proc) and obj.default_proc)
348       return nil
349     end
350     soap_obj = SOAPStruct.new(MapQName)
351     mark_marshalled_obj(obj, soap_obj)
352     obj.each do |key, value|
353       elem = SOAPStruct.new
354       elem.add("key", Mapping._obj2soap(key, map))
355       elem.add("value", Mapping._obj2soap(value, map))
356       # ApacheAxis allows only 'item' here.
357       soap_obj.add("item", elem)
358     end
359     soap_obj
360   end
361
362   def soap2obj(obj_class, node, info, map)
363     unless node.type == MapQName
364       return false
365     end
366     if node.class == SOAPStruct and node.key?('default')
367       return false
368     end
369     obj = Mapping.create_empty_object(obj_class)
370     mark_unmarshalled_obj(node, obj)
371     if node.class == SOAPStruct
372       node.each do |key, value|
373         obj[Mapping._soap2obj(value['key'], map)] =
374           Mapping._soap2obj(value['value'], map)
375       end
376     else
377       node.each do |value|
378         obj[Mapping._soap2obj(value['key'], map)] =
379           Mapping._soap2obj(value['value'], map)
380       end
381     end
382     return true, obj
383   end
384 end
385
386
387 end
388 end
Note: See TracBrowser for help on using the browser.