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

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

Video extension to Greenstone

File size: 10.9 KB
Line 
1# SOAP4R - Ruby type mapping utility.
2# Copyright (C) 2000, 2001, 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
9require 'xsd/codegen/gensupport'
10
11
12module SOAP
13
14
15module Mapping
16 RubyTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/1.6'
17 RubyTypeInstanceNamespace =
18 'http://www.ruby-lang.org/xmlns/ruby/type-instance'
19 RubyCustomTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/custom'
20 ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap'
21
22
23 # TraverseSupport breaks following thread variables.
24 # Thread.current[:SOAPMarshalDataKey]
25 module TraverseSupport
26 def mark_marshalled_obj(obj, soap_obj)
27 raise if obj.nil?
28 Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
29 end
30
31 def mark_unmarshalled_obj(node, obj)
32 return if obj.nil?
33 # node.id is not Object#id but SOAPReference#id
34 Thread.current[:SOAPMarshalDataKey][node.id] = obj
35 end
36 end
37
38
39 EMPTY_OPT = {}
40 def self.obj2soap(obj, registry = nil, type = nil, opt = EMPTY_OPT)
41 registry ||= Mapping::DefaultRegistry
42 soap_obj = nil
43 protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do
44 Thread.current[:SOAPMarshalDataKey] = {}
45 Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE
46 Thread.current[:SOAPMarshalNoReference] = opt[:no_reference]
47 soap_obj = _obj2soap(obj, registry, type)
48 end
49 soap_obj
50 end
51
52 def self.soap2obj(node, registry = nil, klass = nil, opt = EMPTY_OPT)
53 registry ||= Mapping::DefaultRegistry
54 obj = nil
55 protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do
56 Thread.current[:SOAPMarshalDataKey] = {}
57 Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE
58 Thread.current[:SOAPMarshalNoReference] = opt[:no_reference]
59 obj = _soap2obj(node, registry, klass)
60 end
61 obj
62 end
63
64 def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT)
65 registry ||= Mapping::DefaultRegistry
66 type = XSD::QName.new(type_ns, typename)
67 soap_ary = SOAPArray.new(ValueArrayName, 1, type)
68 protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do
69 Thread.current[:SOAPMarshalDataKey] = {}
70 Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE
71 Thread.current[:SOAPMarshalNoReference] = opt[:no_reference]
72 ary.each do |ele|
73 soap_ary.add(_obj2soap(ele, registry, type))
74 end
75 end
76 soap_ary
77 end
78
79 def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT)
80 registry ||= Mapping::DefaultRegistry
81 type = XSD::QName.new(type_ns, typename)
82 md_ary = SOAPArray.new(ValueArrayName, rank, type)
83 protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do
84 Thread.current[:SOAPMarshalDataKey] = {}
85 Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE
86 Thread.current[:SOAPMarshalNoReference] = opt[:no_reference]
87 add_md_ary(md_ary, ary, [], registry)
88 end
89 md_ary
90 end
91
92 def self.fault2exception(fault, registry = nil)
93 registry ||= Mapping::DefaultRegistry
94 detail = if fault.detail
95 soap2obj(fault.detail, registry) || ""
96 else
97 ""
98 end
99 if detail.is_a?(Mapping::SOAPException)
100 begin
101 e = detail.to_e
102 remote_backtrace = e.backtrace
103 e.set_backtrace(nil)
104 raise e # ruby sets current caller as local backtrace of e => e2.
105 rescue Exception => e
106 e.set_backtrace(remote_backtrace + e.backtrace[1..-1])
107 raise
108 end
109 else
110 fault.detail = detail
111 fault.set_backtrace(
112 if detail.is_a?(Array)
113 detail
114 else
115 [detail.to_s]
116 end
117 )
118 raise
119 end
120 end
121
122 def self._obj2soap(obj, registry, type = nil)
123 if referent = Thread.current[:SOAPMarshalDataKey][obj.__id__] and
124 !Thread.current[:SOAPMarshalNoReference]
125 SOAPReference.new(referent)
126 elsif registry
127 registry.obj2soap(obj, type)
128 else
129 raise MappingError.new("no mapping registry given")
130 end
131 end
132
133 def self._soap2obj(node, registry, klass = nil)
134 if node.nil?
135 return nil
136 elsif node.is_a?(SOAPReference)
137 target = node.__getobj__
138 # target.id is not Object#id but SOAPReference#id
139 if referent = Thread.current[:SOAPMarshalDataKey][target.id] and
140 !Thread.current[:SOAPMarshalNoReference]
141 return referent
142 else
143 return _soap2obj(target, registry, klass)
144 end
145 end
146 return registry.soap2obj(node, klass)
147 end
148
149 if Object.respond_to?(:allocate)
150 # ruby/1.7 or later.
151 def self.create_empty_object(klass)
152 klass.allocate
153 end
154 else
155 MARSHAL_TAG = {
156 String => ['"', 1],
157 Regexp => ['/', 2],
158 Array => ['[', 1],
159 Hash => ['{', 1]
160 }
161 def self.create_empty_object(klass)
162 if klass <= Struct
163 name = klass.name
164 return ::Marshal.load(sprintf("\004\006S:%c%s\000", name.length + 5, name))
165 end
166 if MARSHAL_TAG.has_key?(klass)
167 tag, terminate = MARSHAL_TAG[klass]
168 return ::Marshal.load(sprintf("\004\006%s%s", tag, "\000" * terminate))
169 end
170 MARSHAL_TAG.each do |k, v|
171 if klass < k
172 name = klass.name
173 tag, terminate = v
174 return ::Marshal.load(sprintf("\004\006C:%c%s%s%s", name.length + 5, name, tag, "\000" * terminate))
175 end
176 end
177 name = klass.name
178 ::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name))
179 end
180 end
181
182 # Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here.
183 # Caution: '.' is not allowed here.
184 # To follow XML spec., it should be NCName.
185 # (denied chars) => .[0-F][0-F]
186 # ex. a.b => a.2eb
187 #
188 def self.name2elename(name)
189 name.gsub(/([^a-zA-Z0-9:_\-]+)/n) {
190 '.' << $1.unpack('H2' * $1.size).join('.')
191 }.gsub(/::/n, '..')
192 end
193
194 def self.elename2name(name)
195 name.gsub(/\.\./n, '::').gsub(/((?:\.[0-9a-fA-F]{2})+)/n) {
196 [$1.delete('.')].pack('H*')
197 }
198 end
199
200 def self.const_from_name(name, lenient = false)
201 const = ::Object
202 name.sub(/\A::/, '').split('::').each do |const_str|
203 if XSD::CodeGen::GenSupport.safeconstname?(const_str)
204 if const.const_defined?(const_str)
205 const = const.const_get(const_str)
206 next
207 end
208 elsif lenient
209 const_str = XSD::CodeGen::GenSupport.safeconstname(const_str)
210 if const.const_defined?(const_str)
211 const = const.const_get(const_str)
212 next
213 end
214 end
215 return nil
216 end
217 const
218 end
219
220 def self.class_from_name(name, lenient = false)
221 const = const_from_name(name, lenient)
222 if const.is_a?(::Class)
223 const
224 else
225 nil
226 end
227 end
228
229 def self.module_from_name(name, lenient = false)
230 const = const_from_name(name, lenient)
231 if const.is_a?(::Module)
232 const
233 else
234 nil
235 end
236 end
237
238 def self.class2qname(klass)
239 name = schema_type_definition(klass)
240 namespace = schema_ns_definition(klass)
241 XSD::QName.new(namespace, name)
242 end
243
244 def self.class2element(klass)
245 type = Mapping.class2qname(klass)
246 type.name ||= Mapping.name2elename(klass.name)
247 type.namespace ||= RubyCustomTypeNamespace
248 type
249 end
250
251 def self.obj2element(obj)
252 name = namespace = nil
253 ivars = obj.instance_variables
254 if ivars.include?('@schema_type')
255 name = obj.instance_variable_get('@schema_type')
256 end
257 if ivars.include?('@schema_ns')
258 namespace = obj.instance_variable_get('@schema_ns')
259 end
260 if !name or !namespace
261 class2qname(obj.class)
262 else
263 XSD::QName.new(namespace, name)
264 end
265 end
266
267 def self.define_singleton_method(obj, name, &block)
268 sclass = (class << obj; self; end)
269 sclass.class_eval {
270 define_method(name, &block)
271 }
272 end
273
274 def self.get_attribute(obj, attr_name)
275 if obj.is_a?(::Hash)
276 obj[attr_name] || obj[attr_name.intern]
277 else
278 name = XSD::CodeGen::GenSupport.safevarname(attr_name)
279 if obj.instance_variables.include?('@' + name)
280 obj.instance_variable_get('@' + name)
281 elsif ((obj.is_a?(::Struct) or obj.is_a?(Marshallable)) and
282 obj.respond_to?(name))
283 obj.__send__(name)
284 end
285 end
286 end
287
288 def self.set_attributes(obj, values)
289 if obj.is_a?(::SOAP::Mapping::Object)
290 values.each do |attr_name, value|
291 obj.__add_xmlele_value(attr_name, value)
292 end
293 else
294 values.each do |attr_name, value|
295 name = XSD::CodeGen::GenSupport.safevarname(attr_name)
296 setter = name + "="
297 if obj.respond_to?(setter)
298 obj.__send__(setter, value)
299 else
300 obj.instance_variable_set('@' + name, value)
301 begin
302 define_attr_accessor(obj, name,
303 proc { instance_variable_get('@' + name) },
304 proc { |value| instance_variable_set('@' + name, value) })
305 rescue TypeError
306 # singleton class may not exist (e.g. Float)
307 end
308 end
309 end
310 end
311 end
312
313 def self.define_attr_accessor(obj, name, getterproc, setterproc = nil)
314 define_singleton_method(obj, name, &getterproc)
315 define_singleton_method(obj, name + '=', &setterproc) if setterproc
316 end
317
318 def self.schema_type_definition(klass)
319 class_schema_variable(:schema_type, klass)
320 end
321
322 def self.schema_ns_definition(klass)
323 class_schema_variable(:schema_ns, klass)
324 end
325
326 def self.schema_element_definition(klass)
327 schema_element = class_schema_variable(:schema_element, klass) or return nil
328 schema_ns = schema_ns_definition(klass)
329 elements = []
330 as_array = []
331 schema_element.each do |varname, definition|
332 class_name, name = definition
333 if /\[\]$/ =~ class_name
334 class_name = class_name.sub(/\[\]$/, '')
335 as_array << (name ? name.name : varname)
336 end
337 elements << [name || XSD::QName.new(schema_ns, varname), class_name]
338 end
339 [elements, as_array]
340 end
341
342 def self.schema_attribute_definition(klass)
343 class_schema_variable(:schema_attribute, klass)
344 end
345
346 class << Mapping
347 private
348
349 def class_schema_variable(sym, klass)
350 var = "@@#{sym}"
351 klass.class_variables.include?(var) ? klass.class_eval(var) : nil
352 end
353
354 def protect_threadvars(*symbols)
355 backup = {}
356 begin
357 symbols.each do |sym|
358 backup[sym] = Thread.current[sym]
359 end
360 yield
361 ensure
362 symbols.each do |sym|
363 Thread.current[sym] = backup[sym]
364 end
365 end
366 end
367
368 def add_md_ary(md_ary, ary, indices, registry)
369 for idx in 0..(ary.size - 1)
370 if ary[idx].is_a?(Array)
371 add_md_ary(md_ary, ary[idx], indices + [idx], registry)
372 else
373 md_ary[*(indices + [idx])] = _obj2soap(ary[idx], registry)
374 end
375 end
376 end
377 end
378end
379
380
381end
Note: See TracBrowser for help on using the repository browser.