rubywbem 0.1.0
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.
- data/AUTHORS +1 -0
- data/CHANGELOG +3 -0
- data/LICENSE +339 -0
- data/README +28 -0
- data/Rakefile +146 -0
- data/lib/wbem.rb +23 -0
- data/lib/wbem/cim_constants.rb +50 -0
- data/lib/wbem/cim_http.rb +137 -0
- data/lib/wbem/cim_obj.rb +1148 -0
- data/lib/wbem/cim_operations.rb +571 -0
- data/lib/wbem/cim_types.rb +195 -0
- data/lib/wbem/cim_xml.rb +1428 -0
- data/lib/wbem/tupleparse.rb +1181 -0
- data/lib/wbem/tupletree.rb +138 -0
- data/ruby-wbem.spec +54 -0
- data/testsuite/CIM_DTD_V22.dtd +324 -0
- data/testsuite/comfychair.rb +442 -0
- data/testsuite/runtests.sh +56 -0
- data/testsuite/test_cim_obj.rb +1610 -0
- data/testsuite/test_cim_operations.rb +702 -0
- data/testsuite/test_cim_xml.rb +1495 -0
- data/testsuite/test_nocasehash.rb +248 -0
- data/testsuite/test_tupleparse.rb +208 -0
- data/testsuite/validate.rb +93 -0
- metadata +68 -0
@@ -0,0 +1,1181 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2006, Red Hat, Inc
|
3
|
+
# Scott Seago <sseago@redhat.com>
|
4
|
+
#
|
5
|
+
# derived from pywbem, written by Tim Potter <tpot@hp.com>, Martin Pool <mbp@hp.com>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
15
|
+
#
|
16
|
+
|
17
|
+
# '''Tuple parser for the XML schema representing CIM messages.
|
18
|
+
|
19
|
+
# This framework is meant to add some value to the tuple-tree
|
20
|
+
# representation of CIM in XML by having the following properties:
|
21
|
+
|
22
|
+
# - Silently ignoring whitespace text elements
|
23
|
+
|
24
|
+
# - Conversion from tuple-tree representation into a python dictionary
|
25
|
+
# which can then be accessed in a readable fashion.
|
26
|
+
|
27
|
+
# - Validation of the XML elements and attributes without having to
|
28
|
+
# use the DTD file or any external tools.
|
29
|
+
|
30
|
+
# '''
|
31
|
+
|
32
|
+
# Implementation: this works by a recursive descent down the CIM XML
|
33
|
+
# tupletree. As we walk down, we produce cim_obj and cim_type
|
34
|
+
# objects representing the CIM message in digested form.
|
35
|
+
|
36
|
+
# For each XML node type FOO there is one function parse_foo, which
|
37
|
+
# returns the digested form by examining a tuple tree rooted at FOO.
|
38
|
+
|
39
|
+
# The resulting objects are constrained to the shape of the CIM XML
|
40
|
+
# tree: if one node in XML contains another, then the corresponding
|
41
|
+
# CIM object will contain the second. However, there can be local
|
42
|
+
# transformations at each node: some levels are ommitted, some are
|
43
|
+
# transformed into lists or hashes.
|
44
|
+
|
45
|
+
# We try to validate that the tree is well-formed too. The validation
|
46
|
+
# is more strict than the DTD, but it is forgiving of implementation
|
47
|
+
# quirks and bugs in Pegasus.
|
48
|
+
|
49
|
+
# Bear in mind in the parse functions that each tupletree tuple is
|
50
|
+
# structured as
|
51
|
+
|
52
|
+
# tt[0]: name string == name(tt)
|
53
|
+
# tt[1]: hash of attributes == attrs(tt)
|
54
|
+
# tt[2]: sequence of children == kids(tt)
|
55
|
+
|
56
|
+
# At the moment this layer is a little inconsistent: in some places it
|
57
|
+
# returns tupletrees, and in others Python objects. It may be better
|
58
|
+
# to hide the tupletree/XML representation from higher level code.
|
59
|
+
|
60
|
+
|
61
|
+
# TODO: Maybe take a DTD fragment like "(DECLGROUP |
|
62
|
+
# DECLGROUP.WITHNAME | DECLGROUP.WITHPATH)*", parse that and check it
|
63
|
+
# directly.
|
64
|
+
|
65
|
+
# TODO: Syntax-check some attributes with defined formats, such as NAME
|
66
|
+
|
67
|
+
# TODO: Implement qualifiers by making subclasses of CIM types with a
|
68
|
+
# .qualifiers property.
|
69
|
+
|
70
|
+
require "wbem/cim_obj"
|
71
|
+
require "date"
|
72
|
+
|
73
|
+
module WBEM
|
74
|
+
|
75
|
+
class ParseError < Exception
|
76
|
+
#"""This exception is raised when there is a validation error detected
|
77
|
+
#by the parser."""
|
78
|
+
end
|
79
|
+
|
80
|
+
def WBEM.filter_tuples(l)
|
81
|
+
# """Return only the tuples in a list.
|
82
|
+
|
83
|
+
# In a tupletree, tuples correspond to XML elements. Useful for
|
84
|
+
# stripping out whitespace data in a child list."""
|
85
|
+
if l.nil?
|
86
|
+
[]
|
87
|
+
else
|
88
|
+
l.find_all { |x| x.is_a? Array }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def WBEM.pcdata(tt)
|
93
|
+
# """Return the concatenated character data within a tt.
|
94
|
+
|
95
|
+
# The tt must not have non-character children."""
|
96
|
+
tt[2].each do |x|
|
97
|
+
unless x.is_a? String
|
98
|
+
raise ParseError, "unexpected node #{x} under #{tt}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
tt[2].join
|
102
|
+
end
|
103
|
+
|
104
|
+
def WBEM.name(tt)
|
105
|
+
tt[0]
|
106
|
+
end
|
107
|
+
|
108
|
+
def WBEM.attrs(tt)
|
109
|
+
tt[1]
|
110
|
+
end
|
111
|
+
|
112
|
+
def WBEM.kids(tt)
|
113
|
+
WBEM.filter_tuples(tt[2])
|
114
|
+
end
|
115
|
+
|
116
|
+
def WBEM.check_node(tt, nodename, required_attrs = [], optional_attrs = [],
|
117
|
+
allowed_children = nil,
|
118
|
+
allow_pcdata = false)
|
119
|
+
# """Check static local constraints on a single node.
|
120
|
+
|
121
|
+
# The node must have the given name. The required attrs must be
|
122
|
+
# present, and the optional attrs may be.
|
123
|
+
|
124
|
+
# If allowed_children is not nil, the node may have children of the
|
125
|
+
# given types. It can be [] for nodes that may not have any
|
126
|
+
# children. If it's nil, it is assumed the children are validated
|
127
|
+
# in some other way.
|
128
|
+
|
129
|
+
# If allow_pcdata is true, then non-whitespace text children are allowed.
|
130
|
+
# (Whitespace text nodes are always allowed.)
|
131
|
+
# """
|
132
|
+
|
133
|
+
unless WBEM.name(tt) == nodename
|
134
|
+
raise ParseError, "expected node type #{nodename}, not #{WBEM.name(tt)} \n #{tt}"
|
135
|
+
end
|
136
|
+
|
137
|
+
# Check we have all the required attributes, and no unexpected ones
|
138
|
+
tt_attrs = {}
|
139
|
+
tt_attrs = WBEM.attrs(tt).clone unless WBEM.attrs(tt).nil?
|
140
|
+
|
141
|
+
required_attrs.each do |attr|
|
142
|
+
unless tt_attrs.has_key?(attr)
|
143
|
+
raise ParseError, "expected #{attr} attribute on #{WBEM.name(tt)} node, but only have #{WBEM.attrs(tt).keys()}"
|
144
|
+
end
|
145
|
+
tt_attrs.delete(attr)
|
146
|
+
end
|
147
|
+
|
148
|
+
optional_attrs.each { |attr| tt_attrs.delete(attr) }
|
149
|
+
|
150
|
+
unless tt_attrs.empty?
|
151
|
+
raise ParseError, "invalid extra attributes #{tt_attrs.keys()}"
|
152
|
+
end
|
153
|
+
|
154
|
+
unless allowed_children.nil?
|
155
|
+
WBEM.kids(tt).each do |c|
|
156
|
+
unless allowed_children.include?(WBEM.name(c))
|
157
|
+
raise ParseError, "unexpected node #{WBEM.name(c)} under #{WBEM.name(tt)}; wanted #{allowed_children}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
unless allow_pcdata
|
163
|
+
tt[2].each do |c|
|
164
|
+
if (c.is_a? String and c.delete(" \t\n").length > 0)
|
165
|
+
raise ParseError, "unexpected non-blank pcdata node #{c} under #{WBEM.name(tt)}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def WBEM.one_child(tt, acceptable)
|
172
|
+
# """Parse children of a node with exactly one child node.
|
173
|
+
|
174
|
+
# PCData is ignored.
|
175
|
+
# """
|
176
|
+
k = WBEM.kids(tt)
|
177
|
+
|
178
|
+
unless k.length == 1
|
179
|
+
raise ParseError, "expecting just one #{acceptable}, got #{k.each {|t| t[0] }}"
|
180
|
+
end
|
181
|
+
|
182
|
+
child = k[0]
|
183
|
+
|
184
|
+
unless acceptable.include?(WBEM.name(child))
|
185
|
+
raise ParseError, "expecting one of #{acceptable}, got #{WBEM.name(child)} under #{WBEM.name(tt)}"
|
186
|
+
end
|
187
|
+
|
188
|
+
return WBEM.parse_any(child)
|
189
|
+
end
|
190
|
+
|
191
|
+
def WBEM.optional_child(tt, allowed)
|
192
|
+
# """Parse exactly zero or one of a list of elements from the
|
193
|
+
# child nodes."""
|
194
|
+
k = WBEM.kids(tt)
|
195
|
+
|
196
|
+
if k.length > 1
|
197
|
+
raise ParseError, "expecting zero or one of #{allowed} under #{tt}"
|
198
|
+
elsif k.length == 1
|
199
|
+
return WBEM.one_child(tt, allowed)
|
200
|
+
else
|
201
|
+
return nil
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def WBEM.list_of_various(tt, acceptable)
|
206
|
+
# """Parse zero or more of a list of elements from the child nodes.
|
207
|
+
|
208
|
+
# Each element of the list can be any type from the list of acceptable
|
209
|
+
# nodes."""
|
210
|
+
|
211
|
+
r = []
|
212
|
+
|
213
|
+
WBEM.kids(tt).each do |child|
|
214
|
+
unless acceptable.include?(WBEM.name(child))
|
215
|
+
raise ParseError, "expected one of #{acceptable} under #{WBEM.name(tt)}, got #{WBEM.name(child)}"
|
216
|
+
end
|
217
|
+
r << WBEM.parse_any(child)
|
218
|
+
end
|
219
|
+
return r
|
220
|
+
end
|
221
|
+
|
222
|
+
def WBEM.list_of_matching(tt, matched)
|
223
|
+
# """Parse only the children of particular types under tt.
|
224
|
+
|
225
|
+
# Other children are ignored rather than giving an error."""
|
226
|
+
|
227
|
+
r = []
|
228
|
+
|
229
|
+
WBEM.kids(tt).each do |child|
|
230
|
+
r << WBEM.parse_any(child) if matched.include?(WBEM.name(child))
|
231
|
+
end
|
232
|
+
return r
|
233
|
+
end
|
234
|
+
|
235
|
+
def WBEM.list_of_same(tt, acceptable)
|
236
|
+
# """Parse a list of elements from child nodes.
|
237
|
+
|
238
|
+
# The children can be any of the listed acceptable types, but they
|
239
|
+
# must all be the same.
|
240
|
+
# """
|
241
|
+
|
242
|
+
unless (k = WBEM.kids(tt))
|
243
|
+
return [] # empty list, consistent with list_of_various
|
244
|
+
end
|
245
|
+
|
246
|
+
w = WBEM.name(k[0])
|
247
|
+
unless acceptable.include?(w)
|
248
|
+
raise ParseError, "expected one of #{acceptable} under #{WBEM.name(tt)}, got #{WBEM.name(child)}"
|
249
|
+
end
|
250
|
+
r = []
|
251
|
+
k.each do |child|
|
252
|
+
unless WBEM.name(child) == w
|
253
|
+
raise ParseError, "expected list of #{w} under #{WBEM.name(child)}, but found #{WBEM.name(tt)}"
|
254
|
+
end
|
255
|
+
r << WBEM.parse_any(child)
|
256
|
+
end
|
257
|
+
return r
|
258
|
+
end
|
259
|
+
|
260
|
+
def WBEM.notimplemented(tt)
|
261
|
+
raise ParseError, "parser for #{WBEM.name(tt)} not implemented"
|
262
|
+
end
|
263
|
+
#
|
264
|
+
# Root element
|
265
|
+
#
|
266
|
+
|
267
|
+
def WBEM.parse_cim(tt)
|
268
|
+
# """
|
269
|
+
# <!ELEMENT CIM (MESSAGE | DECLARATION)>
|
270
|
+
# <!ATTLIST CIM
|
271
|
+
# CIMVERSION CDATA #REQUIRED
|
272
|
+
# DTDVERSION CDATA #REQUIRED>
|
273
|
+
# """
|
274
|
+
|
275
|
+
WBEM.check_node(tt, "CIM", ["CIMVERSION", "DTDVERSION"])
|
276
|
+
|
277
|
+
unless WBEM.attrs(tt)["CIMVERSION"] == "2.0"
|
278
|
+
raise ParseError, "CIMVERSION is #{WBEM.attrs(tt)[CIMVERSION]}, expected 2.0"
|
279
|
+
end
|
280
|
+
child = WBEM.one_child(tt, ["MESSAGE", "DECLARATION"])
|
281
|
+
return [WBEM.name(tt), WBEM.attrs(tt), child]
|
282
|
+
end
|
283
|
+
|
284
|
+
#
|
285
|
+
# Object value elements
|
286
|
+
#
|
287
|
+
|
288
|
+
def WBEM.parse_value(tt)
|
289
|
+
# '''Return VALUE contents as a string'''
|
290
|
+
## <!ELEMENT VALUE (#PCDATA)>
|
291
|
+
WBEM.check_node(tt, "VALUE", [], [], [], true)
|
292
|
+
return WBEM.pcdata(tt)
|
293
|
+
end
|
294
|
+
|
295
|
+
def WBEM.parse_value_array(tt)
|
296
|
+
#"""Return list of strings."""
|
297
|
+
## <!ELEMENT VALUE.ARRAY (VALUE*)>
|
298
|
+
WBEM.check_node(tt, "VALUE.ARRAY", [], [], ["VALUE"])
|
299
|
+
return WBEM.list_of_same(tt, ["VALUE"])
|
300
|
+
end
|
301
|
+
|
302
|
+
def WBEM.parse_value_reference(tt)
|
303
|
+
# """
|
304
|
+
# <!ELEMENT VALUE.REFERENCE (CLASSPATH | LOCALCLASSPATH | CLASSNAME |
|
305
|
+
# INSTANCEPATH | LOCALINSTANCEPATH |
|
306
|
+
# INSTANCENAME)>
|
307
|
+
# """
|
308
|
+
|
309
|
+
WBEM.check_node(tt, "VALUE.REFERENCE", [])
|
310
|
+
|
311
|
+
child = WBEM.one_child(tt,
|
312
|
+
["CLASSPATH", "LOCALCLASSPATH", "CLASSNAME",
|
313
|
+
"INSTANCEPATH", "LOCALINSTANCEPATH",
|
314
|
+
"INSTANCENAME"])
|
315
|
+
|
316
|
+
# The VALUE.REFERENCE wrapper element is discarded
|
317
|
+
return child
|
318
|
+
end
|
319
|
+
|
320
|
+
def WBEM.parse_value_refarray(tt)
|
321
|
+
# """
|
322
|
+
# <!ELEMENT VALUE.REFARRAY (VALUE.REFERENCE*)>
|
323
|
+
# """
|
324
|
+
|
325
|
+
WBEM.check_node(tt, "VALUE.REFARRAY")
|
326
|
+
children = WBEM.list_of_various(tt, ["VALUE.REFERENCE"])
|
327
|
+
return [WBEM.name(tt), WBEM.attrs(tt), children]
|
328
|
+
end
|
329
|
+
|
330
|
+
def WBEM.parse_value_object(tt)
|
331
|
+
# """
|
332
|
+
# <!ELEMENT VALUE.OBJECT (CLASS | INSTANCE)>
|
333
|
+
# """
|
334
|
+
|
335
|
+
WBEM.check_node(tt, "VALUE.OBJECT")
|
336
|
+
child = WBEM.one_child(tt, ["CLASS", "INSTANCE"])
|
337
|
+
return [WBEM.name(tt), WBEM.attrs(tt), child]
|
338
|
+
end
|
339
|
+
|
340
|
+
def WBEM.parse_value_namedinstance(tt)
|
341
|
+
# """
|
342
|
+
# <!ELEMENT VALUE.NAMEDINSTANCE (INSTANCENAME, INSTANCE)>
|
343
|
+
# """
|
344
|
+
|
345
|
+
WBEM.check_node(tt, "VALUE.NAMEDINSTANCE")
|
346
|
+
k = WBEM.kids(tt)
|
347
|
+
unless k.length == 2
|
348
|
+
raise ParseError, "expecting (INSTANCENAME, INSTANCE), got #{k}"
|
349
|
+
end
|
350
|
+
instancename = WBEM.parse_instancename(k[0])
|
351
|
+
instance = WBEM.parse_instance(k[1])
|
352
|
+
instance.path = instancename
|
353
|
+
return instance
|
354
|
+
end
|
355
|
+
|
356
|
+
def WBEM.parse_value_namedobject(tt)
|
357
|
+
# """
|
358
|
+
# <!ELEMENT VALUE.NAMEDOBJECT (CLASS | (INSTANCENAME, INSTANCE))>
|
359
|
+
# """
|
360
|
+
|
361
|
+
WBEM.check_node(tt, "VALUE.NAMEDOBJECT")
|
362
|
+
k = WBEM.kids(tt)
|
363
|
+
if k.length == 1
|
364
|
+
object = WBEM.parse_class(k[0])
|
365
|
+
elsif k.length == 2
|
366
|
+
path = WBEM.parse_instancename(k[0])
|
367
|
+
object = WBEM.parse_instance(k[1])
|
368
|
+
object.path = path
|
369
|
+
else
|
370
|
+
raise ParseError, "Expecting one or two elements, got #{k}"
|
371
|
+
end
|
372
|
+
return [WBEM.name(tt), WBEM.attrs(tt), object]
|
373
|
+
end
|
374
|
+
|
375
|
+
def WBEM.parse_value_objectwithlocalpath(tt)
|
376
|
+
# """
|
377
|
+
# <!ELEMENT VALUE.OBJECTWITHLOCALPATH ((LOCALCLASSPATH, CLASS) |
|
378
|
+
# (LOCALINSTANCEPATH, INSTANCE))>
|
379
|
+
# """
|
380
|
+
|
381
|
+
WBEM.check_node(tt, "VALUE.OBJECTWITHLOCALPATH")
|
382
|
+
k = WBEM.kids(tt)
|
383
|
+
unless k.length == 2
|
384
|
+
raise ParseError, "Expecting two elements, got #{k.length}"
|
385
|
+
end
|
386
|
+
if k[0][0] == "LOCALCLASSPATH"
|
387
|
+
object = [WBEM.parse_localclasspath(k[0]),
|
388
|
+
WBEM.parse_class(k[1])]
|
389
|
+
else
|
390
|
+
path = WBEM.parse_localinstancepath(k[0])
|
391
|
+
object = WBEM.parse_instance(k[1])
|
392
|
+
object.path = path
|
393
|
+
end
|
394
|
+
return [WBEM.name(tt), WBEM.attrs(tt), object]
|
395
|
+
end
|
396
|
+
|
397
|
+
def WBEM.parse_value_objectwithpath(tt)
|
398
|
+
# """
|
399
|
+
# <!ELEMENT VALUE.OBJECTWITHPATH ((CLASSPATH, CLASS) |
|
400
|
+
# (INSTANCEPATH, INSTANCE))>
|
401
|
+
# """
|
402
|
+
|
403
|
+
WBEM.check_node(tt, "VALUE.OBJECTWITHPATH")
|
404
|
+
k = WBEM.kids(tt)
|
405
|
+
unless k.length == 2
|
406
|
+
raise ParseError, "Expecting two elements, got #{k.length}"
|
407
|
+
end
|
408
|
+
|
409
|
+
if WBEM.name(k[0]) == "CLASSPATH"
|
410
|
+
object = [WBEM.parse_classpath(k[0]),
|
411
|
+
WBEM.parse_class(k[1])]
|
412
|
+
else
|
413
|
+
path = WBEM.parse_instancepath(k[0])
|
414
|
+
object = WBEM.parse_instance(k[1])
|
415
|
+
object.path = path
|
416
|
+
end
|
417
|
+
return [WBEM.name(tt), WBEM.attrs(tt), object]
|
418
|
+
end
|
419
|
+
|
420
|
+
#
|
421
|
+
# Object naming and locating elements
|
422
|
+
#
|
423
|
+
|
424
|
+
def WBEM.parse_namespacepath(tt)
|
425
|
+
# """
|
426
|
+
# <!ELEMENT NAMESPACEPATH (HOST, LOCALNAMESPACEPATH)>
|
427
|
+
# """
|
428
|
+
|
429
|
+
WBEM.check_node(tt, "NAMESPACEPATH")
|
430
|
+
unless ((k = WBEM.kids(tt)).length == 2)
|
431
|
+
raise ParseError, "Expecting (HOST, LOCALNAMESPACEPATH) got #{WBEM.kids(tt).keys()}"
|
432
|
+
end
|
433
|
+
|
434
|
+
host = WBEM.parse_host(k[0])
|
435
|
+
localnspath = WBEM.parse_localnamespacepath(k[1])
|
436
|
+
return CIMNamespacePath.new(host, localnspath)
|
437
|
+
end
|
438
|
+
|
439
|
+
def WBEM.parse_localnamespacepath(tt)
|
440
|
+
# """
|
441
|
+
# <!ELEMENT LOCALNAMESPACEPATH (NAMESPACE+)>
|
442
|
+
# """
|
443
|
+
WBEM.check_node(tt, "LOCALNAMESPACEPATH", [], [], ["NAMESPACE"])
|
444
|
+
if WBEM.kids(tt).length == 0
|
445
|
+
raise ParseError, "Expecting one or more of NAMESPACE, got nothing"
|
446
|
+
end
|
447
|
+
WBEM.list_of_various(tt, ["NAMESPACE"]).join("/")
|
448
|
+
end
|
449
|
+
|
450
|
+
def WBEM.parse_host(tt)
|
451
|
+
# """
|
452
|
+
# <!ELEMENT HOST (#PCDATA)>
|
453
|
+
# """
|
454
|
+
WBEM.check_node(tt, "HOST", [], [], nil , true)
|
455
|
+
return WBEM.pcdata(tt)
|
456
|
+
end
|
457
|
+
|
458
|
+
def WBEM.parse_namespace(tt)
|
459
|
+
# """
|
460
|
+
# <!ELEMENT NAMESPACE EMPTY>
|
461
|
+
# <!ATTLIST NAMESPACE
|
462
|
+
# %CIMName;>
|
463
|
+
# """
|
464
|
+
|
465
|
+
WBEM.check_node(tt, "NAMESPACE", ["NAME"], [], [])
|
466
|
+
return WBEM.attrs(tt)["NAME"]
|
467
|
+
end
|
468
|
+
|
469
|
+
def WBEM.parse_classpath(tt)
|
470
|
+
# """
|
471
|
+
# <!ELEMENT CLASSPATH (NAMESPACEPATH, CLASSNAME)>
|
472
|
+
# """
|
473
|
+
WBEM.check_node(tt, "CLASSPATH")
|
474
|
+
unless ((k = WBEM.kids(tt)).length == 2)
|
475
|
+
raise ParseError, "Expecting (NAMESPACEPATH, CLASSNAME) got #{k.keys()}"
|
476
|
+
end
|
477
|
+
nspath = WBEM.parse_namespacepath(k[0])
|
478
|
+
classname = WBEM.parse_classname(k[1])
|
479
|
+
return CIMClassPath.new(nspath.host, nspath.localnamespacepath,
|
480
|
+
classname.classname)
|
481
|
+
end
|
482
|
+
|
483
|
+
def WBEM.parse_localclasspath(tt)
|
484
|
+
# """
|
485
|
+
# <!ELEMENT LOCALCLASSPATH (LOCALNAMESPACEPATH, CLASSNAME)>
|
486
|
+
# """
|
487
|
+
WBEM.check_node(tt, "LOCALCLASSPATH")
|
488
|
+
unless ((k = WBEM.kids(tt)).length == 2)
|
489
|
+
raise ParseError, "Expecting (LOCALNAMESPACEPATH, CLASSNAME) got #{k.keys()}"
|
490
|
+
end
|
491
|
+
localnspath = WBEM.parse_localnamespacepath(k[0])
|
492
|
+
classname = WBEM.parse_classname(k[1])
|
493
|
+
return CIMLocalClassPath.new(localnspath, classname.classname)
|
494
|
+
end
|
495
|
+
|
496
|
+
def WBEM.parse_classname(tt)
|
497
|
+
# """
|
498
|
+
# <!ELEMENT CLASSNAME EMPTY>
|
499
|
+
# <!ATTLIST CLASSNAME
|
500
|
+
# %CIMName;>
|
501
|
+
# """
|
502
|
+
WBEM.check_node(tt, "CLASSNAME", ["NAME"], [], [])
|
503
|
+
return CIMClassName.new(WBEM.attrs(tt)["NAME"])
|
504
|
+
end
|
505
|
+
|
506
|
+
def WBEM.parse_instancepath(tt)
|
507
|
+
# """
|
508
|
+
# <!ELEMENT INSTANCEPATH (NAMESPACEPATH, INSTANCENAME)>
|
509
|
+
# """
|
510
|
+
|
511
|
+
WBEM.check_node(tt, "INSTANCEPATH")
|
512
|
+
|
513
|
+
unless ((k = WBEM.kids(tt)).length == 2)
|
514
|
+
raise ParseError, "Expecting (NAMESPACEPATH, INSTANCENAME) got #{k}"
|
515
|
+
end
|
516
|
+
nspath = WBEM.parse_namespacepath(k[0])
|
517
|
+
instancename = WBEM.parse_instancename(k[1])
|
518
|
+
instancename.host = nspath.host
|
519
|
+
instancename.namespace = nspath.localnamespacepath
|
520
|
+
|
521
|
+
return instancename
|
522
|
+
end
|
523
|
+
|
524
|
+
def WBEM.parse_localinstancepath(tt)
|
525
|
+
# """
|
526
|
+
# <!ELEMENT LOCALINSTANCEPATH (LOCALNAMESPACEPATH, INSTANCENAME)>
|
527
|
+
# """
|
528
|
+
|
529
|
+
WBEM.check_node(tt, "LOCALINSTANCEPATH")
|
530
|
+
|
531
|
+
unless ((k = WBEM.kids(tt)).length == 2)
|
532
|
+
raise ParseError, "Expecting (LOCALNAMESPACEPATH, INSTANCENAME) got #{k.keys()}"
|
533
|
+
end
|
534
|
+
localnspath = WBEM.parse_localnamespacepath(k[0])
|
535
|
+
instancename = WBEM.parse_instancename(k[1])
|
536
|
+
instancename.namespace = localnspath
|
537
|
+
return instancename
|
538
|
+
end
|
539
|
+
|
540
|
+
def WBEM.parse_instancename(tt)
|
541
|
+
# """Parse XML INSTANCENAME into CIMInstanceName object."""
|
542
|
+
|
543
|
+
## <!ELEMENT INSTANCENAME (KEYBINDING* | KEYVALUE? | VALUE.REFERENCE?)>
|
544
|
+
## <!ATTLIST INSTANCENAME %ClassName;>
|
545
|
+
|
546
|
+
WBEM.check_node(tt, "INSTANCENAME", ["CLASSNAME"])
|
547
|
+
|
548
|
+
if ((k = WBEM.kids(tt)).length == 0)
|
549
|
+
# probably not ever going to see this, but it's valid
|
550
|
+
# according to the grammar
|
551
|
+
return CIMInstanceName.new(WBEM.attrs(tt)["CLASSNAME"], {})
|
552
|
+
end
|
553
|
+
classname = WBEM.attrs(tt)["CLASSNAME"]
|
554
|
+
w = WBEM.name(k[0])
|
555
|
+
if w == "KEYVALUE" or w == "VALUE.REFERENCE"
|
556
|
+
unless ((k = WBEM.kids(tt)).length == 1)
|
557
|
+
raise ParseError, "expected only one #{w} under #{WBEM.name(tt)}"
|
558
|
+
end
|
559
|
+
|
560
|
+
# FIXME: This is probably not the best representation of these forms...
|
561
|
+
return CIMInstanceName(classname, {nil => WBEM.parse_any(k[0])})
|
562
|
+
elsif w == "KEYBINDING"
|
563
|
+
kbs = {}
|
564
|
+
WBEM.list_of_various(tt, ["KEYBINDING"]).each { |kb| kbs.update(kb)}
|
565
|
+
return CIMInstanceName.new(classname, kbs)
|
566
|
+
else
|
567
|
+
raise ParseError, "unexpected node #{w} under #{WBEM.name(tt)}"
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def WBEM.parse_objectpath(tt)
|
572
|
+
# """
|
573
|
+
# <!ELEMENT OBJECTPATH (INSTANCEPATH | CLASSPATH)>
|
574
|
+
# """
|
575
|
+
|
576
|
+
WBEM.check_node(tt, "OBJECTPATH")
|
577
|
+
child = WBEM.one_child(tt, ["INSTANCEPATH", "CLASSPATH"])
|
578
|
+
return [WBEM.name(tt), WBEM.attrs(tt), child]
|
579
|
+
|
580
|
+
|
581
|
+
end
|
582
|
+
|
583
|
+
def WBEM.parse_keybinding(tt)
|
584
|
+
##<!ELEMENT KEYBINDING (KEYVALUE | VALUE.REFERENCE)>
|
585
|
+
##<!ATTLIST KEYBINDING
|
586
|
+
## %CIMName;>
|
587
|
+
|
588
|
+
# """Returns one-item dictionary from name to Python value."""
|
589
|
+
|
590
|
+
WBEM.check_node(tt, "KEYBINDING", ["NAME"])
|
591
|
+
child = WBEM.one_child(tt, ["KEYVALUE", "VALUE.REFERENCE"])
|
592
|
+
return {WBEM.attrs(tt)["NAME"] => child}
|
593
|
+
end
|
594
|
+
|
595
|
+
def WBEM.parse_keyvalue(tt)
|
596
|
+
##<!ELEMENT KEYVALUE (#PCDATA)>
|
597
|
+
##<!ATTLIST KEYVALUE
|
598
|
+
## VALUETYPE (string | boolean | numeric) "string">
|
599
|
+
|
600
|
+
# """Parse VALUETYPE into Python primitive value"""
|
601
|
+
|
602
|
+
WBEM.check_node(tt, "KEYVALUE", [], ["VALUETYPE"], [], true)
|
603
|
+
vt = WBEM.attrs(tt).fetch("VALUETYPE", "string")
|
604
|
+
p = WBEM.pcdata(tt)
|
605
|
+
if vt == "string"
|
606
|
+
return p
|
607
|
+
elsif vt == "boolean"
|
608
|
+
return WBEM.unpack_boolean(p)
|
609
|
+
elsif vt == "numeric"
|
610
|
+
return p.strip().to_i
|
611
|
+
else
|
612
|
+
raise ParseError, "invalid VALUETYPE #{vt} in #{WBEM.name(tt)}"
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
#
|
617
|
+
# Object definition elements
|
618
|
+
#
|
619
|
+
def WBEM.parse_class(tt)
|
620
|
+
## <!ELEMENT CLASS (QUALIFIER*, (PROPERTY | PROPERTY.ARRAY |
|
621
|
+
## PROPERTY.REFERENCE)*, METHOD*)>
|
622
|
+
## <!ATTLIST CLASS
|
623
|
+
## %CIMName;
|
624
|
+
## %SuperClass;>
|
625
|
+
|
626
|
+
# This doesn't check the ordering of elements, but it's not very important
|
627
|
+
WBEM.check_node(tt, "CLASS", ["NAME"], ["SUPERCLASS"],
|
628
|
+
["QUALIFIER", "PROPERTY", "PROPERTY.REFERENCE",
|
629
|
+
"PROPERTY.ARRAY", "METHOD"])
|
630
|
+
|
631
|
+
obj = CIMClass.new(WBEM.attrs(tt)["NAME"])
|
632
|
+
obj.superclass = WBEM.attrs(tt)["SUPERCLASS"]
|
633
|
+
|
634
|
+
obj.properties = WBEM.byname(WBEM.list_of_matching(tt, ["PROPERTY", "PROPERTY.REFERENCE",
|
635
|
+
"PROPERTY.ARRAY"]))
|
636
|
+
|
637
|
+
obj.qualifiers = WBEM.byname(WBEM.list_of_matching(tt, ["QUALIFIER"]))
|
638
|
+
obj.cim_methods = list_of_matching(tt, ["METHOD"])
|
639
|
+
|
640
|
+
return obj
|
641
|
+
end
|
642
|
+
|
643
|
+
def WBEM.parse_instance(tt)
|
644
|
+
# """Return a CIMInstance.
|
645
|
+
|
646
|
+
# The instance contains the properties, qualifiers and classname for
|
647
|
+
# the instance"""
|
648
|
+
|
649
|
+
##<!ELEMENT INSTANCE (QUALIFIER*, (PROPERTY | PROPERTY.ARRAY |
|
650
|
+
## PROPERTY.REFERENCE)*)>
|
651
|
+
##<!ATTLIST INSTANCE
|
652
|
+
## %ClassName;>
|
653
|
+
|
654
|
+
WBEM.check_node(tt, "INSTANCE", ["CLASSNAME"],
|
655
|
+
["QUALIFIER", "PROPERTY", "PROPERTY.ARRAY",
|
656
|
+
"PROPERTY.REFERENCE"])
|
657
|
+
|
658
|
+
## XXX: This does not enforce ordering constraint
|
659
|
+
|
660
|
+
## XXX: This does not enforce the constraint that there be only
|
661
|
+
## one PROPERTY or PROPERTY.ARRAY.
|
662
|
+
|
663
|
+
## TODO: Parse instance qualifiers
|
664
|
+
qualifiers = {}
|
665
|
+
props = WBEM.list_of_matching(tt, ["PROPERTY.REFERENCE", "PROPERTY", "PROPERTY.ARRAY"])
|
666
|
+
|
667
|
+
obj = CIMInstance.new(WBEM.attrs(tt)["CLASSNAME"])
|
668
|
+
obj.qualifiers = qualifiers
|
669
|
+
props.each { |p| obj[p.name] = p }
|
670
|
+
return obj
|
671
|
+
end
|
672
|
+
|
673
|
+
def WBEM.parse_qualifier(tt)
|
674
|
+
## <!ELEMENT QUALIFIER (VALUE | VALUE.ARRAY)>
|
675
|
+
## <!ATTLIST QUALIFIER %CIMName;
|
676
|
+
## %CIMType; #REQUIRED
|
677
|
+
## %Propagated;
|
678
|
+
## %QualifierFlavor;>
|
679
|
+
|
680
|
+
WBEM.check_node(tt, "QUALIFIER", ["NAME", "TYPE"],
|
681
|
+
["OVERRIDABLE", "TOSUBCLASS", "TOINSTANCE",
|
682
|
+
"TRANSLATABLE", "PROPAGATED"],
|
683
|
+
["VALUE", "VALUE.ARRAY"])
|
684
|
+
|
685
|
+
a = WBEM.attrs(tt)
|
686
|
+
|
687
|
+
q = CIMQualifier.new(a["NAME"], WBEM.unpack_value(tt))
|
688
|
+
|
689
|
+
## TODO: Lift this out?
|
690
|
+
["OVERRIDABLE", "TOSUBCLASS", "TOINSTANCE", "TRANSLATABLE", "PROPAGATED"].each do |i|
|
691
|
+
rv = a[i]
|
692
|
+
unless ["true", "false", nil].include?(rv)
|
693
|
+
raise ParseError, "invalid value #{rv} for #{i} on #{WBEM.name(tt)}"
|
694
|
+
end
|
695
|
+
if rv == "true"
|
696
|
+
rv = true
|
697
|
+
elsif rv == "false"
|
698
|
+
rv = false
|
699
|
+
end
|
700
|
+
q.method("#{i.downcase()}=").call(rv)
|
701
|
+
end
|
702
|
+
return q
|
703
|
+
end
|
704
|
+
|
705
|
+
def WBEM.parse_property(tt)
|
706
|
+
# """Parse PROPERTY into a CIMProperty object.
|
707
|
+
|
708
|
+
# VAL is just the pcdata of the enclosed VALUE node."""
|
709
|
+
|
710
|
+
## <!ELEMENT PROPERTY (QUALIFIER*, VALUE?)>
|
711
|
+
## <!ATTLIST PROPERTY %CIMName;
|
712
|
+
## %ClassOrigin;
|
713
|
+
## %Propagated;
|
714
|
+
## %CIMType; #REQUIRED>
|
715
|
+
|
716
|
+
## TODO: Parse this into NAME, VALUE, where the value contains
|
717
|
+
## magic fields for the qualifiers and the propagated flag.
|
718
|
+
|
719
|
+
WBEM.check_node(tt, "PROPERTY", ["TYPE", "NAME"],
|
720
|
+
["NAME", "CLASSORIGIN", "PROPAGATED"],
|
721
|
+
["QUALIFIER", "VALUE"])
|
722
|
+
|
723
|
+
quals = {}
|
724
|
+
WBEM.list_of_matching(tt, ["QUALIFIER"]).each { |q| quals[q.name] = q }
|
725
|
+
val = WBEM.unpack_value(tt)
|
726
|
+
a = WBEM.attrs(tt)
|
727
|
+
|
728
|
+
return CIMProperty.new(a["NAME"], val, a["TYPE"],
|
729
|
+
a["CLASSORIGIN"],
|
730
|
+
WBEM.unpack_boolean(a["PROPAGATED"]),
|
731
|
+
nil,
|
732
|
+
quals)
|
733
|
+
|
734
|
+
end
|
735
|
+
|
736
|
+
def WBEM.parse_property_array(tt)
|
737
|
+
# """
|
738
|
+
# <!ELEMENT PROPERTY.ARRAY (QUALIFIER*, VALUE.ARRAY?)>
|
739
|
+
# <!ATTLIST PROPERTY.ARRAY %CIMName;
|
740
|
+
# %CIMType; #REQUIRED
|
741
|
+
# %ArraySize;
|
742
|
+
# %ClassOrigin;
|
743
|
+
# %Propagated;>
|
744
|
+
# """
|
745
|
+
|
746
|
+
WBEM.check_node(tt, "PROPERTY.ARRAY", ["NAME", "TYPE"],
|
747
|
+
["REFERENCECLASS", "CLASSORIGIN", "PROPAGATED",
|
748
|
+
"ARRAYSIZE"],
|
749
|
+
["QUALIFIER", "VALUE.ARRAY"])
|
750
|
+
|
751
|
+
qualifiers = WBEM.byname(WBEM.list_of_matching(tt, ["QUALIFIER"]))
|
752
|
+
values = WBEM.unpack_value(tt)
|
753
|
+
a = WBEM.attrs(tt)
|
754
|
+
return CIMProperty.new(a["NAME"], values, a["TYPE"],
|
755
|
+
a["CLASSORIGIN"],
|
756
|
+
nil, true, qualifiers)
|
757
|
+
## TODO qualifiers, other attributes
|
758
|
+
end
|
759
|
+
|
760
|
+
def WBEM.parse_property_reference(tt)
|
761
|
+
# """
|
762
|
+
# <!ELEMENT PROPERTY.REFERENCE (QUALIFIER*, (VALUE.REFERENCE)?)>
|
763
|
+
# <!ATTLIST PROPERTY.REFERENCE
|
764
|
+
# %CIMName;
|
765
|
+
# %ReferenceClass;
|
766
|
+
# %ClassOrigin;
|
767
|
+
# %Propagated;>
|
768
|
+
# """
|
769
|
+
|
770
|
+
WBEM.check_node(tt, "PROPERTY.REFERENCE", ["NAME"],
|
771
|
+
["REFERENCECLASS", "CLASSORIGIN", "PROPAGATED"])
|
772
|
+
|
773
|
+
value = WBEM.list_of_matching(tt, ["VALUE.REFERENCE"])
|
774
|
+
|
775
|
+
if value.nil? or value.length == 0
|
776
|
+
value = nil
|
777
|
+
elsif value.length == 1
|
778
|
+
value = value[0]
|
779
|
+
else
|
780
|
+
raise ParseError, "Too many VALUE.REFERENCE elements."
|
781
|
+
end
|
782
|
+
|
783
|
+
attributes = WBEM.attrs(tt)
|
784
|
+
pref = CIMProperty.new(attributes["NAME"], value, "reference")
|
785
|
+
|
786
|
+
WBEM.list_of_matching(tt, ["QUALIFIER"]).each { |q| pref.qualifiers[q.name] = q}
|
787
|
+
if attributes.has_key?("REFERENCECLASS")
|
788
|
+
pref.reference_class = attributes["REFERENCECLASS"]
|
789
|
+
end
|
790
|
+
if attributes.has_key?("CLASSORIGIN")
|
791
|
+
pref.class_origin = attributes["CLASSORIGIN"]
|
792
|
+
end
|
793
|
+
if attributes.has_key?("PROPAGATED")
|
794
|
+
pref.propagated = attributes["PROPAGATED"]
|
795
|
+
end
|
796
|
+
return pref
|
797
|
+
end
|
798
|
+
|
799
|
+
def WBEM.parse_method(tt)
|
800
|
+
# """
|
801
|
+
# <!ELEMENT METHOD (QUALIFIER*, (PARAMETER | PARAMETER.REFERENCE |
|
802
|
+
# PARAMETER.ARRAY | PARAMETER.REFARRAY)*)>
|
803
|
+
# <!ATTLIST METHOD %CIMName;
|
804
|
+
# %CIMType; #IMPLIED
|
805
|
+
# %ClassOrigin;
|
806
|
+
# %Propagated;>
|
807
|
+
# """
|
808
|
+
|
809
|
+
WBEM.check_node(tt, "METHOD", ["NAME"],
|
810
|
+
["TYPE", "CLASSORIGIN", "PROPAGATED"],
|
811
|
+
["QUALIFIER", "PARAMETER", "PARAMETER.REFERENCE",
|
812
|
+
"PARAMETER.ARRAY", "PARAMETER.REFARRAY"])
|
813
|
+
|
814
|
+
qualifiers = WBEM.byname(WBEM.list_of_matching(tt, ["QUALIFIER"]))
|
815
|
+
|
816
|
+
parameters = WBEM.byname(WBEM.list_of_matching(tt, ["PARAMETER",
|
817
|
+
"PARAMETER.REFERENCE",
|
818
|
+
"PARAMETER.ARRAY",
|
819
|
+
"PARAMETER.REFARRAY",]))
|
820
|
+
a = WBEM.attrs(tt)
|
821
|
+
return CIMMethod.new(a["NAME"],
|
822
|
+
a["TYPE"],
|
823
|
+
parameters,
|
824
|
+
a["CLASSORIGIN"],
|
825
|
+
unpack_boolean(a["PROPAGATED"]),
|
826
|
+
qualifiers)
|
827
|
+
end
|
828
|
+
|
829
|
+
def WBEM.parse_parameter(tt)
|
830
|
+
# """
|
831
|
+
# <!ELEMENT PARAMETER (QUALIFIER*)>
|
832
|
+
# <!ATTLIST PARAMETER
|
833
|
+
# %CIMName;
|
834
|
+
# %CIMType; #REQUIRED>
|
835
|
+
# """
|
836
|
+
|
837
|
+
WBEM.check_node(tt, "PARAMETER", ["NAME", "TYPE"], [])
|
838
|
+
|
839
|
+
quals = {}
|
840
|
+
list_of_matching(tt, ['QUALIFIER']).each {|q| quals[q.name] = q }
|
841
|
+
|
842
|
+
a = WBEM.attrs(tt)
|
843
|
+
|
844
|
+
return CIMParameter.new(a["NAME"], a["TYPE"], nil, nil, nil, quals)
|
845
|
+
end
|
846
|
+
|
847
|
+
def WBEM.parse_parameter_reference(tt)
|
848
|
+
# """
|
849
|
+
# <!ELEMENT PARAMETER.REFERENCE (QUALIFIER*)>
|
850
|
+
# <!ATTLIST PARAMETER.REFERENCE
|
851
|
+
# %CIMName;
|
852
|
+
# %ReferenceClass;>
|
853
|
+
# """
|
854
|
+
|
855
|
+
WBEM.check_node(tt, "PARAMETER.REFERENCE", ["NAME"], ["REFERENCECLASS"])
|
856
|
+
|
857
|
+
quals = {}
|
858
|
+
list_of_matching(tt, ['QUALIFIER']).each {|q| quals[q.name] = q }
|
859
|
+
|
860
|
+
a = WBEM.attrs(tt)
|
861
|
+
|
862
|
+
return CIMParameter.new(a["NAME"], "reference", a['REFERENCECLASS'], nil, nil, quals)
|
863
|
+
end
|
864
|
+
|
865
|
+
def WBEM.parse_parameter_array(tt)
|
866
|
+
# """
|
867
|
+
# <!ELEMENT PARAMETER.ARRAY (QUALIFIER*)>
|
868
|
+
# <!ATTLIST PARAMETER.ARRAY
|
869
|
+
# %CIMName;
|
870
|
+
# %CIMType; #REQUIRED
|
871
|
+
# %ArraySize;>
|
872
|
+
# """
|
873
|
+
|
874
|
+
WBEM.check_node(tt, "PARAMETER.ARRAY", ["NAME", "TYPE"], ["ARRAYSIZE"])
|
875
|
+
|
876
|
+
quals = {}
|
877
|
+
list_of_matching(tt, ['QUALIFIER']).each {|q| quals[q.name] = q }
|
878
|
+
|
879
|
+
a = WBEM.attrs(tt)
|
880
|
+
array_size = a["ARRAYSIZE"]
|
881
|
+
array_size = array_size.to_i unless array_size.nil?
|
882
|
+
|
883
|
+
return CIMParameter.new(a["NAME"], a["TYPE"], nil, true, array_size, quals)
|
884
|
+
end
|
885
|
+
|
886
|
+
def WBEM.parse_parameter_refarray(tt)
|
887
|
+
# """
|
888
|
+
# <!ELEMENT PARAMETER.REFARRAY (QUALIFIER*)>
|
889
|
+
# <!ATTLIST PARAMETER.REFARRAY
|
890
|
+
# %CIMName;
|
891
|
+
# %ReferenceClass;
|
892
|
+
# %ArraySize;>
|
893
|
+
# """
|
894
|
+
|
895
|
+
WBEM.check_node(tt, "PARAMETER.REFARRAY", ["NAME"], ["REFERENCECLASS", "ARRAYSIZE"])
|
896
|
+
|
897
|
+
quals = {}
|
898
|
+
list_of_matching(tt, ['QUALIFIER']).each {|q| quals[q.name] = q }
|
899
|
+
|
900
|
+
a = WBEM.attrs(tt)
|
901
|
+
array_size = a["ARRAYSIZE"]
|
902
|
+
array_size = array_size.to_i unless array_size.nil?
|
903
|
+
|
904
|
+
return CIMParameter.new(a["NAME"], "reference", a["REFERENCECLASS"],
|
905
|
+
true, array_size, quals)
|
906
|
+
end
|
907
|
+
|
908
|
+
#
|
909
|
+
# Message elements
|
910
|
+
#
|
911
|
+
def WBEM.parse_message(tt)
|
912
|
+
# """
|
913
|
+
# <!ELEMENT MESSAGE (SIMPLEREQ | MULTIREQ | SIMPLERSP | MULTIRSP)>
|
914
|
+
# <!ATTLIST MESSAGE
|
915
|
+
# ID CDATA #REQUIRED
|
916
|
+
# PROTOCOLVERSION CDATA #REQUIRED>
|
917
|
+
# """
|
918
|
+
WBEM.check_node(tt, "MESSAGE", ["ID", "PROTOCOLVERSION"])
|
919
|
+
messages = WBEM.one_child(
|
920
|
+
tt, ["SIMPLEREQ", "MULTIREQ", "SIMPLERSP", "MULTIRSP"])
|
921
|
+
unless messages[0].is_a?(Array)
|
922
|
+
# make single and multi forms consistent
|
923
|
+
messages = [messages]
|
924
|
+
end
|
925
|
+
return [WBEM.name(tt), WBEM.attrs(tt), messages]
|
926
|
+
end
|
927
|
+
|
928
|
+
def WBEM.parse_multireq(tt)
|
929
|
+
raise ParseError, "MULTIREQ parser not implemented"
|
930
|
+
end
|
931
|
+
|
932
|
+
def WBEM.parse_multiexpreq(tt)
|
933
|
+
raise ParseError, "MULTIEXPREQ parser not implemented"
|
934
|
+
end
|
935
|
+
|
936
|
+
def WBEM.parse_simplereq(tt)
|
937
|
+
# """
|
938
|
+
# <!ELEMENT SIMPLEREQ (IMETHODCALL | METHODCALL)>
|
939
|
+
# """
|
940
|
+
|
941
|
+
WBEM.check_node(tt, "SIMPLEREQ")
|
942
|
+
child = WBEM.one_child(tt, ["IMETHODCALL", "METHODCALL"])
|
943
|
+
return [WBEM.kids(tt)[0][0], child]
|
944
|
+
end
|
945
|
+
|
946
|
+
def WBEM.parse_simpleexpreq(tt)
|
947
|
+
raise ParseError, "SIMPLEEXPREQ parser not implemented"
|
948
|
+
end
|
949
|
+
|
950
|
+
def WBEM.parse_imethodcall(tt)
|
951
|
+
# """
|
952
|
+
# <!ELEMENT IMETHODCALL (LOCALNAMESPACEPATH, IPARAMVALUE*)>
|
953
|
+
# <!ATTLIST IMETHODCALL
|
954
|
+
# %CIMName;>
|
955
|
+
# """
|
956
|
+
|
957
|
+
WBEM.check_node(tt, "IMETHODCALL", ["NAME"])
|
958
|
+
if ((k = WBEM.kids(tt)).length < 1)
|
959
|
+
raise ParseError, "Expecting LOCALNAMESPACEPATH, got nothing"
|
960
|
+
end
|
961
|
+
localnspath = WBEM.parse_localnamespacepath(k[0])
|
962
|
+
params = k[1..-1].collect { |x| WBEM.parse_iparamvalue(x) }
|
963
|
+
return [WBEM.name(tt), WBEM.attrs(tt), localnspath, params]
|
964
|
+
end
|
965
|
+
|
966
|
+
def WBEM.parse_methodcall(tt)
|
967
|
+
raise ParseError, "METHODCALL parser not implemented"
|
968
|
+
end
|
969
|
+
|
970
|
+
def WBEM.parse_expmethodcall(tt)
|
971
|
+
raise ParseError, "EXPMETHODCALL parser not implemented"
|
972
|
+
end
|
973
|
+
|
974
|
+
def WBEM.parse_paramvalue(tt)
|
975
|
+
## <!ELEMENT PARAMVALUE (VALUE | VALUE.REFERENCE | VALUE.ARRAY |
|
976
|
+
## VALUE.REFARRAY)?>
|
977
|
+
## <!ATTLIST PARAMVALUE
|
978
|
+
## %CIMName;
|
979
|
+
## %ParamType; #IMPLIED>
|
980
|
+
|
981
|
+
## Version 2.1.1 of the DTD lacks the %ParamType attribute but it
|
982
|
+
## is present in version 2.2. Make it optional to be backwards
|
983
|
+
## compatible.
|
984
|
+
|
985
|
+
WBEM.check_node(tt, "PARAMVALUE", ["NAME"], ["PARAMTYPE"])
|
986
|
+
|
987
|
+
child = WBEM.optional_child(tt,
|
988
|
+
["VALUE", "VALUE.REFERENCE", "VALUE.ARRAY",
|
989
|
+
"VALUE.REFARRAY",])
|
990
|
+
|
991
|
+
if WBEM.attrs(tt).has_key?("PARAMTYPE")
|
992
|
+
paramtype = WBEM.attrs(tt)["PARAMTYPE"]
|
993
|
+
else
|
994
|
+
paramtype = nil
|
995
|
+
end
|
996
|
+
return [WBEM.attrs(tt)["NAME"], paramtype, child]
|
997
|
+
end
|
998
|
+
|
999
|
+
def WBEM.parse_iparamvalue(tt)
|
1000
|
+
## <!ELEMENT IPARAMVALUE (VALUE | VALUE.ARRAY | VALUE.REFERENCE |
|
1001
|
+
## INSTANCENAME | CLASSNAME | QUALIFIER.DECLARATION |
|
1002
|
+
## CLASS | INSTANCE | VALUE.NAMEDINSTANCE)?>
|
1003
|
+
## <!ATTLIST IPARAMVALUE %CIMName;>
|
1004
|
+
|
1005
|
+
# """Returns NAME, VALUE pair."""
|
1006
|
+
|
1007
|
+
WBEM.check_node(tt, "IPARAMVALUE", ["NAME"], [])
|
1008
|
+
|
1009
|
+
child = WBEM.optional_child(tt,
|
1010
|
+
["VALUE", "VALUE.ARRAY", "VALUE.REFERENCE",
|
1011
|
+
"INSTANCENAME", "CLASSNAME",
|
1012
|
+
"QUALIFIER.DECLARATION", "CLASS", "INSTANCE",
|
1013
|
+
"VALUE.NAMEDINSTANCE"])
|
1014
|
+
## TODO: WBEM.unpack_value() where appropriate.
|
1015
|
+
return [WBEM.attrs(tt)["NAME"], child ]
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
def WBEM.parse_expparamvalue(tt)
|
1019
|
+
raise ParseError, "EXPPARAMVALUE parser not implemented"
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
def WBEM.parse_multirsp(tt)
|
1023
|
+
raise ParseError, "MULTIRSP parser not implemented"
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
def WBEM.parse_multiexprsp(tt)
|
1027
|
+
raise ParseError, "MULTIEXPRSP parser not implemented"
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
def WBEM.parse_simplersp(tt)
|
1031
|
+
## <!ELEMENT SIMPLERSP (METHODRESPONSE | IMETHODRESPONSE)>
|
1032
|
+
WBEM.check_node(tt, "SIMPLERSP", [], [])
|
1033
|
+
child = WBEM.one_child(tt, ["METHODRESPONSE", "IMETHODRESPONSE"])
|
1034
|
+
return [WBEM.name(tt), WBEM.attrs(tt), child]
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
def WBEM.parse_simpleexprsp(tt)
|
1038
|
+
raise ParseError, "SIMPLEEXPRSP parser not implemented"
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def WBEM.parse_methodresponse(tt)
|
1042
|
+
## <!ELEMENT METHODRESPONSE (ERROR | (RETURNVALUE?, PARAMVALUE*))>
|
1043
|
+
## <!ATTLIST METHODRESPONSE
|
1044
|
+
## %CIMName;>
|
1045
|
+
|
1046
|
+
WBEM.check_node(tt, "METHODRESPONSE", ["NAME"], [])
|
1047
|
+
|
1048
|
+
return [WBEM.name(tt), WBEM.attrs(tt), WBEM.list_of_various(tt, ["ERROR", "RETURNVALUE",
|
1049
|
+
"PARAMVALUE"])]
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
def WBEM.parse_expmethodresponse(tt)
|
1053
|
+
raise ParseError, "EXPMETHODRESPONSE parser not implemented"
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
def WBEM.parse_imethodresponse(tt)
|
1057
|
+
## <!ELEMENT IMETHODRESPONSE (ERROR | IRETURNVALUE?)>
|
1058
|
+
## <!ATTLIST IMETHODRESPONSE %CIMName;>
|
1059
|
+
WBEM.check_node(tt, "IMETHODRESPONSE", ["NAME"], [])
|
1060
|
+
return [WBEM.name(tt), WBEM.attrs(tt), WBEM.optional_child(tt, ["ERROR", "IRETURNVALUE"])]
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
def WBEM.parse_error(tt)
|
1064
|
+
# """
|
1065
|
+
# <!ELEMENT ERROR EMPTY>
|
1066
|
+
# <!ATTLIST ERROR
|
1067
|
+
# CODE CDATA #REQUIRED
|
1068
|
+
# DESCRIPTION CDATA #IMPLIED>
|
1069
|
+
# """
|
1070
|
+
|
1071
|
+
## TODO: Return a CIMError object, not a tuple
|
1072
|
+
WBEM.check_node(tt, "ERROR", ["CODE"], ["DESCRIPTION"])
|
1073
|
+
return [WBEM.name(tt), WBEM.attrs(tt), nil]
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
def WBEM.parse_returnvalue(tt)
|
1077
|
+
## <!ELEMENT RETURNVALUE (VALUE | VALUE.ARRAY | VALUE.REFERENCE |
|
1078
|
+
## VALUE.REFARRAY)>
|
1079
|
+
## <!ATTLIST RETURNVALUE %ParamType; #IMPLIED>
|
1080
|
+
|
1081
|
+
## Version 2.1.1 of the DTD lacks the %ParamType attribute but it
|
1082
|
+
## is present in version 2.2. Make it optional to be backwards
|
1083
|
+
## compatible.
|
1084
|
+
|
1085
|
+
WBEM.check_node(tt, "RETURNVALUE", [], ["PARAMTYPE"])
|
1086
|
+
return name[(tt), WBEM.attrs(tt), WBEM.one_child(tt, ["VALUE", "VALUE.ARRAY",
|
1087
|
+
"VALUE.REFERENCE",
|
1088
|
+
"VALUE.REFARRAY"])]
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
def WBEM.parse_ireturnvalue(tt)
|
1092
|
+
## <!ELEMENT IRETURNVALUE (CLASSNAME* | INSTANCENAME* | VALUE* |
|
1093
|
+
## VALUE.OBJECTWITHPATH* |
|
1094
|
+
## VALUE.OBJECTWITHLOCALPATH* | VALUE.OBJECT* |
|
1095
|
+
## OBJECTPATH* | QUALIFIER.DECLARATION* |
|
1096
|
+
## VALUE.ARRAY? | VALUE.REFERENCE? | CLASS* |
|
1097
|
+
## INSTANCE* | VALUE.NAMEDINSTANCE*)>
|
1098
|
+
|
1099
|
+
WBEM.check_node(tt, "IRETURNVALUE", [], [])
|
1100
|
+
|
1101
|
+
# XXX: doesn"t prohibit the case of only one VALUE.ARRAY or
|
1102
|
+
# VALUE.REFERENCE. But why is that required? Why can it return
|
1103
|
+
# multiple VALUEs but not multiple VALUE.REFERENCEs?
|
1104
|
+
|
1105
|
+
values = WBEM.list_of_same(tt, ["CLASSNAME", "INSTANCENAME",
|
1106
|
+
"VALUE", "VALUE.OBJECTWITHPATH", "VALUE.OBJECT",
|
1107
|
+
"OBJECTPATH", "QUALIFIER.DECLARATION",
|
1108
|
+
"VALUE.ARRAY", "VALUE.REFERENCE",
|
1109
|
+
"CLASS", "INSTANCE",
|
1110
|
+
"VALUE.NAMEDINSTANCE",])
|
1111
|
+
## TODO: Call WBEM.unpack_value if appropriate
|
1112
|
+
return [WBEM.name(tt), WBEM.attrs(tt), values]
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
#
|
1116
|
+
# Object naming and locating elements
|
1117
|
+
#
|
1118
|
+
|
1119
|
+
class MethodHelper
|
1120
|
+
|
1121
|
+
end
|
1122
|
+
def WBEM.parse_any(tt)
|
1123
|
+
# """Parse any fragment of XML."""
|
1124
|
+
h = MethodHelper.new
|
1125
|
+
nodename = WBEM.name(tt).downcase().tr(".", "_")
|
1126
|
+
fn_name = "parse_" + nodename
|
1127
|
+
method = self.method(fn_name)
|
1128
|
+
unless method
|
1129
|
+
raise ParseError, "no parser #{fn_name} for node type #{WBEM.name(tt)}"
|
1130
|
+
end
|
1131
|
+
return method.call(tt)
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
def WBEM.unpack_value(tt)
|
1135
|
+
# """Find VALUE or VALUE.ARRAY under TT and convert to a Python value.
|
1136
|
+
|
1137
|
+
# Looks at the TYPE of the node to work out how to decode it.
|
1138
|
+
# Handles nodes with no value (e.g. in CLASS.)
|
1139
|
+
# """
|
1140
|
+
val = WBEM.list_of_matching(tt, ["VALUE", "VALUE.ARRAY"])
|
1141
|
+
|
1142
|
+
## TODO: Handle VALUE.REFERENCE, VALUE.REFARRAY
|
1143
|
+
|
1144
|
+
valtype = WBEM.attrs(tt)["TYPE"]
|
1145
|
+
raw_val = WBEM.list_of_matching(tt, ["VALUE", "VALUE.ARRAY"])
|
1146
|
+
if raw_val.empty?
|
1147
|
+
return nil
|
1148
|
+
elsif raw_val.length > 1
|
1149
|
+
raise ParseError, "more than one VALUE or VALUE.ARRAY under #{WBEM.name(tt)}"
|
1150
|
+
end
|
1151
|
+
raw_val = raw_val[0]
|
1152
|
+
|
1153
|
+
if raw_val.is_a?(Array)
|
1154
|
+
return raw_val.collect { |x| tocimobj(valtype, x) }
|
1155
|
+
elif raw_val.empty?
|
1156
|
+
return nil
|
1157
|
+
else
|
1158
|
+
return WBEM.tocimobj(valtype, raw_val)
|
1159
|
+
end
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
def WBEM.unpack_boolean(p)
|
1163
|
+
# """Unpack a boolean, represented as "TRUE" or "FALSE" in CIM."""
|
1164
|
+
if p.nil?
|
1165
|
+
return nil
|
1166
|
+
end
|
1167
|
+
## CIM-XML says "These values MUST be treated as case-insensitive"
|
1168
|
+
## (even though the XML definition requires them to be lowercase.)
|
1169
|
+
|
1170
|
+
p = p.strip().downcase() # ignore space
|
1171
|
+
if p == "true"
|
1172
|
+
return true
|
1173
|
+
elsif p == "false"
|
1174
|
+
return false
|
1175
|
+
elsif p == ""
|
1176
|
+
return nil
|
1177
|
+
else
|
1178
|
+
raise ParseError, "invalid boolean #{p}"
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
end
|