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

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

Video extension to Greenstone

File size: 11.4 KB
Line 
1# SOAP4R - WSDL literal mapping registry.
2# Copyright (C) 2004, 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
9require 'soap/baseData'
10require 'soap/mapping/mapping'
11require 'soap/mapping/typeMap'
12require 'xsd/codegen/gensupport'
13require 'xsd/namedelements'
14
15
16module SOAP
17module Mapping
18
19
20class WSDLLiteralRegistry < Registry
21 attr_reader :definedelements
22 attr_reader :definedtypes
23 attr_accessor :excn_handler_obj2soap
24 attr_accessor :excn_handler_soap2obj
25
26 def initialize(definedtypes = XSD::NamedElements::Empty,
27 definedelements = XSD::NamedElements::Empty)
28 @definedtypes = definedtypes
29 @definedelements = definedelements
30 @excn_handler_obj2soap = nil
31 @excn_handler_soap2obj = nil
32 @schema_element_cache = {}
33 @schema_attribute_cache = {}
34 end
35
36 def obj2soap(obj, qname)
37 soap_obj = nil
38 if ele = @definedelements[qname]
39 soap_obj = obj2elesoap(obj, ele)
40 elsif type = @definedtypes[qname]
41 soap_obj = obj2typesoap(obj, type, true)
42 else
43 soap_obj = any2soap(obj, qname)
44 end
45 return soap_obj if soap_obj
46 if @excn_handler_obj2soap
47 soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj|
48 Mapping.obj2soap(yield_obj, nil, nil, MAPPING_OPT)
49 }
50 return soap_obj if soap_obj
51 end
52 raise MappingError.new("cannot map #{obj.class.name} as #{qname}")
53 end
54
55 # node should be a SOAPElement
56 def soap2obj(node, obj_class = nil)
57 # obj_class is given when rpc/literal service. but ignored for now.
58 begin
59 return any2obj(node)
60 rescue MappingError
61 end
62 if @excn_handler_soap2obj
63 begin
64 return @excn_handler_soap2obj.call(node) { |yield_node|
65 Mapping.soap2obj(yield_node, nil, nil, MAPPING_OPT)
66 }
67 rescue Exception
68 end
69 end
70 if node.respond_to?(:type)
71 raise MappingError.new("cannot map #{node.type.name} to Ruby object")
72 else
73 raise MappingError.new("cannot map #{node.elename.name} to Ruby object")
74 end
75 end
76
77private
78
79 MAPPING_OPT = { :no_reference => true }
80
81 def obj2elesoap(obj, ele)
82 o = nil
83 qualified = (ele.elementform == 'qualified')
84 if ele.type
85 if type = @definedtypes[ele.type]
86 o = obj2typesoap(obj, type, qualified)
87 elsif type = TypeMap[ele.type]
88 o = base2soap(obj, type)
89 else
90 raise MappingError.new("cannot find type #{ele.type}")
91 end
92 elsif ele.local_complextype
93 o = obj2typesoap(obj, ele.local_complextype, qualified)
94 add_attributes2soap(obj, o)
95 elsif ele.local_simpletype
96 o = obj2typesoap(obj, ele.local_simpletype, qualified)
97 else
98 raise MappingError.new('illegal schema?')
99 end
100 o.elename = ele.name
101 o
102 end
103
104 def obj2typesoap(obj, type, qualified)
105 if type.is_a?(::WSDL::XMLSchema::SimpleType)
106 simpleobj2soap(obj, type)
107 else
108 complexobj2soap(obj, type, qualified)
109 end
110 end
111
112 def simpleobj2soap(obj, type)
113 type.check_lexical_format(obj)
114 return SOAPNil.new if obj.nil? # ToDo: check nillable.
115 o = base2soap(obj, TypeMap[type.base])
116 o
117 end
118
119 def complexobj2soap(obj, type, qualified)
120 o = SOAPElement.new(type.name)
121 o.qualified = qualified
122 type.each_element do |child_ele|
123 child = Mapping.get_attribute(obj, child_ele.name.name)
124 if child.nil?
125 if child_ele.nillable
126 # ToDo: test
127 # add empty element
128 child_soap = obj2elesoap(nil, child_ele)
129 o.add(child_soap)
130 elsif Integer(child_ele.minoccurs) == 0
131 # nothing to do
132 else
133 raise MappingError.new("nil not allowed: #{child_ele.name.name}")
134 end
135 elsif child_ele.map_as_array?
136 child.each do |item|
137 child_soap = obj2elesoap(item, child_ele)
138 o.add(child_soap)
139 end
140 else
141 child_soap = obj2elesoap(child, child_ele)
142 o.add(child_soap)
143 end
144 end
145 o
146 end
147
148 def any2soap(obj, qname)
149 if obj.is_a?(SOAPElement)
150 obj
151 elsif obj.class.class_variables.include?('@@schema_element')
152 stubobj2soap(obj, qname)
153 elsif obj.is_a?(SOAP::Mapping::Object)
154 mappingobj2soap(obj, qname)
155 elsif obj.is_a?(Hash)
156 ele = SOAPElement.from_obj(obj)
157 ele.elename = qname
158 ele
159 else
160 # expected to be a basetype or an anyType.
161 # SOAPStruct, etc. is used instead of SOAPElement.
162 begin
163 ele = Mapping.obj2soap(obj, nil, nil, MAPPING_OPT)
164 ele.elename = qname
165 ele
166 rescue MappingError
167 ele = SOAPElement.new(qname, obj.to_s)
168 end
169 if obj.respond_to?(:__xmlattr)
170 obj.__xmlattr.each do |key, value|
171 ele.extraattr[key] = value
172 end
173 end
174 ele
175 end
176 end
177
178 def stubobj2soap(obj, qname)
179 ele = SOAPElement.new(qname)
180 ele.qualified =
181 (obj.class.class_variables.include?('@@schema_qualified') and
182 obj.class.class_eval('@@schema_qualified'))
183 add_elements2soap(obj, ele)
184 add_attributes2soap(obj, ele)
185 ele
186 end
187
188 def mappingobj2soap(obj, qname)
189 ele = SOAPElement.new(qname)
190 obj.__xmlele.each do |key, value|
191 if value.is_a?(::Array)
192 value.each do |item|
193 ele.add(obj2soap(item, key))
194 end
195 else
196 ele.add(obj2soap(value, key))
197 end
198 end
199 obj.__xmlattr.each do |key, value|
200 ele.extraattr[key] = value
201 end
202 ele
203 end
204
205 def add_elements2soap(obj, ele)
206 elements, as_array = schema_element_definition(obj.class)
207 if elements
208 elements.each do |elename, type|
209 if child = Mapping.get_attribute(obj, elename.name)
210 if as_array.include?(elename.name)
211 child.each do |item|
212 ele.add(obj2soap(item, elename))
213 end
214 else
215 ele.add(obj2soap(child, elename))
216 end
217 elsif obj.is_a?(::Array) and as_array.include?(elename.name)
218 obj.each do |item|
219 ele.add(obj2soap(item, elename))
220 end
221 end
222 end
223 end
224 end
225
226 def add_attributes2soap(obj, ele)
227 attributes = schema_attribute_definition(obj.class)
228 if attributes
229 attributes.each do |qname, param|
230 attr = obj.__send__('xmlattr_' +
231 XSD::CodeGen::GenSupport.safevarname(qname.name))
232 ele.extraattr[qname] = attr
233 end
234 end
235 end
236
237 def base2soap(obj, type)
238 soap_obj = nil
239 if type <= XSD::XSDString
240 str = XSD::Charset.encoding_conv(obj.to_s,
241 Thread.current[:SOAPExternalCES], XSD::Charset.encoding)
242 soap_obj = type.new(str)
243 else
244 soap_obj = type.new(obj)
245 end
246 soap_obj
247 end
248
249 def anytype2obj(node)
250 if node.is_a?(::SOAP::SOAPBasetype)
251 return node.data
252 end
253 klass = ::SOAP::Mapping::Object
254 obj = klass.new
255 obj
256 end
257
258 def any2obj(node, obj_class = nil)
259 unless obj_class
260 typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name)
261 obj_class = Mapping.class_from_name(typestr)
262 end
263 if obj_class and obj_class.class_variables.include?('@@schema_element')
264 soapele2stubobj(node, obj_class)
265 elsif node.is_a?(SOAPElement) or node.is_a?(SOAPStruct)
266 # SOAPArray for literal?
267 soapele2plainobj(node)
268 else
269 obj = Mapping.soap2obj(node, nil, obj_class, MAPPING_OPT)
270 add_attributes2plainobj(node, obj)
271 obj
272 end
273 end
274
275 def soapele2stubobj(node, obj_class)
276 obj = Mapping.create_empty_object(obj_class)
277 add_elements2stubobj(node, obj)
278 add_attributes2stubobj(node, obj)
279 obj
280 end
281
282 def soapele2plainobj(node)
283 obj = anytype2obj(node)
284 add_elements2plainobj(node, obj)
285 add_attributes2plainobj(node, obj)
286 obj
287 end
288
289 def add_elements2stubobj(node, obj)
290 elements, as_array = schema_element_definition(obj.class)
291 vars = {}
292 node.each do |name, value|
293 item = elements.find { |k, v| k.name == name }
294 if item
295 elename, class_name = item
296 if klass = Mapping.class_from_name(class_name)
297 # klass must be a SOAPBasetype or a class
298 if klass.ancestors.include?(::SOAP::SOAPBasetype)
299 if value.respond_to?(:data)
300 child = klass.new(value.data).data
301 else
302 child = klass.new(nil).data
303 end
304 else
305 child = any2obj(value, klass)
306 end
307 elsif klass = Mapping.module_from_name(class_name)
308 # simpletype
309 if value.respond_to?(:data)
310 child = value.data
311 else
312 raise MappingError.new(
313 "cannot map to a module value: #{class_name}")
314 end
315 else
316 raise MappingError.new("unknown class/module: #{class_name}")
317 end
318 else # untyped element is treated as anyType.
319 child = any2obj(value)
320 end
321 if as_array.include?(elename.name)
322 (vars[name] ||= []) << child
323 else
324 vars[name] = child
325 end
326 end
327 Mapping.set_attributes(obj, vars)
328 end
329
330 def add_attributes2stubobj(node, obj)
331 if attributes = schema_attribute_definition(obj.class)
332 define_xmlattr(obj)
333 attributes.each do |qname, class_name|
334 attr = node.extraattr[qname]
335 next if attr.nil? or attr.empty?
336 klass = Mapping.class_from_name(class_name)
337 if klass.ancestors.include?(::SOAP::SOAPBasetype)
338 child = klass.new(attr).data
339 else
340 child = attr
341 end
342 obj.__xmlattr[qname] = child
343 define_xmlattr_accessor(obj, qname)
344 end
345 end
346 end
347
348 def add_elements2plainobj(node, obj)
349 node.each do |name, value|
350 obj.__add_xmlele_value(value.elename, any2obj(value))
351 end
352 end
353
354 def add_attributes2plainobj(node, obj)
355 return if node.extraattr.empty?
356 define_xmlattr(obj)
357 node.extraattr.each do |qname, value|
358 obj.__xmlattr[qname] = value
359 define_xmlattr_accessor(obj, qname)
360 end
361 end
362
363 if RUBY_VERSION > "1.7.0"
364 def define_xmlattr_accessor(obj, qname)
365 name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
366 Mapping.define_attr_accessor(obj, 'xmlattr_' + name,
367 proc { @__xmlattr[qname] },
368 proc { |value| @__xmlattr[qname] = value })
369 end
370 else
371 def define_xmlattr_accessor(obj, qname)
372 name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
373 obj.instance_eval <<-EOS
374 def #{name}
375 @__xmlattr[#{qname.dump}]
376 end
377
378 def #{name}=(value)
379 @__xmlattr[#{qname.dump}] = value
380 end
381 EOS
382 end
383 end
384
385 if RUBY_VERSION > "1.7.0"
386 def define_xmlattr(obj)
387 obj.instance_variable_set('@__xmlattr', {})
388 unless obj.respond_to?(:__xmlattr)
389 Mapping.define_attr_accessor(obj, :__xmlattr, proc { @__xmlattr })
390 end
391 end
392 else
393 def define_xmlattr(obj)
394 obj.instance_variable_set('@__xmlattr', {})
395 unless obj.respond_to?(:__xmlattr)
396 obj.instance_eval <<-EOS
397 def __xmlattr
398 @__xmlattr
399 end
400 EOS
401 end
402 end
403 end
404
405 # it caches @@schema_element. this means that @@schema_element must not be
406 # changed while a lifetime of a WSDLLiteralRegistry.
407 def schema_element_definition(klass)
408 @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass)
409 end
410
411 def schema_attribute_definition(klass)
412 @schema_attribute_cache[klass] ||= Mapping.schema_attribute_definition(klass)
413 end
414end
415
416
417end
418end
Note: See TracBrowser for help on using the repository browser.