ruby_vim_sdk 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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