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

http://github.com/agross/netopenspace · Ruby · 541 lines · 464 code · 62 blank · 15 comment · 35 complexity · e301efe2b01f4464e05afa6b3e37781f MD5 · raw file

  1. # SOAP4R - Mapping registry.
  2. # Copyright (C) 2000, 2001, 2002, 2003 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 'soap/mapping/factory'
  10. require 'soap/mapping/rubytypeFactory'
  11. module SOAP
  12. module Marshallable
  13. # @@type_ns = Mapping::RubyCustomTypeNamespace
  14. end
  15. module Mapping
  16. module MappedException; end
  17. RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
  18. RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends')
  19. RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars')
  20. # Inner class to pass an exception.
  21. class SOAPException; include Marshallable
  22. attr_reader :excn_type_name, :cause
  23. def initialize(e)
  24. @excn_type_name = Mapping.name2elename(e.class.to_s)
  25. @cause = e
  26. end
  27. def to_e
  28. if @cause.is_a?(::Exception)
  29. @cause.extend(::SOAP::Mapping::MappedException)
  30. return @cause
  31. elsif @cause.respond_to?(:message) and @cause.respond_to?(:backtrace)
  32. e = RuntimeError.new(@cause.message)
  33. e.set_backtrace(@cause.backtrace)
  34. return e
  35. end
  36. klass = Mapping.class_from_name(Mapping.elename2name(@excn_type_name.to_s))
  37. if klass.nil? or not klass <= ::Exception
  38. return RuntimeError.new(@cause.inspect)
  39. end
  40. obj = klass.new(@cause.message)
  41. obj.extend(::SOAP::Mapping::MappedException)
  42. obj
  43. end
  44. end
  45. # For anyType object: SOAP::Mapping::Object not ::Object
  46. class Object; include Marshallable
  47. def initialize
  48. @__xmlele_type = {}
  49. @__xmlele = []
  50. @__xmlattr = {}
  51. end
  52. def inspect
  53. sprintf("#<%s:0x%x%s>", self.class.name, __id__,
  54. @__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join)
  55. end
  56. def __xmlattr
  57. @__xmlattr
  58. end
  59. def __xmlele
  60. @__xmlele
  61. end
  62. def [](qname)
  63. unless qname.is_a?(XSD::QName)
  64. qname = XSD::QName.new(nil, qname)
  65. end
  66. @__xmlele.each do |k, v|
  67. return v if k == qname
  68. end
  69. # fallback
  70. @__xmlele.each do |k, v|
  71. return v if k.name == qname.name
  72. end
  73. nil
  74. end
  75. def []=(qname, value)
  76. unless qname.is_a?(XSD::QName)
  77. qname = XSD::QName.new(nil, qname)
  78. end
  79. found = false
  80. @__xmlele.each do |pair|
  81. if pair[0] == qname
  82. found = true
  83. pair[1] = value
  84. end
  85. end
  86. unless found
  87. __define_attr_accessor(qname)
  88. @__xmlele << [qname, value]
  89. end
  90. @__xmlele_type[qname] = :single
  91. end
  92. def __add_xmlele_value(qname, value)
  93. found = false
  94. @__xmlele.map! do |k, v|
  95. if k == qname
  96. found = true
  97. [k, __set_xmlele_value(k, v, value)]
  98. else
  99. [k, v]
  100. end
  101. end
  102. unless found
  103. __define_attr_accessor(qname)
  104. @__xmlele << [qname, value]
  105. @__xmlele_type[qname] = :single
  106. end
  107. value
  108. end
  109. private
  110. if RUBY_VERSION > "1.7.0"
  111. def __define_attr_accessor(qname)
  112. name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
  113. Mapping.define_attr_accessor(self, name,
  114. proc { self[qname] },
  115. proc { |value| self[qname] = value })
  116. end
  117. else
  118. def __define_attr_accessor(qname)
  119. name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
  120. instance_eval <<-EOS
  121. def #{name}
  122. self[#{qname.dump}]
  123. end
  124. def #{name}=(value)
  125. self[#{qname.dump}] = value
  126. end
  127. EOS
  128. end
  129. end
  130. def __set_xmlele_value(key, org, value)
  131. case @__xmlele_type[key]
  132. when :multi
  133. org << value
  134. org
  135. when :single
  136. @__xmlele_type[key] = :multi
  137. [org, value]
  138. else
  139. raise RuntimeError.new("unknown type")
  140. end
  141. end
  142. end
  143. class MappingError < Error; end
  144. class Registry
  145. class Map
  146. def initialize(registry)
  147. @obj2soap = {}
  148. @soap2obj = {}
  149. @registry = registry
  150. end
  151. def obj2soap(obj)
  152. klass = obj.class
  153. if map = @obj2soap[klass]
  154. map.each do |soap_class, factory, info|
  155. ret = factory.obj2soap(soap_class, obj, info, @registry)
  156. return ret if ret
  157. end
  158. end
  159. ancestors = klass.ancestors
  160. ancestors.delete(klass)
  161. ancestors.delete(::Object)
  162. ancestors.delete(::Kernel)
  163. ancestors.each do |klass|
  164. if map = @obj2soap[klass]
  165. map.each do |soap_class, factory, info|
  166. if info[:derived_class]
  167. ret = factory.obj2soap(soap_class, obj, info, @registry)
  168. return ret if ret
  169. end
  170. end
  171. end
  172. end
  173. nil
  174. end
  175. def soap2obj(node, klass = nil)
  176. if map = @soap2obj[node.class]
  177. map.each do |obj_class, factory, info|
  178. next if klass and obj_class != klass
  179. conv, obj = factory.soap2obj(obj_class, node, info, @registry)
  180. return true, obj if conv
  181. end
  182. end
  183. return false, nil
  184. end
  185. # Give priority to former entry.
  186. def init(init_map = [])
  187. clear
  188. init_map.reverse_each do |obj_class, soap_class, factory, info|
  189. add(obj_class, soap_class, factory, info)
  190. end
  191. end
  192. # Give priority to latter entry.
  193. def add(obj_class, soap_class, factory, info)
  194. info ||= {}
  195. (@obj2soap[obj_class] ||= []).unshift([soap_class, factory, info])
  196. (@soap2obj[soap_class] ||= []).unshift([obj_class, factory, info])
  197. end
  198. def clear
  199. @obj2soap.clear
  200. @soap2obj.clear
  201. end
  202. def find_mapped_soap_class(target_obj_class)
  203. map = @obj2soap[target_obj_class]
  204. map.empty? ? nil : map[0][1]
  205. end
  206. def find_mapped_obj_class(target_soap_class)
  207. map = @soap2obj[target_soap_class]
  208. map.empty? ? nil : map[0][0]
  209. end
  210. end
  211. StringFactory = StringFactory_.new
  212. BasetypeFactory = BasetypeFactory_.new
  213. DateTimeFactory = DateTimeFactory_.new
  214. ArrayFactory = ArrayFactory_.new
  215. Base64Factory = Base64Factory_.new
  216. URIFactory = URIFactory_.new
  217. TypedArrayFactory = TypedArrayFactory_.new
  218. TypedStructFactory = TypedStructFactory_.new
  219. HashFactory = HashFactory_.new
  220. SOAPBaseMap = [
  221. [::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
  222. [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
  223. [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
  224. [::String, ::SOAP::SOAPString, StringFactory],
  225. [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
  226. [::Date, ::SOAP::SOAPDate, DateTimeFactory],
  227. [::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
  228. [::Time, ::SOAP::SOAPTime, DateTimeFactory],
  229. [::Float, ::SOAP::SOAPDouble, BasetypeFactory,
  230. {:derived_class => true}],
  231. [::Float, ::SOAP::SOAPFloat, BasetypeFactory,
  232. {:derived_class => true}],
  233. [::Integer, ::SOAP::SOAPInt, BasetypeFactory,
  234. {:derived_class => true}],
  235. [::Integer, ::SOAP::SOAPLong, BasetypeFactory,
  236. {:derived_class => true}],
  237. [::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
  238. {:derived_class => true}],
  239. [::Integer, ::SOAP::SOAPShort, BasetypeFactory,
  240. {:derived_class => true}],
  241. [::Integer, ::SOAP::SOAPByte, BasetypeFactory,
  242. {:derived_class => true}],
  243. [::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory,
  244. {:derived_class => true}],
  245. [::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory,
  246. {:derived_class => true}],
  247. [::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory,
  248. {:derived_class => true}],
  249. [::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory,
  250. {:derived_class => true}],
  251. [::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory,
  252. {:derived_class => true}],
  253. [::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory,
  254. {:derived_class => true}],
  255. [::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory,
  256. {:derived_class => true}],
  257. [::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory,
  258. {:derived_class => true}],
  259. [::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory,
  260. {:derived_class => true}],
  261. [::String, ::SOAP::SOAPBase64, Base64Factory],
  262. [::String, ::SOAP::SOAPHexBinary, Base64Factory],
  263. [::String, ::SOAP::SOAPDecimal, BasetypeFactory],
  264. [::String, ::SOAP::SOAPDuration, BasetypeFactory],
  265. [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
  266. [::String, ::SOAP::SOAPGYear, BasetypeFactory],
  267. [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
  268. [::String, ::SOAP::SOAPGDay, BasetypeFactory],
  269. [::String, ::SOAP::SOAPGMonth, BasetypeFactory],
  270. [::String, ::SOAP::SOAPQName, BasetypeFactory],
  271. [::Hash, ::SOAP::SOAPArray, HashFactory],
  272. [::Hash, ::SOAP::SOAPStruct, HashFactory],
  273. [::Array, ::SOAP::SOAPArray, ArrayFactory,
  274. {:derived_class => true}],
  275. [::SOAP::Mapping::SOAPException,
  276. ::SOAP::SOAPStruct, TypedStructFactory,
  277. {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
  278. ]
  279. RubyOriginalMap = [
  280. [::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
  281. [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
  282. [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
  283. [::String, ::SOAP::SOAPString, StringFactory],
  284. [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
  285. [::Date, ::SOAP::SOAPDate, DateTimeFactory],
  286. [::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
  287. [::Time, ::SOAP::SOAPTime, DateTimeFactory],
  288. [::Float, ::SOAP::SOAPDouble, BasetypeFactory,
  289. {:derived_class => true}],
  290. [::Float, ::SOAP::SOAPFloat, BasetypeFactory,
  291. {:derived_class => true}],
  292. [::Integer, ::SOAP::SOAPInt, BasetypeFactory,
  293. {:derived_class => true}],
  294. [::Integer, ::SOAP::SOAPLong, BasetypeFactory,
  295. {:derived_class => true}],
  296. [::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
  297. {:derived_class => true}],
  298. [::Integer, ::SOAP::SOAPShort, BasetypeFactory,
  299. {:derived_class => true}],
  300. [::Integer, ::SOAP::SOAPByte, BasetypeFactory,
  301. {:derived_class => true}],
  302. [::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory,
  303. {:derived_class => true}],
  304. [::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory,
  305. {:derived_class => true}],
  306. [::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory,
  307. {:derived_class => true}],
  308. [::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory,
  309. {:derived_class => true}],
  310. [::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory,
  311. {:derived_class => true}],
  312. [::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory,
  313. {:derived_class => true}],
  314. [::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory,
  315. {:derived_class => true}],
  316. [::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory,
  317. {:derived_class => true}],
  318. [::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory,
  319. {:derived_class => true}],
  320. [::String, ::SOAP::SOAPBase64, Base64Factory],
  321. [::String, ::SOAP::SOAPHexBinary, Base64Factory],
  322. [::String, ::SOAP::SOAPDecimal, BasetypeFactory],
  323. [::String, ::SOAP::SOAPDuration, BasetypeFactory],
  324. [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
  325. [::String, ::SOAP::SOAPGYear, BasetypeFactory],
  326. [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
  327. [::String, ::SOAP::SOAPGDay, BasetypeFactory],
  328. [::String, ::SOAP::SOAPGMonth, BasetypeFactory],
  329. [::String, ::SOAP::SOAPQName, BasetypeFactory],
  330. [::Hash, ::SOAP::SOAPArray, HashFactory],
  331. [::Hash, ::SOAP::SOAPStruct, HashFactory],
  332. # Does not allow Array's subclass here.
  333. [::Array, ::SOAP::SOAPArray, ArrayFactory],
  334. [::SOAP::Mapping::SOAPException,
  335. ::SOAP::SOAPStruct, TypedStructFactory,
  336. {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
  337. ]
  338. attr_accessor :default_factory
  339. attr_accessor :excn_handler_obj2soap
  340. attr_accessor :excn_handler_soap2obj
  341. def initialize(config = {})
  342. @config = config
  343. @map = Map.new(self)
  344. if @config[:allow_original_mapping]
  345. @allow_original_mapping = true
  346. @map.init(RubyOriginalMap)
  347. else
  348. @allow_original_mapping = false
  349. @map.init(SOAPBaseMap)
  350. end
  351. @allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
  352. @config[:allow_untyped_struct] : true
  353. @rubytype_factory = RubytypeFactory.new(
  354. :allow_untyped_struct => @allow_untyped_struct,
  355. :allow_original_mapping => @allow_original_mapping
  356. )
  357. @default_factory = @rubytype_factory
  358. @excn_handler_obj2soap = nil
  359. @excn_handler_soap2obj = nil
  360. end
  361. def add(obj_class, soap_class, factory, info = nil)
  362. @map.add(obj_class, soap_class, factory, info)
  363. end
  364. alias set add
  365. # general Registry ignores type_qname
  366. def obj2soap(obj, type_qname = nil)
  367. soap = _obj2soap(obj)
  368. if @allow_original_mapping
  369. addextend2soap(soap, obj)
  370. end
  371. soap
  372. end
  373. def soap2obj(node, klass = nil)
  374. obj = _soap2obj(node, klass)
  375. if @allow_original_mapping
  376. addextend2obj(obj, node.extraattr[RubyExtendName])
  377. addiv2obj(obj, node.extraattr[RubyIVarName])
  378. end
  379. obj
  380. end
  381. def find_mapped_soap_class(obj_class)
  382. @map.find_mapped_soap_class(obj_class)
  383. end
  384. def find_mapped_obj_class(soap_class)
  385. @map.find_mapped_obj_class(soap_class)
  386. end
  387. private
  388. def _obj2soap(obj)
  389. ret = nil
  390. if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray)
  391. obj.replace do |ele|
  392. Mapping._obj2soap(ele, self)
  393. end
  394. return obj
  395. elsif obj.is_a?(SOAPBasetype)
  396. return obj
  397. end
  398. begin
  399. ret = @map.obj2soap(obj) ||
  400. @default_factory.obj2soap(nil, obj, nil, self)
  401. return ret if ret
  402. rescue MappingError
  403. end
  404. if @excn_handler_obj2soap
  405. ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
  406. Mapping._obj2soap(yield_obj, self)
  407. }
  408. return ret if ret
  409. end
  410. raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.")
  411. end
  412. # Might return nil as a mapping result.
  413. def _soap2obj(node, klass = nil)
  414. if node.extraattr.key?(RubyTypeName)
  415. conv, obj = @rubytype_factory.soap2obj(nil, node, nil, self)
  416. return obj if conv
  417. else
  418. conv, obj = @map.soap2obj(node, klass)
  419. return obj if conv
  420. conv, obj = @default_factory.soap2obj(nil, node, nil, self)
  421. return obj if conv
  422. end
  423. if @excn_handler_soap2obj
  424. begin
  425. return @excn_handler_soap2obj.call(node) { |yield_node|
  426. Mapping._soap2obj(yield_node, self)
  427. }
  428. rescue Exception
  429. end
  430. end
  431. raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.")
  432. end
  433. def addiv2obj(obj, attr)
  434. return unless attr
  435. vars = {}
  436. attr.__getobj__.each do |name, value|
  437. vars[name] = Mapping._soap2obj(value, self)
  438. end
  439. Mapping.set_attributes(obj, vars)
  440. end
  441. if RUBY_VERSION >= '1.8.0'
  442. def addextend2obj(obj, attr)
  443. return unless attr
  444. attr.split(/ /).reverse_each do |mstr|
  445. obj.extend(Mapping.module_from_name(mstr))
  446. end
  447. end
  448. else
  449. # (class < false; self; end).ancestors includes "TrueClass" under 1.6...
  450. def addextend2obj(obj, attr)
  451. return unless attr
  452. attr.split(/ /).reverse_each do |mstr|
  453. m = Mapping.module_from_name(mstr)
  454. obj.extend(m)
  455. end
  456. end
  457. end
  458. def addextend2soap(node, obj)
  459. return if obj.is_a?(Symbol) or obj.is_a?(Fixnum)
  460. list = (class << obj; self; end).ancestors - obj.class.ancestors
  461. unless list.empty?
  462. node.extraattr[RubyExtendName] = list.collect { |c|
  463. if c.name.empty?
  464. raise TypeError.new("singleton can't be dumped #{ obj }")
  465. end
  466. c.name
  467. }.join(" ")
  468. end
  469. end
  470. end
  471. DefaultRegistry = Registry.new
  472. RubyOriginalRegistry = Registry.new(:allow_original_mapping => true)
  473. end
  474. end