ruby_vim_sdk 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. data/README +1 -0
  2. data/Rakefile +51 -0
  3. data/lib/ruby_vim_sdk.rb +48 -0
  4. data/lib/ruby_vim_sdk/base_type.rb +15 -0
  5. data/lib/ruby_vim_sdk/const.rb +32 -0
  6. data/lib/ruby_vim_sdk/core_types.rb +68 -0
  7. data/lib/ruby_vim_sdk/data_type.rb +14 -0
  8. data/lib/ruby_vim_sdk/enum_type.rb +12 -0
  9. data/lib/ruby_vim_sdk/ext.rb +9 -0
  10. data/lib/ruby_vim_sdk/managed_type.rb +12 -0
  11. data/lib/ruby_vim_sdk/method.rb +37 -0
  12. data/lib/ruby_vim_sdk/missing_types.rb +11 -0
  13. data/lib/ruby_vim_sdk/property.rb +49 -0
  14. data/lib/ruby_vim_sdk/server_objects.rb +2718 -0
  15. data/lib/ruby_vim_sdk/soap/deserializer.rb +301 -0
  16. data/lib/ruby_vim_sdk/soap/serializer.rb +225 -0
  17. data/lib/ruby_vim_sdk/soap/stub_adapter.rb +123 -0
  18. data/lib/ruby_vim_sdk/soap_exception.rb +12 -0
  19. data/lib/ruby_vim_sdk/typed_array.rb +9 -0
  20. data/lib/ruby_vim_sdk/types.rb +22 -0
  21. data/lib/ruby_vim_sdk/version.rb +5 -0
  22. data/lib/ruby_vim_sdk/vmodl/data_object.rb +102 -0
  23. data/lib/ruby_vim_sdk/vmodl/managed_object.rb +78 -0
  24. data/lib/ruby_vim_sdk/vmodl/method_name.rb +7 -0
  25. data/lib/ruby_vim_sdk/vmodl/property_path.rb +7 -0
  26. data/lib/ruby_vim_sdk/vmodl/type_name.rb +7 -0
  27. data/lib/ruby_vim_sdk/vmodl_helper.rb +33 -0
  28. data/lib/ruby_vim_sdk/vmomi_support.rb +280 -0
  29. data/spec/spec_helper.rb +10 -0
  30. data/spec/unit/soap/deserializer_spec.rb +206 -0
  31. data/spec/unit/soap/serializer_spec.rb +261 -0
  32. data/spec/unit/soap/stub_adapter_spec.rb +9 -0
  33. data/spec/unit/vmodl/data_object_spec.rb +9 -0
  34. data/spec/unit/vmodl/managed_object_spec.rb +9 -0
  35. data/spec/unit/vmodl_helper_spec.rb +36 -0
  36. data/spec/unit/vmomi_support_spec.rb +33 -0
  37. metadata +121 -0
@@ -0,0 +1,301 @@
1
+ module VimSdk
2
+ module Soap
3
+
4
+ class DelegatedDocument < DelegateClass(Nokogiri::XML::SAX::Document)
5
+
6
+ def initialize(delegate = nil)
7
+ super(delegate)
8
+ end
9
+
10
+ end
11
+
12
+ class NamespacedDocument < Nokogiri::XML::SAX::Document
13
+ def initialize(namespace_map = nil)
14
+ @namespace_map = namespace_map || {}
15
+ @prefix_stack = []
16
+ end
17
+
18
+ def start_namespaced_element(name, attrs)
19
+ end
20
+
21
+ def end_namespaced_element(name)
22
+ end
23
+
24
+ def namespace_and_wsdl_name(tag)
25
+ index = tag.index(":")
26
+ if index
27
+ prefix, name = tag[0..index - 1], tag[index + 1..-1]
28
+ else
29
+ prefix, name = nil, tag
30
+ end
31
+ namespace = @namespace_map[prefix].last
32
+ [namespace, name]
33
+ end
34
+
35
+ def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = [])
36
+ prefixes = []
37
+ ns.each do |namespace_prefix, namespace|
38
+ (@namespace_map[namespace_prefix] ||= []) << namespace
39
+ prefixes << namespace_prefix
40
+ end
41
+ @prefix_stack << prefixes
42
+ namespaced_attrs = {}
43
+ attrs.each do |attr|
44
+ attr_uri = attr.uri || uri
45
+ namespaced_attrs[[attr_uri, attr.localname]] = attr.value
46
+ end
47
+
48
+ start_namespaced_element([uri, name], namespaced_attrs)
49
+ end
50
+
51
+ def end_element_namespace(name, prefix = nil, uri = nil)
52
+ end_namespaced_element([uri, name])
53
+
54
+ unless @prefix_stack.empty?
55
+ prefixes = @prefix_stack.pop
56
+ prefixes.each { |namespace_prefix| @namespace_map[namespace_prefix].pop }
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ class SoapDeserializer < NamespacedDocument
63
+
64
+ attr_accessor :result
65
+
66
+ def initialize(stub = nil, version = nil)
67
+ super(nil)
68
+ @stub = stub
69
+ if version
70
+ @version = version
71
+ elsif @stub
72
+ @version = @stub.version
73
+ else
74
+ @version = nil
75
+ end
76
+ @result = nil
77
+ end
78
+
79
+ def deserialize(delegated_document, result_type = Object, is_fault = false, namespace_map = nil)
80
+ @is_fault = is_fault
81
+
82
+ @delegated_document = delegated_document
83
+ @original_document = @delegated_document.__getobj__
84
+ @delegated_document.__setobj__(self)
85
+
86
+ @result_type = result_type
87
+ @stack = []
88
+ @data = ""
89
+
90
+ if @result_type.ancestors.include?(Array)
91
+ @result = []
92
+ else
93
+ @result = nil
94
+ end
95
+
96
+ @namespace_map = namespace_map || {}
97
+ end
98
+
99
+ def lookup_wsdl_type(namespace, name, allow_managed_object_reference = false)
100
+ begin
101
+ return VmomiSupport.loaded_wsdl_type(namespace, name)
102
+ rescue
103
+ if allow_managed_object_reference
104
+ if name =~ /ManagedObjectReference/ && namespace == XMLNS_VMODL_BASE
105
+ return VmomiSupport.loaded_wsdl_type(namespace, name[0..-("Reference".length + 1)])
106
+ end
107
+ end
108
+
109
+ if name =~ /ManagedObjectReference/ && allow_managed_object_reference
110
+ return VmomiSupport.loaded_wsdl_type(XMLNS_VMODL_BASE, name[0..-("Reference".length + 1)])
111
+ end
112
+ return VmomiSupport.guess_wsdl_type(name)
113
+ end
114
+ end
115
+
116
+ def start_namespaced_element(name, attrs = {})
117
+ @data = ""
118
+ deserialize_as_localized_method_fault = true
119
+ if @stack.empty?
120
+ if @is_fault
121
+ object_type = lookup_wsdl_type(name[0], name[1][0..-("Fault".length + 1)])
122
+ deserialize_as_localized_method_fault = false
123
+ else
124
+ object_type = @result_type
125
+ end
126
+ else
127
+ parent_object = @stack.last
128
+ if parent_object.kind_of?(Array)
129
+ object_type = parent_object.class.item
130
+ elsif parent_object.kind_of?(Vmodl::DataObject)
131
+ object_type = parent_object.class.property(:wsdl_name => name[1]).type
132
+ if name[1] == "fault" and parent_object.kind_of?(Vmodl::LocalizedMethodFault)
133
+ deserialize_as_localized_method_fault = false
134
+ end
135
+ else
136
+ raise "Invalid type for tag #{name.pretty_inspect}"
137
+ end
138
+ end
139
+
140
+ xsi_type = attrs[[XMLNS_XSI, "type"]]
141
+ if xsi_type
142
+ unless DYNAMIC_TYPES.include?(object_type)
143
+ name = namespace_and_wsdl_name(xsi_type)
144
+ dynamic_type = lookup_wsdl_type(name[0], name[1], true)
145
+ object_type = dynamic_type unless dynamic_type.kind_of?(Array) || object_type.kind_of?(Array)
146
+ end
147
+ else
148
+ object_type = object_type.item if object_type.ancestors.include?(Array)
149
+ end
150
+
151
+ object_type = VmomiSupport.compatible_type(object_type, @version) if @version
152
+ ancestor_set = Set.new(object_type.ancestors)
153
+ if ancestor_set.include?(Vmodl::ManagedObject)
154
+ type_attr = attrs[[name[0], "type"]]
155
+ type_name = namespace_and_wsdl_name(type_attr)
156
+ @stack << VmomiSupport.guess_wsdl_type(type_name[1])
157
+ elsif ancestor_set.include?(Vmodl::DataObject) || ancestor_set.include?(Array)
158
+ if deserialize_as_localized_method_fault and object_type.ancestors.include?(Vmodl::MethodFault)
159
+ object_type = Vmodl::LocalizedMethodFault
160
+ end
161
+ @stack << object_type.new
162
+ else
163
+ @stack << object_type
164
+ end
165
+ end
166
+
167
+ def end_namespaced_element(name)
168
+ if @stack.empty?
169
+ @delegated_document.__setobj__(@original_document)
170
+ @original_document.end_namespaced_element(name)
171
+ return
172
+ end
173
+
174
+ object = @stack.pop
175
+
176
+ if object.kind_of?(Class) || object == Vmodl::TypeName
177
+ if object == Vmodl::TypeName
178
+ if @data.empty?
179
+ object = nil
180
+ else
181
+ object_name = namespace_and_wsdl_name(@data)
182
+ object = VmomiSupport.guess_wsdl_type(object_name[1])
183
+ end
184
+ elsif object == Vmodl::MethodName
185
+ object_name = namespace_and_wsdl_name(@data)
186
+ object = VmomiSupport.guess_wsdl_type(object_name[1])
187
+ elsif object == SoapBoolean
188
+ if @data == "0" || @data.downcase == "false"
189
+ object = false
190
+ elsif @data == "1" || @data.downcase == "true"
191
+ object = true
192
+ else
193
+ raise "Invalid boolean value: #{@data}"
194
+ end
195
+ elsif object == SoapBinary
196
+ object = Base64.decode64(@data)
197
+ elsif object == String
198
+ object = @data
199
+ elsif object == Time
200
+ object = Time.iso8601(@data)
201
+ else
202
+ ancestor_set = Set.new(object.ancestors)
203
+ if ancestor_set.include?(Vmodl::ManagedObject)
204
+ object = object.new(@data, @stub)
205
+ elsif object.ancestors.include?(SoapEnum)
206
+ object = object.const_get(VmodlHelper.underscore(@data).upcase)
207
+ elsif object == SoapFloat || object == SoapDouble
208
+ object = Float(@data)
209
+ elsif object == SoapInteger || object == SoapByte || object == SoapShort || object == SoapLong
210
+ object = Integer(@data)
211
+ else
212
+ object = object.new(@data)
213
+ end
214
+ end
215
+ elsif object.kind_of?(Vmodl::LocalizedMethodFault)
216
+ object.fault.msg = object.localized_message
217
+ object = object.fault
218
+ end
219
+
220
+ if !@stack.empty?
221
+ parent_object = @stack.last
222
+ if parent_object.kind_of?(Array)
223
+ parent_object << object
224
+ elsif parent_object.kind_of?(Vmodl::DataObject)
225
+ property_info = parent_object.class.property(:wsdl_name => name[1])
226
+ raise "Can't find #{name[1]} for #{parent_object.class.name}" if property_info.nil?
227
+ if !object.kind_of?(Array) && property_info.type.ancestors.include?(Array)
228
+ parent_object.send(property_info.name) << object
229
+ else
230
+ parent_object.send("#{property_info.name}=".to_sym, object)
231
+ end
232
+ else
233
+ parent_object.send("#{name[1]}=", object)
234
+ end
235
+ else
236
+ if !object.kind_of?(Array) && @result_type.ancestors.include?(Array)
237
+ @result << object
238
+ else
239
+ @result = object
240
+ @delegated_document.__setobj__(@original_document)
241
+ end
242
+ end
243
+ end
244
+
245
+ def characters(string)
246
+ @data += string
247
+ end
248
+ end
249
+
250
+ class SoapResponseDeserializer < NamespacedDocument
251
+
252
+ def initialize(stub)
253
+ super
254
+ @stub = stub
255
+ @deserializer = SoapDeserializer.new(stub)
256
+ end
257
+
258
+ def deserialize(contents, result_type, namespace_map = nil)
259
+ @result_type = result_type
260
+ @stack = []
261
+ @message = ""
262
+ @data = ""
263
+ @deserializer.result = nil
264
+ @is_fault = false
265
+ @delegated_document = DelegatedDocument.new(self)
266
+ @parser = Nokogiri::XML::SAX::Parser.new(@delegated_document)
267
+ @namespace_map = namespace_map || {}
268
+ @parser.parse(contents)
269
+ result = @deserializer.result
270
+ if @is_fault
271
+ result = Vmodl::RuntimeFault.new if result.nil?
272
+ result.msg = @message
273
+ end
274
+ result
275
+ end
276
+
277
+ def start_namespaced_element(name, attrs = {})
278
+ @data = ""
279
+ if name == [XMLNS_SOAPENV, "Fault"]
280
+ @is_fault = true
281
+ elsif @is_fault && name[1] == "detail"
282
+ @deserializer.deserialize(@delegated_document, Class, true, @namespace_map)
283
+ elsif name[1] =~ /Response$/
284
+ @deserializer.deserialize(@delegated_document, @result_type, false, @namespace_map)
285
+ end
286
+ end
287
+
288
+ def end_namespaced_element(name)
289
+ if @is_fault && name[1] == "faultstring"
290
+ @message = @data
291
+ end
292
+ end
293
+
294
+ def characters(string)
295
+ @data += string
296
+ end
297
+
298
+ end
299
+
300
+ end
301
+ end
@@ -0,0 +1,225 @@
1
+ module VimSdk
2
+ module Soap
3
+
4
+ class SoapSerializer
5
+
6
+ def initialize(writer, version, namespace_map)
7
+ @writer = writer
8
+ @version = version
9
+ @namespace_map = namespace_map
10
+
11
+ @namespace_map.each do |namespace, prefix|
12
+ if prefix == ""
13
+ @default_namespace = namespace
14
+ break
15
+ end
16
+ end
17
+ @default_namespace = "" if @default_namespace.nil?
18
+
19
+ @outermost_attributes = ""
20
+
21
+ [["xsi", XMLNS_XSI, :@xsi_prefix],
22
+ ["xsd", XMLNS_XSD, :@xsd_prefix]].each do |namespace_prefix, namespace, variable_name|
23
+ prefix = @namespace_map[namespace]
24
+ unless prefix
25
+ prefix = namespace_prefix
26
+ @outermost_attributes += " xmlns:#{prefix}=\"#{namespace}\""
27
+ @namespace_map = @namespace_map.dup
28
+ @namespace_map[namespace] = prefix
29
+ end
30
+ instance_variable_set(variable_name, "#{prefix}:")
31
+ end
32
+ end
33
+
34
+ def serialize(value, info, default_namespace = @default_namespace)
35
+ return unless VmomiSupport.is_child_version(@version, info.version)
36
+
37
+ if value.nil?
38
+ return if info.optional?
39
+ raise "Field #{info.name} is not optional"
40
+ elsif value.kind_of?(Array) && value.empty?
41
+ if info.type == Object
42
+ raise "Cannot assign empty 'untyped' array to an Any" unless value.class.ancestors.include?(TypedArray)
43
+ elsif info.optional?
44
+ return
45
+ else
46
+ raise "Field #{info.name} is not optional"
47
+ end
48
+ end
49
+
50
+ if @outermost_attributes
51
+ attribute = @outermost_attributes
52
+ @outermost_attributes = nil
53
+ else
54
+ attribute = ""
55
+ end
56
+
57
+ current_default_namespace = default_namespace
58
+ current_tag_namespace = VmomiSupport.wsdl_namespace(info.version)
59
+ if current_tag_namespace != default_namespace
60
+ attribute += " xmlns=\"#{current_tag_namespace}\""
61
+ current_default_namespace = current_tag_namespace
62
+ end
63
+
64
+ if value.kind_of?(Vmodl::ManagedObject)
65
+ if info.type == Object
66
+ namespace_attribute, qualified_name = qualified_name(Vmodl::ManagedObject, current_default_namespace)
67
+ attribute += "#{namespace_attribute} #{@xsi_prefix}type=\"#{qualified_name}\""
68
+ end
69
+ _, name = VmomiSupport.qualified_wsdl_name(value.class)
70
+ attribute += " type=\"#{name}\""
71
+ @writer << "<#{info.wsdl_name}#{attribute}>#{value.__mo_id__.to_xs}</#{info.wsdl_name}>"
72
+ elsif value.kind_of?(Vmodl::DataObject)
73
+ if value.kind_of?(Vmodl::MethodFault)
74
+ localized_method_fault = Vmodl::LocalizedMethodFault.new
75
+ localized_method_fault.fault = value
76
+ localized_method_fault.localized_message = value.msg
77
+
78
+ unless info.type == Object
79
+ info = info.dup
80
+ info.type = Vmodl::LocalizedMethodFault
81
+ end
82
+
83
+ serialize_data_object(localized_method_fault, info, attribute, current_default_namespace)
84
+ else
85
+ serialize_data_object(value, info, attribute, current_default_namespace)
86
+ end
87
+ elsif value.kind_of?(Array)
88
+ if info.type == Object
89
+ if value.class.respond_to?(:item)
90
+ item_type = value.class.item
91
+ else
92
+ item_type = value.first.class
93
+ end
94
+
95
+ if DYNAMIC_TYPES.include?(item_type)
96
+ tag = "string"
97
+ type = String::TypedArray
98
+ elsif item_type.ancestors.include?(Vmodl::ManagedObject)
99
+ tag = "ManagedObjectReference"
100
+ type = Vmodl::ManagedObject::TypedArray
101
+ else
102
+ tag = VmomiSupport.wsdl_name(item_type)
103
+ type = item_type::TypedArray
104
+ end
105
+
106
+ namespace_attribute, qualified_name = qualified_name(type, current_default_namespace)
107
+ attribute += "#{namespace_attribute} #{@xsi_prefix}type=\"#{qualified_name}\""
108
+ @writer << "<#{info.wsdl_name}#{attribute}>"
109
+
110
+ item_info = info.dup
111
+ item_info.wsdl_name = tag
112
+ item_info.type = value.class
113
+
114
+ value.each do |child|
115
+ serialize(child, item_info, current_default_namespace)
116
+ end
117
+
118
+ @writer << "</#{info.wsdl_name}>"
119
+ else
120
+ item_info = info.dup
121
+ item_info.type = info.type.item
122
+ value.each do |v|
123
+ serialize(v, item_info, default_namespace)
124
+ end
125
+ end
126
+ elsif value.kind_of?(Class)
127
+ if info.type == Object
128
+ attribute += " #{@xsi_prefix}type=\"#{@xsd_prefix}string\""
129
+ end
130
+ @writer << "<#{info.wsdl_name}#{attribute}>#{VmomiSupport.wsdl_name(value)}</#{info.wsdl_name}>"
131
+ elsif value.kind_of?(Vmodl::MethodName)
132
+ if info.type == Object
133
+ attribute += " #{@xsi_prefix}type=\"#{@xsd_prefix}string\""
134
+ end
135
+ @writer << "<#{info.wsdl_name}#{attribute}>#{value}</#{info.wsdl_name}>"
136
+ elsif value.kind_of?(Time)
137
+ if info.type == Object
138
+ namespace_attribute, qualified_name = qualified_name(value.class, current_default_namespace)
139
+ attribute += "#{namespace_attribute} #{@xsi_prefix}type=\"#{qualified_name}\""
140
+ end
141
+ @writer << "<#{info.wsdl_name}#{attribute}>#{value.utc.iso8601}</#{info.wsdl_name}>"
142
+ elsif value.kind_of?(SoapBinary) || info.type == SoapBinary
143
+ if info.type == Object
144
+ namespace_attribute, qualified_name = qualified_name(value.class, current_default_namespace)
145
+ attribute += "#{namespace_attribute} #{@xsi_prefix}type=\"#{qualified_name}\""
146
+ end
147
+ @writer << "<#{info.wsdl_name}#{attribute}>#{Base64.encode64(value)}</#{info.wsdl_name}>"
148
+ elsif value.kind_of?(TrueClass) || value.kind_of?(FalseClass) || value.kind_of?(SoapBoolean)
149
+ if info.type == Object
150
+ namespace_attribute, qualified_name = qualified_name(value.class, current_default_namespace)
151
+ attribute += "#{namespace_attribute} #{@xsi_prefix}type=\"#{qualified_name}\""
152
+ end
153
+ @writer << "<#{info.wsdl_name}#{attribute}>#{value ? "true" : "false"}</#{info.wsdl_name}>"
154
+ else
155
+ if info.type == Object
156
+ if value.kind_of?(Vmodl::PropertyPath)
157
+ attribute += " #{@xsi_prefix}type=\"#{@xsd_prefix}string\""
158
+ else
159
+ namespace_attribute, qualified_name = qualified_name(value.class, current_default_namespace)
160
+ attribute += "#{namespace_attribute} #{@xsi_prefix}type=\"#{qualified_name}\""
161
+ end
162
+ end
163
+ value = value.to_s unless value.kind_of?(String)
164
+ @writer << "<#{info.wsdl_name}#{attribute}>#{value.to_xs}</#{info.wsdl_name}>"
165
+ end
166
+ end
167
+
168
+ def serialize_data_object(value, info, attribute, current_default_namespace)
169
+ dynamic_type = VmomiSupport.compatible_type(value.class, @version)
170
+ if dynamic_type != info.type
171
+ namespace_attribute, qualified_name = qualified_name(dynamic_type, current_default_namespace)
172
+ attribute += "#{namespace_attribute} #{@xsi_prefix}type=\"#{qualified_name}\""
173
+ end
174
+ @writer << "<#{info.wsdl_name}#{attribute}>"
175
+ if dynamic_type.kind_of?(Vmodl::LocalizedMethodFault)
176
+ info.type.property_list.each do |property|
177
+ property_value = value.send(property.name)
178
+ if property.name == "fault"
179
+ property_value = property_value.dup
180
+ property_value.msg = nil
181
+ serialize_data_object(property_value, property, "", current_default_namespace)
182
+ else
183
+ serialize(property_value, property, current_default_namespace)
184
+ end
185
+ end
186
+ else
187
+ value.class.property_list.each do |property|
188
+ serialize(value.__send__(property.name), property, current_default_namespace)
189
+ end
190
+ end
191
+ @writer << "</#{info.wsdl_name}>"
192
+ end
193
+
194
+ def serialize_fault_detail(value, type_info)
195
+ serialize_data_object(value, type_info, "", @default_namespace)
196
+ end
197
+
198
+ def namespace_prefix(namespace)
199
+ if namespace == @default_namespace
200
+ ""
201
+ else
202
+ prefix = @namespace_map[namespace]
203
+ prefix ? "#{prefix}:" : ""
204
+ end
205
+ end
206
+
207
+ def qualified_name(type, default_namespace)
208
+ attribute = ""
209
+ namespace, name = VmomiSupport.qualified_wsdl_name(type)
210
+ if namespace == default_namespace
211
+ prefix = ""
212
+ else
213
+ prefix = @namespace_map[namespace]
214
+ unless prefix
215
+ prefix = namespace.split(":", 2).last
216
+ attribute = " xmlns:#{prefix}=\"#{namespace}\""
217
+ end
218
+ end
219
+ [attribute, prefix.empty? ? name : "#{prefix}:#{name}"]
220
+ end
221
+
222
+ end
223
+
224
+ end
225
+ end