| 1 |
# SOAP4R - Ruby type mapping utility. |
|---|
| 2 |
# Copyright (C) 2000-2007 NAKAMURA Hiroshi <nahi@ruby-lang.org>. |
|---|
| 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 |
|
|---|
| 9 |
require 'xsd/codegen/gensupport' |
|---|
| 10 |
require 'soap/mapping/schemadefinition' |
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
module SOAP |
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
module Mapping |
|---|
| 17 |
RubyTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/1.6' |
|---|
| 18 |
RubyTypeInstanceNamespace = |
|---|
| 19 |
'http://www.ruby-lang.org/xmlns/ruby/type-instance' |
|---|
| 20 |
RubyCustomTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/custom' |
|---|
| 21 |
ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap' |
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
module TraverseSupport |
|---|
| 25 |
def mark_marshalled_obj(obj, soap_obj) |
|---|
| 26 |
raise if obj.nil? |
|---|
| 27 |
Thread.current[:SOAPMapping][:MarshalKey][obj.__id__] = soap_obj |
|---|
| 28 |
end |
|---|
| 29 |
|
|---|
| 30 |
def mark_unmarshalled_obj(node, obj) |
|---|
| 31 |
return if obj.nil? |
|---|
| 32 |
# node.id is not Object#id but SOAPReference#id |
|---|
| 33 |
Thread.current[:SOAPMapping][:MarshalKey][node.id] = obj |
|---|
| 34 |
end |
|---|
| 35 |
end |
|---|
| 36 |
|
|---|
| 37 |
|
|---|
| 38 |
EMPTY_OPT = {}.freeze |
|---|
| 39 |
def self.obj2soap(obj, registry = nil, type = nil, opt = EMPTY_OPT) |
|---|
| 40 |
registry ||= Mapping::DefaultRegistry |
|---|
| 41 |
soap_obj = nil |
|---|
| 42 |
protect_mapping(opt) do |
|---|
| 43 |
soap_obj = _obj2soap(obj, registry, type) |
|---|
| 44 |
end |
|---|
| 45 |
soap_obj |
|---|
| 46 |
end |
|---|
| 47 |
|
|---|
| 48 |
def self.objs2soap(objs, registry = nil, types = nil, opt = EMPTY_OPT) |
|---|
| 49 |
registry ||= Mapping::DefaultRegistry |
|---|
| 50 |
ary = [] |
|---|
| 51 |
protect_mapping(opt) do |
|---|
| 52 |
0.upto(objs.length - 1) do |idx| |
|---|
| 53 |
type = types ? types[idx] : nil |
|---|
| 54 |
soap = _obj2soap(objs[idx], registry, type) |
|---|
| 55 |
ary << soap |
|---|
| 56 |
end |
|---|
| 57 |
end |
|---|
| 58 |
ary |
|---|
| 59 |
end |
|---|
| 60 |
|
|---|
| 61 |
def self.soap2obj(node, registry = nil, klass = nil, opt = EMPTY_OPT) |
|---|
| 62 |
registry ||= Mapping::DefaultRegistry |
|---|
| 63 |
obj = nil |
|---|
| 64 |
protect_mapping(opt) do |
|---|
| 65 |
obj = _soap2obj(node, registry, klass) |
|---|
| 66 |
end |
|---|
| 67 |
obj |
|---|
| 68 |
end |
|---|
| 69 |
|
|---|
| 70 |
def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT) |
|---|
| 71 |
registry ||= Mapping::DefaultRegistry |
|---|
| 72 |
type = XSD::QName.new(type_ns, typename) |
|---|
| 73 |
soap_ary = SOAPArray.new(ValueArrayName, 1, type) |
|---|
| 74 |
protect_mapping(opt) do |
|---|
| 75 |
ary.each do |ele| |
|---|
| 76 |
soap_ary.add(_obj2soap(ele, registry, type)) |
|---|
| 77 |
end |
|---|
| 78 |
end |
|---|
| 79 |
soap_ary |
|---|
| 80 |
end |
|---|
| 81 |
|
|---|
| 82 |
def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT) |
|---|
| 83 |
registry ||= Mapping::DefaultRegistry |
|---|
| 84 |
type = XSD::QName.new(type_ns, typename) |
|---|
| 85 |
md_ary = SOAPArray.new(ValueArrayName, rank, type) |
|---|
| 86 |
protect_mapping(opt) do |
|---|
| 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 = "" |
|---|
| 95 |
if fault.detail |
|---|
| 96 |
begin |
|---|
| 97 |
fault.detail.type ||= XSD::QName::EMPTY |
|---|
| 98 |
detail = soap2obj(fault.detail, registry) || "" |
|---|
| 99 |
rescue MappingError |
|---|
| 100 |
detail = fault.detail |
|---|
| 101 |
end |
|---|
| 102 |
end |
|---|
| 103 |
if detail.is_a?(Mapping::SOAPException) |
|---|
| 104 |
begin |
|---|
| 105 |
e = detail.to_e |
|---|
| 106 |
remote_backtrace = e.backtrace |
|---|
| 107 |
e.set_backtrace(nil) |
|---|
| 108 |
raise e # ruby sets current caller as local backtrace of e => e2. |
|---|
| 109 |
rescue Exception => e |
|---|
| 110 |
e.set_backtrace(remote_backtrace + e.backtrace[1..-1]) |
|---|
| 111 |
raise |
|---|
| 112 |
end |
|---|
| 113 |
else |
|---|
| 114 |
fault.detail = detail |
|---|
| 115 |
fault.set_backtrace( |
|---|
| 116 |
if detail.is_a?(Array) |
|---|
| 117 |
detail |
|---|
| 118 |
else |
|---|
| 119 |
[detail.to_s] |
|---|
| 120 |
end |
|---|
| 121 |
) |
|---|
| 122 |
raise |
|---|
| 123 |
end |
|---|
| 124 |
end |
|---|
| 125 |
|
|---|
| 126 |
def self._obj2soap(obj, registry, type = nil) |
|---|
| 127 |
if obj.respond_to?(:to_xmlpart) |
|---|
| 128 |
SOAPRawData.new(obj) |
|---|
| 129 |
elsif defined?(::REXML) and obj.is_a?(::REXML::Element) |
|---|
| 130 |
SOAPRawData.new(SOAPREXMLElementWrap.new(obj)) |
|---|
| 131 |
elsif referent = Thread.current[:SOAPMapping][:MarshalKey][obj.__id__] and |
|---|
| 132 |
!Thread.current[:SOAPMapping][:NoReference] |
|---|
| 133 |
SOAPReference.new(referent) |
|---|
| 134 |
elsif registry |
|---|
| 135 |
registry.obj2soap(obj, type) |
|---|
| 136 |
else |
|---|
| 137 |
raise MappingError.new("no mapping registry given") |
|---|
| 138 |
end |
|---|
| 139 |
end |
|---|
| 140 |
|
|---|
| 141 |
def self._soap2obj(node, registry, klass = nil) |
|---|
| 142 |
if node.nil? |
|---|
| 143 |
return nil |
|---|
| 144 |
elsif node.is_a?(SOAPReference) |
|---|
| 145 |
target = node.__getobj__ |
|---|
| 146 |
# target.id is not Object#id but SOAPReference#id |
|---|
| 147 |
if referent = Thread.current[:SOAPMapping][:MarshalKey][target.id] and |
|---|
| 148 |
!Thread.current[:SOAPMapping][:NoReference] |
|---|
| 149 |
return referent |
|---|
| 150 |
else |
|---|
| 151 |
return _soap2obj(target, registry, klass) |
|---|
| 152 |
end |
|---|
| 153 |
end |
|---|
| 154 |
return registry.soap2obj(node, klass) |
|---|
| 155 |
end |
|---|
| 156 |
|
|---|
| 157 |
if Object.respond_to?(:allocate) |
|---|
| 158 |
# ruby/1.7 or later. |
|---|
| 159 |
def self.create_empty_object(klass) |
|---|
| 160 |
klass.allocate |
|---|
| 161 |
end |
|---|
| 162 |
else |
|---|
| 163 |
MARSHAL_TAG = { |
|---|
| 164 |
String => ['"', 1], |
|---|
| 165 |
Regexp => ['/', 2], |
|---|
| 166 |
Array => ['[', 1], |
|---|
| 167 |
Hash => ['{', 1] |
|---|
| 168 |
} |
|---|
| 169 |
def self.create_empty_object(klass) |
|---|
| 170 |
if klass <= Struct |
|---|
| 171 |
name = klass.name |
|---|
| 172 |
return ::Marshal.load(sprintf("\004\006S:%c%s\000", name.length + 5, name)) |
|---|
| 173 |
end |
|---|
| 174 |
if MARSHAL_TAG.has_key?(klass) |
|---|
| 175 |
tag, terminate = MARSHAL_TAG[klass] |
|---|
| 176 |
return ::Marshal.load(sprintf("\004\006%s%s", tag, "\000" * terminate)) |
|---|
| 177 |
end |
|---|
| 178 |
MARSHAL_TAG.each do |k, v| |
|---|
| 179 |
if klass < k |
|---|
| 180 |
name = klass.name |
|---|
| 181 |
tag, terminate = v |
|---|
| 182 |
return ::Marshal.load(sprintf("\004\006C:%c%s%s%s", name.length + 5, name, tag, "\000" * terminate)) |
|---|
| 183 |
end |
|---|
| 184 |
end |
|---|
| 185 |
name = klass.name |
|---|
| 186 |
::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name)) |
|---|
| 187 |
end |
|---|
| 188 |
end |
|---|
| 189 |
|
|---|
| 190 |
# Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here. |
|---|
| 191 |
# Caution: '.' is not allowed here. |
|---|
| 192 |
# To follow XML spec., it should be NCName. |
|---|
| 193 |
# (denied chars) => .[0-F][0-F] |
|---|
| 194 |
# ex. a.b => a.2eb |
|---|
| 195 |
# |
|---|
| 196 |
def self.name2elename(name) |
|---|
| 197 |
name.gsub(/([^a-zA-Z0-9:_\-]+)/n) { |
|---|
| 198 |
'.' << $1.unpack('H2' * $1.size).join('.') |
|---|
| 199 |
}.gsub(/::/n, '..') |
|---|
| 200 |
end |
|---|
| 201 |
|
|---|
| 202 |
def self.elename2name(name) |
|---|
| 203 |
name.gsub(/\.\./n, '::').gsub(/((?:\.[0-9a-fA-F]{2})+)/n) { |
|---|
| 204 |
[$1.delete('.')].pack('H*') |
|---|
| 205 |
} |
|---|
| 206 |
end |
|---|
| 207 |
|
|---|
| 208 |
def self.const_from_name(name, lenient = false) |
|---|
| 209 |
const = ::Object |
|---|
| 210 |
name.sub(/\A::/, '').split('::').each do |const_str| |
|---|
| 211 |
if /\A[A-Z]/ =~ const_str |
|---|
| 212 |
begin |
|---|
| 213 |
if const.const_defined?(const_str) |
|---|
| 214 |
const = const.const_get(const_str) |
|---|
| 215 |
next |
|---|
| 216 |
end |
|---|
| 217 |
rescue NameError |
|---|
| 218 |
end |
|---|
| 219 |
end |
|---|
| 220 |
if lenient |
|---|
| 221 |
const_str = Mapping.safeconstname(const_str) |
|---|
| 222 |
if const.const_defined?(const_str) |
|---|
| 223 |
const = const.const_get(const_str) |
|---|
| 224 |
next |
|---|
| 225 |
end |
|---|
| 226 |
end |
|---|
| 227 |
return nil |
|---|
| 228 |
end |
|---|
| 229 |
const |
|---|
| 230 |
end |
|---|
| 231 |
|
|---|
| 232 |
def self.class_from_name(name, lenient = false) |
|---|
| 233 |
unless lenient |
|---|
| 234 |
const = const_from_name_nonlenient(name) |
|---|
| 235 |
else |
|---|
| 236 |
const = const_from_name(name, true) |
|---|
| 237 |
end |
|---|
| 238 |
if const.is_a?(::Class) |
|---|
| 239 |
const |
|---|
| 240 |
else |
|---|
| 241 |
nil |
|---|
| 242 |
end |
|---|
| 243 |
end |
|---|
| 244 |
|
|---|
| 245 |
def self.module_from_name(name, lenient = false) |
|---|
| 246 |
unless lenient |
|---|
| 247 |
const = const_from_name_nonlenient(name) |
|---|
| 248 |
else |
|---|
| 249 |
const = const_from_name(name, true) |
|---|
| 250 |
end |
|---|
| 251 |
if const.is_a?(::Module) |
|---|
| 252 |
const |
|---|
| 253 |
else |
|---|
| 254 |
nil |
|---|
| 255 |
end |
|---|
| 256 |
end |
|---|
| 257 |
|
|---|
| 258 |
def self.const_from_name_nonlenient(name) |
|---|
| 259 |
if Thread.current[:SOAPMapping] |
|---|
| 260 |
Thread.current[:SOAPMapping][:ConstFromName][name] ||= |
|---|
| 261 |
const_from_name(name) |
|---|
| 262 |
else |
|---|
| 263 |
const_from_name(name) |
|---|
| 264 |
end |
|---|
| 265 |
end |
|---|
| 266 |
|
|---|
| 267 |
def self.class2qname(klass) |
|---|
| 268 |
name = schema_type_definition(klass) |
|---|
| 269 |
namespace = schema_ns_definition(klass) |
|---|
| 270 |
XSD::QName.new(namespace, name) |
|---|
| 271 |
end |
|---|
| 272 |
|
|---|
| 273 |
def self.class2element(klass) |
|---|
| 274 |
name = schema_type_definition(klass) || |
|---|
| 275 |
Mapping.name2elename(klass.name) |
|---|
| 276 |
namespace = schema_ns_definition(klass) || RubyCustomTypeNamespace |
|---|
| 277 |
XSD::QName.new(namespace, name) |
|---|
| 278 |
end |
|---|
| 279 |
|
|---|
| 280 |
def self.obj2element(obj) |
|---|
| 281 |
name = namespace = nil |
|---|
| 282 |
ivars = obj.instance_variables |
|---|
| 283 |
if ivars.include?('@schema_type') |
|---|
| 284 |
name = obj.instance_variable_get('@schema_type') |
|---|
| 285 |
end |
|---|
| 286 |
if ivars.include?('@schema_ns') |
|---|
| 287 |
namespace = obj.instance_variable_get('@schema_ns') |
|---|
| 288 |
end |
|---|
| 289 |
if !name or !namespace |
|---|
| 290 |
class2qname(obj.class) |
|---|
| 291 |
else |
|---|
| 292 |
XSD::QName.new(namespace, name) |
|---|
| 293 |
end |
|---|
| 294 |
end |
|---|
| 295 |
|
|---|
| 296 |
def self.to_qname(obj, ns = nil) |
|---|
| 297 |
if obj.is_a?(XSD::QName) |
|---|
| 298 |
obj |
|---|
| 299 |
else |
|---|
| 300 |
XSD::QName.new(ns, obj) |
|---|
| 301 |
end |
|---|
| 302 |
end |
|---|
| 303 |
|
|---|
| 304 |
def self.define_singleton_method(obj, name, &block) |
|---|
| 305 |
sclass = (class << obj; self; end) |
|---|
| 306 |
sclass.class_eval { |
|---|
| 307 |
define_method(name, &block) |
|---|
| 308 |
} |
|---|
| 309 |
end |
|---|
| 310 |
|
|---|
| 311 |
def self.get_attributes(obj) |
|---|
| 312 |
if obj.is_a?(::Hash) |
|---|
| 313 |
obj |
|---|
| 314 |
else |
|---|
| 315 |
rs = {} |
|---|
| 316 |
obj.instance_variables.each do |ele| |
|---|
| 317 |
rs[ele.sub(/^@/, '')] = obj.instance_variable_get(ele) |
|---|
| 318 |
end |
|---|
| 319 |
rs |
|---|
| 320 |
end |
|---|
| 321 |
end |
|---|
| 322 |
|
|---|
| 323 |
EMPTY_ATTRIBUTES = {}.freeze |
|---|
| 324 |
def self.get_attributes_for_any(obj) |
|---|
| 325 |
if obj.respond_to?(:__xmlele_any) |
|---|
| 326 |
obj.__xmlele_any || EMPTY_ATTRIBUTES |
|---|
| 327 |
else |
|---|
| 328 |
get_attributes(obj) |
|---|
| 329 |
end |
|---|
| 330 |
end |
|---|
| 331 |
|
|---|
| 332 |
def self.get_attribute(obj, attr_name) |
|---|
| 333 |
case obj |
|---|
| 334 |
when ::SOAP::Mapping::Object |
|---|
| 335 |
return obj[attr_name] |
|---|
| 336 |
when ::Hash |
|---|
| 337 |
return obj[attr_name] || obj[attr_name.intern] |
|---|
| 338 |
else |
|---|
| 339 |
if obj.respond_to?(attr_name) |
|---|
| 340 |
return obj.__send__(attr_name) |
|---|
| 341 |
end |
|---|
| 342 |
iv = obj.instance_variables |
|---|
| 343 |
name = Mapping.safevarname(attr_name) |
|---|
| 344 |
if iv.include?("@#{name}") |
|---|
| 345 |
return obj.instance_variable_get("@#{name}") |
|---|
| 346 |
elsif iv.include?("@#{attr_name}") |
|---|
| 347 |
return obj.instance_variable_get("@#{attr_name}") |
|---|
| 348 |
end |
|---|
| 349 |
if obj.respond_to?(name) |
|---|
| 350 |
return obj.__send__(name) |
|---|
| 351 |
end |
|---|
| 352 |
nil |
|---|
| 353 |
end |
|---|
| 354 |
end |
|---|
| 355 |
|
|---|
| 356 |
def self.set_attributes(obj, values) |
|---|
| 357 |
case obj |
|---|
| 358 |
when ::SOAP::Mapping::Object |
|---|
| 359 |
values.each do |attr_name, value| |
|---|
| 360 |
obj.__add_xmlele_value(attr_name, value) |
|---|
| 361 |
end |
|---|
| 362 |
else |
|---|
| 363 |
values.each do |attr_name, value| |
|---|
| 364 |
# untaint depends GenSupport.safevarname |
|---|
| 365 |
name = Mapping.safevarname(attr_name).untaint |
|---|
| 366 |
setter = name + "=" |
|---|
| 367 |
if obj.respond_to?(setter) |
|---|
| 368 |
obj.__send__(setter, value) |
|---|
| 369 |
else |
|---|
| 370 |
obj.instance_variable_set('@' + name, value) |
|---|
| 371 |
begin |
|---|
| 372 |
unless obj.respond_to?(name) |
|---|
| 373 |
obj.instance_eval <<-EOS |
|---|
| 374 |
def #{name} |
|---|
| 375 |
@#{name} |
|---|
| 376 |
end |
|---|
| 377 |
EOS |
|---|
| 378 |
end |
|---|
| 379 |
unless self.respond_to?(name + "=") |
|---|
| 380 |
obj.instance_eval <<-EOS |
|---|
| 381 |
def #{name}=(value) |
|---|
| 382 |
@#{name} = value |
|---|
| 383 |
end |
|---|
| 384 |
EOS |
|---|
| 385 |
end |
|---|
| 386 |
rescue TypeError |
|---|
| 387 |
# singleton class may not exist (e.g. Float) |
|---|
| 388 |
end |
|---|
| 389 |
end |
|---|
| 390 |
end |
|---|
| 391 |
end |
|---|
| 392 |
end |
|---|
| 393 |
|
|---|
| 394 |
def self.safeconstname(name) |
|---|
| 395 |
Thread.current[:SOAPMapping][:SafeConstName][name] ||= |
|---|
| 396 |
XSD::CodeGen::GenSupport.safeconstname(name) |
|---|
| 397 |
end |
|---|
| 398 |
|
|---|
| 399 |
def self.safemethodname(name) |
|---|
| 400 |
Thread.current[:SOAPMapping][:SafeMethodName][name] ||= |
|---|
| 401 |
XSD::CodeGen::GenSupport.safemethodname(name) |
|---|
| 402 |
end |
|---|
| 403 |
|
|---|
| 404 |
def self.safevarname(name) |
|---|
| 405 |
Thread.current[:SOAPMapping][:SafeVarName][name] ||= |
|---|
| 406 |
XSD::CodeGen::GenSupport.safevarname(name) |
|---|
| 407 |
end |
|---|
| 408 |
|
|---|
| 409 |
def self.root_type_hint |
|---|
| 410 |
Thread.current[:SOAPMapping][:RootTypeHint] |
|---|
| 411 |
end |
|---|
| 412 |
|
|---|
| 413 |
def self.reset_root_type_hint |
|---|
| 414 |
Thread.current[:SOAPMapping][:RootTypeHint] = false |
|---|
| 415 |
end |
|---|
| 416 |
|
|---|
| 417 |
def self.external_ces |
|---|
| 418 |
Thread.current[:SOAPMapping][:ExternalCES] |
|---|
| 419 |
end |
|---|
| 420 |
|
|---|
| 421 |
def self.schema_ns_definition(klass) |
|---|
| 422 |
class_schema_variable(:schema_ns, klass) |
|---|
| 423 |
end |
|---|
| 424 |
|
|---|
| 425 |
def self.schema_name_definition(klass) |
|---|
| 426 |
class_schema_variable(:schema_name, klass) |
|---|
| 427 |
end |
|---|
| 428 |
|
|---|
| 429 |
def self.schema_type_definition(klass) |
|---|
| 430 |
class_schema_variable(:schema_type, klass) |
|---|
| 431 |
end |
|---|
| 432 |
|
|---|
| 433 |
def self.schema_qualified_definition(klass) |
|---|
| 434 |
class_schema_variable(:schema_qualified, klass) |
|---|
| 435 |
end |
|---|
| 436 |
|
|---|
| 437 |
def self.schema_element_definition(klass) |
|---|
| 438 |
class_schema_variable(:schema_element, klass) |
|---|
| 439 |
end |
|---|
| 440 |
|
|---|
| 441 |
def self.schema_attribute_definition(klass) |
|---|
| 442 |
class_schema_variable(:schema_attribute, klass) |
|---|
| 443 |
end |
|---|
| 444 |
|
|---|
| 445 |
def self.schema_definition_classdef(klass) |
|---|
| 446 |
if Thread.current[:SOAPMapping][:SchemaDefinition].key?(klass) |
|---|
| 447 |
return Thread.current[:SOAPMapping][:SchemaDefinition][klass] |
|---|
| 448 |
end |
|---|
| 449 |
schema_ns = schema_ns_definition(klass) |
|---|
| 450 |
schema_name = schema_name_definition(klass) |
|---|
| 451 |
schema_type = schema_type_definition(klass) |
|---|
| 452 |
qualified = schema_qualified_definition(klass) |
|---|
| 453 |
elements = schema_element_definition(klass) |
|---|
| 454 |
attributes = schema_attribute_definition(klass) |
|---|
| 455 |
return nil if schema_name.nil? and schema_type.nil? |
|---|
| 456 |
schema_name = Mapping.to_qname(schema_name, schema_ns) if schema_name |
|---|
| 457 |
schema_type = Mapping.to_qname(schema_type, schema_ns) if schema_type |
|---|
| 458 |
definition = create_schema_definition(klass, |
|---|
| 459 |
:schema_name => schema_name, |
|---|
| 460 |
:schema_type => schema_type, |
|---|
| 461 |
:is_anonymous => false, |
|---|
| 462 |
:schema_qualified => qualified, |
|---|
| 463 |
:schema_element => elements, |
|---|
| 464 |
:schema_attribute => attributes |
|---|
| 465 |
) |
|---|
| 466 |
Thread.current[:SOAPMapping][:SchemaDefinition][klass] = definition |
|---|
| 467 |
definition |
|---|
| 468 |
end |
|---|
| 469 |
|
|---|
| 470 |
def self.create_schema_definition(klass, definition) |
|---|
| 471 |
schema_ns = definition[:schema_ns] |
|---|
| 472 |
schema_name = definition[:schema_name] |
|---|
| 473 |
schema_type = definition[:schema_type] |
|---|
| 474 |
is_anonymous = definition[:is_anonymous] |
|---|
| 475 |
schema_basetype = definition[:schema_basetype] |
|---|
| 476 |
# wrap if needed for backward compatibility |
|---|
| 477 |
if schema_ns |
|---|
| 478 |
schema_name = Mapping.to_qname(schema_name, schema_ns) if schema_name |
|---|
| 479 |
schema_type = Mapping.to_qname(schema_type, schema_ns) if schema_type |
|---|
| 480 |
# no need for schema_basetype bacause it's introduced later |
|---|
| 481 |
end |
|---|
| 482 |
schema_qualified = definition[:schema_qualified] |
|---|
| 483 |
schema_element = definition[:schema_element] |
|---|
| 484 |
schema_attributes = definition[:schema_attribute] |
|---|
| 485 |
definition = SchemaDefinition.new(klass, schema_name, schema_type, is_anonymous, schema_qualified) |
|---|
| 486 |
definition.basetype = schema_basetype |
|---|
| 487 |
definition.attributes = schema_attributes |
|---|
| 488 |
if schema_element |
|---|
| 489 |
if schema_element.respond_to?(:is_concrete_definition) and |
|---|
| 490 |
schema_element.is_concrete_definition |
|---|
| 491 |
definition.elements = schema_element |
|---|
| 492 |
else |
|---|
| 493 |
default_ns = schema_name.namespace if schema_name |
|---|
| 494 |
default_ns ||= schema_type.namespace if schema_type |
|---|
| 495 |
definition.elements = parse_schema_definition(schema_element, default_ns) |
|---|
| 496 |
if klass < ::Array |
|---|
| 497 |
definition.elements.set_array |
|---|
| 498 |
end |
|---|
| 499 |
end |
|---|
| 500 |
end |
|---|
| 501 |
definition |
|---|
| 502 |
end |
|---|
| 503 |
|
|---|
| 504 |
# for backward compatibility |
|---|
| 505 |
# returns SchemaComplexTypeDefinition |
|---|
| 506 |
def self.parse_schema_definition(schema_element, default_ns) |
|---|
| 507 |
definition = nil |
|---|
| 508 |
if schema_element[0] == :choice |
|---|
| 509 |
schema_element.shift |
|---|
| 510 |
definition = SchemaChoiceDefinition.new |
|---|
| 511 |
else |
|---|
| 512 |
definition = SchemaSequenceDefinition.new |
|---|
| 513 |
end |
|---|
| 514 |
schema_element.each do |ele| |
|---|
| 515 |
element_definition = parse_schema_element_definition(ele, default_ns) |
|---|
| 516 |
definition << element_definition |
|---|
| 517 |
end |
|---|
| 518 |
definition |
|---|
| 519 |
end |
|---|
| 520 |
|
|---|
| 521 |
# returns SchemaElementDefinition |
|---|
| 522 |
def self.parse_schema_element_definition(schema_element, default_ns) |
|---|
| 523 |
if schema_element[0] == :choice |
|---|
| 524 |
parse_schema_definition(schema_element, default_ns) |
|---|
| 525 |
elsif schema_element[0].is_a?(Array) |
|---|
| 526 |
parse_schema_definition(schema_element, default_ns) |
|---|
| 527 |
else |
|---|
| 528 |
varname, info, occurrence = schema_element |
|---|
| 529 |
mapped_class_str, elename = info |
|---|
| 530 |
if occurrence |
|---|
| 531 |
minoccurs, maxoccurs = occurrence |
|---|
| 532 |
else |
|---|
| 533 |
# for backward compatibility |
|---|
| 534 |
minoccurs, maxoccurs = 1, 1 |
|---|
| 535 |
end |
|---|
| 536 |
as_any = as_array = false |
|---|
| 537 |
if /\[\]$/ =~ mapped_class_str |
|---|
| 538 |
mapped_class_str = mapped_class_str.sub(/\[\]$/, '') |
|---|
| 539 |
if mapped_class_str.empty? |
|---|
| 540 |
mapped_class_str = nil |
|---|
| 541 |
end |
|---|
| 542 |
as_array = true |
|---|
| 543 |
end |
|---|
| 544 |
if mapped_class_str |
|---|
| 545 |
mapped_class = Mapping.class_from_name(mapped_class_str) |
|---|
| 546 |
if mapped_class.nil? |
|---|
| 547 |
warn("cannot find mapped class: #{mapped_class_str}") |
|---|
| 548 |
end |
|---|
| 549 |
end |
|---|
| 550 |
if elename == XSD::AnyTypeName |
|---|
| 551 |
as_any = true |
|---|
| 552 |
elsif elename.nil? |
|---|
| 553 |
elename = XSD::QName.new(default_ns, varname) |
|---|
| 554 |
end |
|---|
| 555 |
SchemaElementDefinition.new( |
|---|
| 556 |
varname, mapped_class, elename, minoccurs, maxoccurs, as_any, as_array) |
|---|
| 557 |
end |
|---|
| 558 |
end |
|---|
| 559 |
|
|---|
| 560 |
class << Mapping |
|---|
| 561 |
public |
|---|
| 562 |
|
|---|
| 563 |
def protect_threadvars(*symbols) |
|---|
| 564 |
backup = {} |
|---|
| 565 |
begin |
|---|
| 566 |
symbols.each do |sym| |
|---|
| 567 |
backup[sym] = Thread.current[sym] |
|---|
| 568 |
end |
|---|
| 569 |
yield |
|---|
| 570 |
ensure |
|---|
| 571 |
symbols.each do |sym| |
|---|
| 572 |
Thread.current[sym] = backup[sym] |
|---|
| 573 |
end |
|---|
| 574 |
end |
|---|
| 575 |
end |
|---|
| 576 |
|
|---|
| 577 |
private |
|---|
| 578 |
|
|---|
| 579 |
def class_schema_variable(sym, klass) |
|---|
| 580 |
var = "@@#{sym}" |
|---|
| 581 |
klass.class_variables.include?(var) ? klass.class_eval(var) : nil |
|---|
| 582 |
end |
|---|
| 583 |
|
|---|
| 584 |
def protect_mapping(opt) |
|---|
| 585 |
protect_threadvars(:SOAPMapping) do |
|---|
| 586 |
data = Thread.current[:SOAPMapping] = {} |
|---|
| 587 |
data[:MarshalKey] = {} |
|---|
| 588 |
data[:ExternalCES] = opt[:external_ces] || XSD::Charset.encoding |
|---|
| 589 |
data[:NoReference] = opt[:no_reference] |
|---|
| 590 |
data[:RootTypeHint] = opt[:root_type_hint] |
|---|
| 591 |
data[:SchemaDefinition] = {} |
|---|
| 592 |
data[:SafeConstName] = {} |
|---|
| 593 |
data[:SafeMethodName] = {} |
|---|
| 594 |
data[:SafeVarName] = {} |
|---|
| 595 |
data[:ConstFromName] = {} |
|---|
| 596 |
yield |
|---|
| 597 |
end |
|---|
| 598 |
end |
|---|
| 599 |
|
|---|
| 600 |
def add_md_ary(md_ary, ary, indices, registry) |
|---|
| 601 |
for idx in 0..(ary.size - 1) |
|---|
| 602 |
if ary[idx].is_a?(Array) |
|---|
| 603 |
add_md_ary(md_ary, ary[idx], indices + [idx], registry) |
|---|
| 604 |
else |
|---|
| 605 |
md_ary[*(indices + [idx])] = _obj2soap(ary[idx], registry) |
|---|
| 606 |
end |
|---|
| 607 |
end |
|---|
| 608 |
end |
|---|
| 609 |
end |
|---|
| 610 |
end |
|---|
| 611 |
|
|---|
| 612 |
|
|---|
| 613 |
end |
|---|