This repository has been archived by the owner on Jul 1, 2021. It is now read-only.
/
deserialization.rb
214 lines (191 loc) · 5.36 KB
/
deserialization.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# Copyright (c) 2011 VMware, Inc. All Rights Reserved.
require 'time'
module RbVmomi
class NewDeserializer
NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance'
DEMANGLED_ARRAY_TYPES = {
'AnyType' => 'xsd:anyType',
'DateTime' => 'xsd:dateTime',
}
%w(Boolean String Byte Short Int Long Float Double).each do |x|
DEMANGLED_ARRAY_TYPES[x] = "xsd:#{x.downcase}"
end
BUILTIN = Set.new %w(
xsd:string xsd:boolean xsd:byte xsd:short xsd:int xsd:long xsd:float xsd:dateTime xsd:base64Binary
KeyValue PropertyPath MethodName TypeName
)
def initialize conn
@conn = conn
@loader = conn.class.loader
end
def deserialize node, type=nil
type_attr = node['type']
type = type_attr if type_attr
if BUILTIN.member? type
case type
when 'xsd:string'
node.content
when 'xsd:boolean'
node.content == '1'
when 'xsd:int', 'xsd:long', 'xsd:short', 'xsd:byte'
node.content.to_i
when 'xsd:float'
node.content.to_f
when 'xsd:dateTime'
leaf_date node
when 'PropertyPath', 'MethodName', 'TypeName'
node.content
when 'xsd:base64Binary'
leaf_binary node
when 'KeyValue'
leaf_keyvalue node
else fail
end
else
if type =~ /^ArrayOf/
type = DEMANGLED_ARRAY_TYPES[$'] || $'
return node.children.select(&:element?).map { |c| deserialize c, type }
end
klass = @loader.get(type) or fail "no such type #{type}"
case klass.kind
when :data
traverse_data node, klass
when :enum
node.content
when :managed
leaf_managed node, klass
else fail
end
end
end
def traverse_data node, klass
obj = klass.new nil
props = obj.props
children = node.children.select(&:element?)
n = children.size
i = 0
klass.full_props_desc.each do |desc|
name = desc['name']
child_type = desc['wsdl_type']
if desc['is-array']
a = []
while ((child = children[i]) && (child.name == name))
child = children[i]
a << deserialize(child, child_type)
i += 1
end
props[name.to_sym] = a
elsif ((child = children[i]) && (child.name == name))
props[name.to_sym] = deserialize(child, child_type)
i += 1
end
end
obj
end
def leaf_managed node, klass
type_attr = node['type']
klass = @loader.get(type_attr) if type_attr
klass.new(@conn, node.content)
end
def leaf_date node
Time.parse node.content
end
def leaf_binary node
node.content.unpack('m')[0]
end
# XXX does the value need to be deserialized?
def leaf_keyvalue node
h = {}
node.children.each do |child|
next unless child.element?
h[child.name] = child.content
end
[h['key'], h['value']]
end
end
class OldDeserializer
NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance'
def initialize conn
@conn = conn
end
def deserialize xml, typename=nil
if IS_JRUBY
type_attr = xml.attribute_nodes.find { |a| a.name == 'type' &&
a.namespace &&
a.namespace.prefix == 'xsi' }
else
type_attr = xml.attribute_with_ns('type', NS_XSI)
end
typename = (type_attr || typename).to_s
if typename =~ /^ArrayOf/
typename = demangle_array_type $'
return xml.children.select(&:element?).map { |c| deserialize c, typename }
end
t = @conn.type typename
if t <= BasicTypes::DataObject
props_desc = t.full_props_desc
h = {}
props_desc.select { |d| d['is-array'] }.each { |d| h[d['name'].to_sym] = [] }
xml.children.each do |c|
next unless c.element?
field = c.name.to_sym
d = t.find_prop_desc(field.to_s) or next
o = deserialize c, d['wsdl_type']
if h[field].is_a? Array
h[field] << o
else
h[field] = o
end
end
t.new h
elsif t == BasicTypes::ManagedObjectReference
@conn.type(xml['type']).new @conn, xml.text
elsif t <= BasicTypes::ManagedObject
@conn.type(xml['type'] || t.wsdl_name).new @conn, xml.text
elsif t <= BasicTypes::Enum
xml.text
elsif t <= BasicTypes::KeyValue
h = {}
xml.children.each do |c|
next unless c.element?
h[c.name] = c.text
end
[h['key'], h['value']]
elsif t <= String
xml.text
elsif t <= Symbol
xml.text.to_sym
elsif t <= Integer
xml.text.to_i
elsif t <= Float
xml.text.to_f
elsif t <= Time
Time.parse xml.text
elsif t == BasicTypes::Boolean
xml.text == 'true' || xml.text == '1'
elsif t == BasicTypes::Binary
xml.text.unpack('m')[0]
elsif t == BasicTypes::AnyType
fail "attempted to deserialize an AnyType"
else fail "unexpected type #{t.inspect} (#{t.ancestors * '/'})"
end
rescue
$stderr.puts "#{$!.class} while deserializing #{xml.name} (#{typename}):"
$stderr.puts xml.to_s
raise
end
def demangle_array_type x
case x
when 'AnyType' then 'anyType'
when 'DateTime' then 'dateTime'
when 'Boolean', 'String', 'Byte', 'Short', 'Int', 'Long', 'Float', 'Double' then x.downcase
else x
end
end
end
if ENV['RBVMOMI_NEW_DESERIALIZER'] == '1'
Deserializer = NewDeserializer
else
Deserializer = OldDeserializer
end
end