/tools/Ruby/lib/ruby/1.8/soap/mapping/wsdlliteralregistry.rb

http://github.com/agross/netopenspace · Ruby · 418 lines · 364 code · 37 blank · 17 comment · 38 complexity · 75531d025e845e746c7c804a03df4709 MD5 · raw file

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