source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/soap/mapping/rubytypeFactory.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 15.1 KB
Line 
1# SOAP4R - Ruby type mapping factory.
2# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi <[email protected]>.
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
9module SOAP
10module Mapping
11
12
13class RubytypeFactory < Factory
14 TYPE_STRING = XSD::QName.new(RubyTypeNamespace, 'String')
15 TYPE_TIME = XSD::QName.new(RubyTypeNamespace, 'Time')
16 TYPE_ARRAY = XSD::QName.new(RubyTypeNamespace, 'Array')
17 TYPE_REGEXP = XSD::QName.new(RubyTypeNamespace, 'Regexp')
18 TYPE_RANGE = XSD::QName.new(RubyTypeNamespace, 'Range')
19 TYPE_CLASS = XSD::QName.new(RubyTypeNamespace, 'Class')
20 TYPE_MODULE = XSD::QName.new(RubyTypeNamespace, 'Module')
21 TYPE_SYMBOL = XSD::QName.new(RubyTypeNamespace, 'Symbol')
22 TYPE_STRUCT = XSD::QName.new(RubyTypeNamespace, 'Struct')
23 TYPE_HASH = XSD::QName.new(RubyTypeNamespace, 'Map')
24
25 def initialize(config = {})
26 @config = config
27 @allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
28 @config[:allow_untyped_struct] : true
29 @allow_original_mapping = @config.key?(:allow_original_mapping) ?
30 @config[:allow_original_mapping] : false
31 @string_factory = StringFactory_.new(true)
32 @basetype_factory = BasetypeFactory_.new(true)
33 @datetime_factory = DateTimeFactory_.new(true)
34 @array_factory = ArrayFactory_.new(true)
35 @hash_factory = HashFactory_.new(true)
36 end
37
38 def obj2soap(soap_class, obj, info, map)
39 param = nil
40 case obj
41 when ::String
42 unless @allow_original_mapping
43 return nil
44 end
45 param = @string_factory.obj2soap(SOAPString, obj, info, map)
46 if obj.class != String
47 param.extraattr[RubyTypeName] = obj.class.name
48 end
49 addiv2soapattr(param, obj, map)
50 when ::Time
51 unless @allow_original_mapping
52 return nil
53 end
54 param = @datetime_factory.obj2soap(SOAPDateTime, obj, info, map)
55 if obj.class != Time
56 param.extraattr[RubyTypeName] = obj.class.name
57 end
58 addiv2soapattr(param, obj, map)
59 when ::Array
60 unless @allow_original_mapping
61 return nil
62 end
63 param = @array_factory.obj2soap(nil, obj, info, map)
64 if obj.class != Array
65 param.extraattr[RubyTypeName] = obj.class.name
66 end
67 addiv2soapattr(param, obj, map)
68 when ::NilClass
69 unless @allow_original_mapping
70 return nil
71 end
72 param = @basetype_factory.obj2soap(SOAPNil, obj, info, map)
73 addiv2soapattr(param, obj, map)
74 when ::FalseClass, ::TrueClass
75 unless @allow_original_mapping
76 return nil
77 end
78 param = @basetype_factory.obj2soap(SOAPBoolean, obj, info, map)
79 addiv2soapattr(param, obj, map)
80 when ::Integer
81 unless @allow_original_mapping
82 return nil
83 end
84 param = @basetype_factory.obj2soap(SOAPInt, obj, info, map)
85 param ||= @basetype_factory.obj2soap(SOAPInteger, obj, info, map)
86 param ||= @basetype_factory.obj2soap(SOAPDecimal, obj, info, map)
87 addiv2soapattr(param, obj, map)
88 when ::Float
89 unless @allow_original_mapping
90 return nil
91 end
92 param = @basetype_factory.obj2soap(SOAPDouble, obj, info, map)
93 if obj.class != Float
94 param.extraattr[RubyTypeName] = obj.class.name
95 end
96 addiv2soapattr(param, obj, map)
97 when ::Hash
98 unless @allow_original_mapping
99 return nil
100 end
101 if obj.respond_to?(:default_proc) && obj.default_proc
102 raise TypeError.new("cannot dump hash with default proc")
103 end
104 param = SOAPStruct.new(TYPE_HASH)
105 mark_marshalled_obj(obj, param)
106 if obj.class != Hash
107 param.extraattr[RubyTypeName] = obj.class.name
108 end
109 obj.each do |key, value|
110 elem = SOAPStruct.new # Undefined type.
111 elem.add("key", Mapping._obj2soap(key, map))
112 elem.add("value", Mapping._obj2soap(value, map))
113 param.add("item", elem)
114 end
115 param.add('default', Mapping._obj2soap(obj.default, map))
116 addiv2soapattr(param, obj, map)
117 when ::Regexp
118 unless @allow_original_mapping
119 return nil
120 end
121 param = SOAPStruct.new(TYPE_REGEXP)
122 mark_marshalled_obj(obj, param)
123 if obj.class != Regexp
124 param.extraattr[RubyTypeName] = obj.class.name
125 end
126 param.add('source', SOAPBase64.new(obj.source))
127 if obj.respond_to?('options')
128 # Regexp#options is from Ruby/1.7
129 options = obj.options
130 else
131 options = 0
132 obj.inspect.sub(/^.*\//, '').each_byte do |c|
133 options += case c
134 when ?i
135 1
136 when ?x
137 2
138 when ?m
139 4
140 when ?n
141 16
142 when ?e
143 32
144 when ?s
145 48
146 when ?u
147 64
148 end
149 end
150 end
151 param.add('options', SOAPInt.new(options))
152 addiv2soapattr(param, obj, map)
153 when ::Range
154 unless @allow_original_mapping
155 return nil
156 end
157 param = SOAPStruct.new(TYPE_RANGE)
158 mark_marshalled_obj(obj, param)
159 if obj.class != Range
160 param.extraattr[RubyTypeName] = obj.class.name
161 end
162 param.add('begin', Mapping._obj2soap(obj.begin, map))
163 param.add('end', Mapping._obj2soap(obj.end, map))
164 param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?))
165 addiv2soapattr(param, obj, map)
166 when ::Class
167 unless @allow_original_mapping
168 return nil
169 end
170 if obj.to_s[0] == ?#
171 raise TypeError.new("can't dump anonymous class #{obj}")
172 end
173 param = SOAPStruct.new(TYPE_CLASS)
174 mark_marshalled_obj(obj, param)
175 param.add('name', SOAPString.new(obj.name))
176 addiv2soapattr(param, obj, map)
177 when ::Module
178 unless @allow_original_mapping
179 return nil
180 end
181 if obj.to_s[0] == ?#
182 raise TypeError.new("can't dump anonymous module #{obj}")
183 end
184 param = SOAPStruct.new(TYPE_MODULE)
185 mark_marshalled_obj(obj, param)
186 param.add('name', SOAPString.new(obj.name))
187 addiv2soapattr(param, obj, map)
188 when ::Symbol
189 unless @allow_original_mapping
190 return nil
191 end
192 param = SOAPStruct.new(TYPE_SYMBOL)
193 mark_marshalled_obj(obj, param)
194 param.add('id', SOAPString.new(obj.id2name))
195 addiv2soapattr(param, obj, map)
196 when ::Struct
197 unless @allow_original_mapping
198 # treat it as an user defined class. [ruby-talk:104980]
199 #param = unknownobj2soap(soap_class, obj, info, map)
200 param = SOAPStruct.new(XSD::AnyTypeName)
201 mark_marshalled_obj(obj, param)
202 obj.members.each do |member|
203 param.add(Mapping.name2elename(member),
204 Mapping._obj2soap(obj[member], map))
205 end
206 else
207 param = SOAPStruct.new(TYPE_STRUCT)
208 mark_marshalled_obj(obj, param)
209 param.add('type', ele_type = SOAPString.new(obj.class.to_s))
210 ele_member = SOAPStruct.new
211 obj.members.each do |member|
212 ele_member.add(Mapping.name2elename(member),
213 Mapping._obj2soap(obj[member], map))
214 end
215 param.add('member', ele_member)
216 addiv2soapattr(param, obj, map)
217 end
218 when ::IO, ::Binding, ::Continuation, ::Data, ::Dir, ::File::Stat,
219 ::MatchData, Method, ::Proc, ::Thread, ::ThreadGroup
220 # from 1.8: Process::Status, UnboundMethod
221 return nil
222 when ::SOAP::Mapping::Object
223 param = SOAPStruct.new(XSD::AnyTypeName)
224 mark_marshalled_obj(obj, param)
225 obj.__xmlele.each do |key, value|
226 param.add(key.name, Mapping._obj2soap(value, map))
227 end
228 obj.__xmlattr.each do |key, value|
229 param.extraattr[key] = value
230 end
231 when ::Exception
232 typestr = Mapping.name2elename(obj.class.to_s)
233 param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr))
234 mark_marshalled_obj(obj, param)
235 param.add('message', Mapping._obj2soap(obj.message, map))
236 param.add('backtrace', Mapping._obj2soap(obj.backtrace, map))
237 addiv2soapattr(param, obj, map)
238 else
239 param = unknownobj2soap(soap_class, obj, info, map)
240 end
241 param
242 end
243
244 def soap2obj(obj_class, node, info, map)
245 rubytype = node.extraattr[RubyTypeName]
246 if rubytype or node.type.namespace == RubyTypeNamespace
247 rubytype2obj(node, info, map, rubytype)
248 elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName
249 anytype2obj(node, info, map)
250 else
251 unknowntype2obj(node, info, map)
252 end
253 end
254
255private
256
257 def addiv2soapattr(node, obj, map)
258 return if obj.instance_variables.empty?
259 ivars = SOAPStruct.new # Undefined type.
260 setiv2soap(ivars, obj, map)
261 node.extraattr[RubyIVarName] = ivars
262 end
263
264 def unknownobj2soap(soap_class, obj, info, map)
265 if obj.class.name.empty?
266 raise TypeError.new("can't dump anonymous class #{obj}")
267 end
268 singleton_class = class << obj; self; end
269 if !singleton_methods_true(obj).empty? or
270 !singleton_class.instance_variables.empty?
271 raise TypeError.new("singleton can't be dumped #{obj}")
272 end
273 if !(singleton_class.ancestors - obj.class.ancestors).empty?
274 typestr = Mapping.name2elename(obj.class.to_s)
275 type = XSD::QName.new(RubyTypeNamespace, typestr)
276 else
277 type = Mapping.class2element(obj.class)
278 end
279 param = SOAPStruct.new(type)
280 mark_marshalled_obj(obj, param)
281 setiv2soap(param, obj, map)
282 param
283 end
284
285 if RUBY_VERSION >= '1.8.0'
286 def singleton_methods_true(obj)
287 obj.singleton_methods(true)
288 end
289 else
290 def singleton_methods_true(obj)
291 obj.singleton_methods
292 end
293 end
294
295 def rubytype2obj(node, info, map, rubytype)
296 klass = rubytype ? Mapping.class_from_name(rubytype) : nil
297 obj = nil
298 case node
299 when SOAPString
300 return @string_factory.soap2obj(klass || String, node, info, map)
301 when SOAPDateTime
302 #return @datetime_factory.soap2obj(klass || Time, node, info, map)
303 klass ||= Time
304 t = node.to_time
305 arg = [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.usec]
306 obj = t.gmt? ? klass.gm(*arg) : klass.local(*arg)
307 mark_unmarshalled_obj(node, obj)
308 return true, obj
309 when SOAPArray
310 return @array_factory.soap2obj(klass || Array, node, info, map)
311 when SOAPNil, SOAPBoolean, SOAPInt, SOAPInteger, SOAPDecimal, SOAPDouble
312 return @basetype_factory.soap2obj(nil, node, info, map)
313 when SOAPStruct
314 return rubytypestruct2obj(node, info, map, rubytype)
315 else
316 raise
317 end
318 end
319
320 def rubytypestruct2obj(node, info, map, rubytype)
321 klass = rubytype ? Mapping.class_from_name(rubytype) : nil
322 obj = nil
323 case node.type
324 when TYPE_HASH
325 klass = rubytype ? Mapping.class_from_name(rubytype) : Hash
326 obj = Mapping.create_empty_object(klass)
327 mark_unmarshalled_obj(node, obj)
328 node.each do |key, value|
329 next unless key == 'item'
330 obj[Mapping._soap2obj(value['key'], map)] =
331 Mapping._soap2obj(value['value'], map)
332 end
333 if node.key?('default')
334 obj.default = Mapping._soap2obj(node['default'], map)
335 end
336 when TYPE_REGEXP
337 klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp
338 obj = Mapping.create_empty_object(klass)
339 mark_unmarshalled_obj(node, obj)
340 source = node['source'].string
341 options = node['options'].data || 0
342 Regexp.instance_method(:initialize).bind(obj).call(source, options)
343 when TYPE_RANGE
344 klass = rubytype ? Mapping.class_from_name(rubytype) : Range
345 obj = Mapping.create_empty_object(klass)
346 mark_unmarshalled_obj(node, obj)
347 first = Mapping._soap2obj(node['begin'], map)
348 last = Mapping._soap2obj(node['end'], map)
349 exclude_end = node['exclude_end'].data
350 Range.instance_method(:initialize).bind(obj).call(first, last, exclude_end)
351 when TYPE_CLASS
352 obj = Mapping.class_from_name(node['name'].data)
353 when TYPE_MODULE
354 obj = Mapping.class_from_name(node['name'].data)
355 when TYPE_SYMBOL
356 obj = node['id'].data.intern
357 when TYPE_STRUCT
358 typestr = Mapping.elename2name(node['type'].data)
359 klass = Mapping.class_from_name(typestr)
360 if klass.nil?
361 return false
362 end
363 unless klass <= ::Struct
364 return false
365 end
366 obj = Mapping.create_empty_object(klass)
367 mark_unmarshalled_obj(node, obj)
368 node['member'].each do |name, value|
369 obj[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
370 end
371 else
372 return unknowntype2obj(node, info, map)
373 end
374 return true, obj
375 end
376
377 def anytype2obj(node, info, map)
378 case node
379 when SOAPBasetype
380 return true, node.data
381 when SOAPStruct
382 klass = ::SOAP::Mapping::Object
383 obj = klass.new
384 mark_unmarshalled_obj(node, obj)
385 node.each do |name, value|
386 obj.__add_xmlele_value(XSD::QName.new(nil, name),
387 Mapping._soap2obj(value, map))
388 end
389 unless node.extraattr.empty?
390 obj.instance_variable_set('@__xmlattr', node.extraattr)
391 end
392 return true, obj
393 else
394 return false
395 end
396 end
397
398 def unknowntype2obj(node, info, map)
399 case node
400 when SOAPBasetype
401 return true, node.data
402 when SOAPArray
403 return @array_factory.soap2obj(Array, node, info, map)
404 when SOAPStruct
405 obj = unknownstruct2obj(node, info, map)
406 return true, obj if obj
407 if !@allow_untyped_struct
408 return false
409 end
410 return anytype2obj(node, info, map)
411 else
412 # Basetype which is not defined...
413 return false
414 end
415 end
416
417 def unknownstruct2obj(node, info, map)
418 unless node.type.name
419 return nil
420 end
421 typestr = Mapping.elename2name(node.type.name)
422 klass = Mapping.class_from_name(typestr)
423 if klass.nil? and @allow_untyped_struct
424 klass = Mapping.class_from_name(typestr, true) # lenient
425 end
426 if klass.nil?
427 return nil
428 end
429 if klass <= ::Exception
430 return exception2obj(klass, node, map)
431 end
432 klass_type = Mapping.class2qname(klass)
433 return nil unless node.type.match(klass_type)
434 obj = nil
435 begin
436 obj = Mapping.create_empty_object(klass)
437 rescue
438 # type name "data" tries Data.new which raises TypeError
439 nil
440 end
441 mark_unmarshalled_obj(node, obj)
442 setiv2obj(obj, node, map)
443 obj
444 end
445
446 def exception2obj(klass, node, map)
447 message = Mapping._soap2obj(node['message'], map)
448 backtrace = Mapping._soap2obj(node['backtrace'], map)
449 obj = Mapping.create_empty_object(klass)
450 obj = obj.exception(message)
451 mark_unmarshalled_obj(node, obj)
452 obj.set_backtrace(backtrace)
453 obj
454 end
455
456 # Only creates empty array. Do String#replace it with real string.
457 def array2obj(node, map, rubytype)
458 klass = rubytype ? Mapping.class_from_name(rubytype) : Array
459 obj = Mapping.create_empty_object(klass)
460 mark_unmarshalled_obj(node, obj)
461 obj
462 end
463
464 # Only creates empty string. Do String#replace it with real string.
465 def string2obj(node, map, rubytype)
466 klass = rubytype ? Mapping.class_from_name(rubytype) : String
467 obj = Mapping.create_empty_object(klass)
468 mark_unmarshalled_obj(node, obj)
469 obj
470 end
471end
472
473
474end
475end
Note: See TracBrowser for help on using the repository browser.