1 karl 1.54 //%2006////////////////////////////////////////////////////////////////////////
|
2 chip 1.1 //
|
3 karl 1.43 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.30 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.43 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.45 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.54 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 chip 1.1 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 karl 1.54 //
|
21 chip 1.1 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
|
32 kumpf 1.2 // Author: Mike Brasher (mbrasher@bmc.com)
|
33 chip 1.1 //
|
34 kumpf 1.2 // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
|
35 kumpf 1.9 // Carol Ann Krug Graves, Hewlett-Packard Company
36 // (carolann_graves@hp.com)
|
37 dave.sudlik 1.44 // Dave Sudlik, IBM (dsudlik@us.ibm.com)
|
38 vijay.eli 1.51 // Vijay Eli, IBM (vijayeli@in.ibm.com), bug#2556.
|
39 chip 1.1 //
40 //%/////////////////////////////////////////////////////////////////////////////
41
|
42 kumpf 1.2 #include <Pegasus/Common/Config.h>
43 #include <cstring>
|
44 kumpf 1.22 #include <iostream>
|
45 kumpf 1.2 #include "HashTable.h"
46 #include "CIMObjectPath.h"
47 #include "Indentor.h"
48 #include "CIMName.h"
49 #include "XmlWriter.h"
50 #include "XmlReader.h"
|
51 kumpf 1.11 #include "ArrayInternal.h"
|
52 chip 1.1
53 PEGASUS_NAMESPACE_BEGIN
|
54 kumpf 1.2
|
55 kumpf 1.16 #define PEGASUS_ARRAY_T CIMKeyBinding
|
56 kumpf 1.2 # include "ArrayImpl.h"
57 #undef PEGASUS_ARRAY_T
58
59 #define PEGASUS_ARRAY_T CIMObjectPath
60 # include "ArrayImpl.h"
61 #undef PEGASUS_ARRAY_T
62
63 // ATTN: KS May 2002 P0 Add resolve method to CIMObjectPath.
64 // Add a resolve method to this class to verify that the
65 // reference is correct (that the class name corresponds to a real
66 // class and that the property names are really keys and that all keys
67 // of the class or used. Also be sure that there is a valid conversion
68 // between the string value and the value of that property).
69 //
70 // ATTN: also check to see that the reference refers to a class that is the
71 // same or derived from the _className member.
72
73 ////////////////////////////////////////////////////////////////////////////////
74 //
75 // Local routines:
76 //
77 kumpf 1.2 ////////////////////////////////////////////////////////////////////////////////
78
79 static String _escapeSpecialCharacters(const String& str)
80 {
81 String result;
82
83 for (Uint32 i = 0, n = str.size(); i < n; i++)
84 {
85 switch (str[i])
86 {
|
87 kumpf 1.28 case '\\':
88 result.append("\\\\");
|
89 kumpf 1.2 break;
90
91 case '"':
|
92 kumpf 1.13 result.append("\\\"");
|
93 kumpf 1.2 break;
94
95 default:
|
96 kumpf 1.13 result.append(str[i]);
|
97 kumpf 1.2 }
98 }
99
100 return result;
101 }
102
|
103 kumpf 1.16 static void _BubbleSort(Array<CIMKeyBinding>& x)
|
104 kumpf 1.2 {
105 Uint32 n = x.size();
106
|
107 kumpf 1.24 //
|
108 chip 1.47 // If the key is a reference, the keys in the reference must also be
|
109 kumpf 1.24 // sorted
110 //
111 for (Uint32 k = 0; k < n ; k++)
112 if (x[k].getType () == CIMKeyBinding::REFERENCE)
113 {
114 CIMObjectPath tmp (x[k].getValue ());
115 Array <CIMKeyBinding> keyBindings = tmp.getKeyBindings ();
116 _BubbleSort (keyBindings);
117 tmp.setKeyBindings (keyBindings);
118 x[k].setValue (tmp.toString ());
119 }
120
|
121 kumpf 1.2 if (n < 2)
122 return;
123
124 for (Uint32 i = 0; i < n - 1; i++)
125 {
126 for (Uint32 j = 0; j < n - 1; j++)
127 {
|
128 chip 1.47 if (String::compareNoCase(x[j].getName().getString(),
|
129 kumpf 1.17 x[j+1].getName().getString()) > 0)
|
130 kumpf 1.2 {
|
131 kumpf 1.16 CIMKeyBinding t = x[j];
|
132 kumpf 1.2 x[j] = x[j+1];
133 x[j+1] = t;
134 }
135 }
136 }
137 }
138
139 ////////////////////////////////////////////////////////////////////////////////
140 //
|
141 kumpf 1.16 // CIMKeyBinding
|
142 kumpf 1.2 //
143 ////////////////////////////////////////////////////////////////////////////////
144
|
145 kumpf 1.16 class CIMKeyBindingRep
|
146 kumpf 1.2 {
147 public:
|
148 kumpf 1.16 CIMKeyBindingRep()
|
149 kumpf 1.2 {
150 }
151
|
152 kumpf 1.16 CIMKeyBindingRep(const CIMKeyBindingRep& x)
|
153 kumpf 1.2 : _name(x._name), _value(x._value), _type(x._type)
154 {
155 }
156
|
157 kumpf 1.16 CIMKeyBindingRep(
|
158 kumpf 1.7 const CIMName& name,
|
159 kumpf 1.2 const String& value,
|
160 kumpf 1.16 CIMKeyBinding::Type type)
|
161 kumpf 1.2 : _name(name), _value(value), _type(type)
162 {
163 }
164
|
165 kumpf 1.16 ~CIMKeyBindingRep()
|
166 kumpf 1.2 {
167 }
168
|
169 kumpf 1.16 CIMKeyBindingRep& operator=(const CIMKeyBindingRep& x)
|
170 kumpf 1.2 {
171 if (&x != this)
172 {
173 _name = x._name;
174 _value = x._value;
175 _type = x._type;
176 }
177 return *this;
178 }
179
|
180 kumpf 1.7 CIMName _name;
|
181 kumpf 1.2 String _value;
|
182 kumpf 1.16 CIMKeyBinding::Type _type;
|
183 kumpf 1.2 };
184
185
|
186 a.arora 1.39 CIMKeyBinding::CIMKeyBinding()
|
187 kumpf 1.2 {
|
188 a.arora 1.39 _rep = new CIMKeyBindingRep();
|
189 kumpf 1.2 }
190
|
191 a.arora 1.39 CIMKeyBinding::CIMKeyBinding(const CIMKeyBinding& x)
|
192 kumpf 1.2 {
|
193 a.arora 1.39 _rep = new CIMKeyBindingRep(*x._rep);
|
194 kumpf 1.2 }
195
|
196 a.arora 1.39 CIMKeyBinding::CIMKeyBinding(const CIMName& name, const String& value, Type type)
|
197 kumpf 1.2 {
|
198 a.arora 1.39 _rep = new CIMKeyBindingRep(name, value, type);
|
199 kumpf 1.2 }
200
|
201 kumpf 1.18 CIMKeyBinding::CIMKeyBinding(const CIMName& name, const CIMValue& value)
202 {
|
203 kumpf 1.21 if (value.isArray())
|
204 kumpf 1.20 {
205 throw TypeMismatchException();
206 }
207
|
208 kumpf 1.18 String kbValue = value.toString();
209 Type kbType;
210
211 switch (value.getType())
212 {
213 case CIMTYPE_BOOLEAN:
214 kbType = BOOLEAN;
215 break;
216 case CIMTYPE_CHAR16:
217 case CIMTYPE_STRING:
218 case CIMTYPE_DATETIME:
219 kbType = STRING;
220 break;
221 case CIMTYPE_REFERENCE:
222 kbType = REFERENCE;
223 break;
|
224 dave.sudlik 1.46 // case CIMTYPE_REAL32:
225 // case CIMTYPE_REAL64:
|
226 dave.sudlik 1.44 case CIMTYPE_OBJECT:
|
227 a.dunfey 1.55 #ifdef PEGASUS_EMBEDDED_INSTANCE_SUPPORT
228 case CIMTYPE_INSTANCE:
229 #endif // PEGASUS_EMBEDDED_INSTANCE_SUPPORT
|
230 dave.sudlik 1.46 // From PEP 194: EmbeddedObjects cannot be keys.
|
231 dave.sudlik 1.44 throw TypeMismatchException();
232 break;
|
233 kumpf 1.18 default:
234 kbType = NUMERIC;
235 break;
236 }
237
|
238 a.arora 1.39 _rep = new CIMKeyBindingRep(name, kbValue, kbType);
|
239 kumpf 1.18 }
240
|
241 kumpf 1.16 CIMKeyBinding::~CIMKeyBinding()
|
242 kumpf 1.2 {
|
243 a.arora 1.39 delete _rep;
|
244 kumpf 1.2 }
245
|
246 kumpf 1.16 CIMKeyBinding& CIMKeyBinding::operator=(const CIMKeyBinding& x)
|
247 kumpf 1.2 {
|
248 a.arora 1.39 *_rep = *x._rep;
|
249 kumpf 1.2 return *this;
250 }
251
|
252 kumpf 1.16 const CIMName& CIMKeyBinding::getName() const
|
253 kumpf 1.2 {
254 return _rep->_name;
255 }
256
|
257 kumpf 1.16 void CIMKeyBinding::setName(const CIMName& name)
|
258 kumpf 1.2 {
259 _rep->_name = name;
260 }
261
|
262 kumpf 1.16 const String& CIMKeyBinding::getValue() const
|
263 kumpf 1.2 {
264 return _rep->_value;
265 }
266
|
267 kumpf 1.16 void CIMKeyBinding::setValue(const String& value)
|
268 kumpf 1.2 {
269 _rep->_value = value;
270 }
271
|
272 kumpf 1.16 CIMKeyBinding::Type CIMKeyBinding::getType() const
|
273 kumpf 1.2 {
274 return _rep->_type;
275 }
276
|
277 kumpf 1.16 void CIMKeyBinding::setType(CIMKeyBinding::Type type)
|
278 kumpf 1.2 {
279 _rep->_type = type;
280 }
|
281 kumpf 1.18
282 Boolean CIMKeyBinding::equal(CIMValue value)
283 {
|
284 kumpf 1.21 if (value.isArray())
|
285 kumpf 1.20 {
286 return false;
287 }
288
|
289 kumpf 1.18 CIMValue kbValue;
290
291 try
292 {
293 switch (value.getType())
294 {
295 case CIMTYPE_CHAR16:
|
296 kumpf 1.20 if (getType() != STRING) return false;
|
297 kumpf 1.18 kbValue.set(getValue()[0]);
298 break;
299 case CIMTYPE_DATETIME:
|
300 kumpf 1.20 if (getType() != STRING) return false;
|
301 kumpf 1.18 kbValue.set(CIMDateTime(getValue()));
302 break;
303 case CIMTYPE_STRING:
|
304 kumpf 1.20 if (getType() != STRING) return false;
|
305 kumpf 1.18 kbValue.set(getValue());
306 break;
307 case CIMTYPE_REFERENCE:
|
308 kumpf 1.20 if (getType() != REFERENCE) return false;
|
309 kumpf 1.18 kbValue.set(CIMObjectPath(getValue()));
310 break;
|
311 kumpf 1.20 case CIMTYPE_BOOLEAN:
312 if (getType() != BOOLEAN) return false;
313 kbValue = XmlReader::stringToValue(0, getValue().getCString(),
314 value.getType());
315 break;
|
316 dave.sudlik 1.46 // case CIMTYPE_REAL32:
317 // case CIMTYPE_REAL64:
|
318 dave.sudlik 1.44 case CIMTYPE_OBJECT:
|
319 a.dunfey 1.55 #ifdef PEGASUS_EMBEDDED_INSTANCE_SUPPORT
320 case CIMTYPE_INSTANCE:
321 #endif // PEGASUS_EMBEDDED_INSTANCE_SUPPORT
|
322 dave.sudlik 1.46 // From PEP 194: EmbeddedObjects cannot be keys.
|
323 dave.sudlik 1.44 return false;
324 break;
|
325 kumpf 1.20 default: // Numerics
326 if (getType() != NUMERIC) return false;
|
327 kumpf 1.18 kbValue = XmlReader::stringToValue(0, getValue().getCString(),
328 value.getType());
329 break;
330 }
331 }
|
332 kumpf 1.19 catch (Exception&)
|
333 kumpf 1.18 {
334 return false;
335 }
336
337 return value.equal(kbValue);
338 }
|
339 kumpf 1.2
|
340 kumpf 1.16 Boolean operator==(const CIMKeyBinding& x, const CIMKeyBinding& y)
|
341 kumpf 1.2 {
|
342 kumpf 1.33 // Check that the names and types match
343 if (!(x.getName().equal(y.getName())) ||
344 !(x.getType() == y.getType()))
345 {
346 return false;
347 }
348
349 switch (x.getType())
350 {
351 case CIMKeyBinding::REFERENCE:
352 try
353 {
354 // References should be compared as CIMObjectPaths
355 return (CIMObjectPath(x.getValue()) == CIMObjectPath(y.getValue()));
356 }
357 catch (Exception&)
358 {
359 // If CIMObjectPath parsing fails, just compare strings
360 return (String::equal(x.getValue(), y.getValue()));
361 }
362 break;
363 kumpf 1.33 case CIMKeyBinding::BOOLEAN:
364 // Case-insensitive comparison is sufficient for booleans
365 return (String::equalNoCase(x.getValue(), y.getValue()));
366 break;
367 case CIMKeyBinding::NUMERIC:
368 // Note: This comparison assumes XML syntax for integers
369 // First try comparing as unsigned integers
370 {
371 Uint64 xValue;
372 Uint64 yValue;
373 if (XmlReader::stringToUnsignedInteger(
374 x.getValue().getCString(), xValue) &&
375 XmlReader::stringToUnsignedInteger(
376 y.getValue().getCString(), yValue))
377 {
378 return (xValue == yValue);
379 }
380 }
381 // Next try comparing as signed integers
382 {
383 Sint64 xValue;
384 kumpf 1.33 Sint64 yValue;
385 if (XmlReader::stringToSignedInteger(
386 x.getValue().getCString(), xValue) &&
387 XmlReader::stringToSignedInteger(
388 y.getValue().getCString(), yValue))
389 {
390 return (xValue == yValue);
391 }
392 }
393 // Note: Keys may not be real values, so don't try comparing as reals
394 // We couldn't parse the numbers, so just compare the strings
395 return (String::equal(x.getValue(), y.getValue()));
396 break;
397 default: // CIMKeyBinding::STRING
398 return (String::equal(x.getValue(), y.getValue()));
399 break;
400 }
401
402 PEGASUS_UNREACHABLE(return false;)
|
403 kumpf 1.2 }
404
405
406 ////////////////////////////////////////////////////////////////////////////////
407 //
408 // CIMObjectPath
409 //
410 ////////////////////////////////////////////////////////////////////////////////
411
412 class CIMObjectPathRep
413 {
414 public:
415 CIMObjectPathRep()
416 {
417 }
418
419 CIMObjectPathRep(const CIMObjectPathRep& x)
420 : _host(x._host), _nameSpace(x._nameSpace),
421 _className(x._className), _keyBindings(x._keyBindings)
422 {
423 }
424 kumpf 1.2
425 CIMObjectPathRep(
426 const String& host,
|
427 kumpf 1.7 const CIMNamespaceName& nameSpace,
428 const CIMName& className,
|
429 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
430 kumpf 1.2 : _host(host), _nameSpace(nameSpace),
431 _className(className), _keyBindings(keyBindings)
432 {
433 }
434
435 ~CIMObjectPathRep()
436 {
437 }
438
439 CIMObjectPathRep& operator=(const CIMObjectPathRep& x)
440 {
441 if (&x != this)
442 {
443 _host = x._host;
444 _nameSpace = x._nameSpace;
445 _className = x._className;
446 _keyBindings = x._keyBindings;
447 }
448 return *this;
449 }
450
|
451 kumpf 1.34 static Boolean isValidHostname(const String& hostname)
452 {
453 //------------------------------------------------------------------
454 // Validate the hostname. The hostname value may or may not be a
455 // fully-qualified domain name (e.g., xyz.company.com) or may be an
456 // IP address. A port number may follow the hostname.
457 // Hostnames must match one of the following regular expressions:
|
458 dave.sudlik 1.42 // ^([A-Za-z0-9][A-Za-z0-9-]*)(\.[A-Za-z][A-Za-z0-9-]*)*(:[0-9]*)?$
|
459 kumpf 1.34 // ^([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)(:[0-9]*)?$
|
460 dave.sudlik 1.42 // Note for Bug#1462. Be careful here, from RFC 1123:
|
461 chip 1.47 // - The syntax of a legal Internet host name was specified in
462 // RFC-952 [DNS:4]. One aspect of host name syntax is hereby
463 // changed: the restriction on the first character is relaxed to
464 // allow either a letter or a digit.
|
465 dave.sudlik 1.42 // - If a dotted-decimal number can be entered without identifying
466 // delimiters, then a full syntactic check must be made, because
467 // a segment of a host domain name is now allowed to begin with a
468 // digit and could legally be entirely numeric (see Section 6.1.2.4).
469 // However, a valid host name can never have the dotted-decimal form
470 // #.#.#.#, since at least the highest-level component label will be
|
471 chip 1.47 // alphabetic.
|
472 dave.sudlik 1.42 // The algorithm below has been updated accordingly.
|
473 kumpf 1.34 //------------------------------------------------------------------
474
475 Uint32 i = 0;
476
|
477 dave.sudlik 1.42 Boolean isValid = false;
478
|
479 kumpf 1.52 if (isascii(hostname[0]) && isdigit(hostname[0]))
|
480 kumpf 1.34 {
|
481 dave.sudlik 1.42 //--------------------------------------------------------------
|
482 chip 1.47 // Attempt to validate an IP address, but keep in mind that it
|
483 dave.sudlik 1.42 // might be a host name, since the leading character can now be
484 // a digit.
485 //--------------------------------------------------------------
486 isValid = true;
|
487 kumpf 1.34
488 for (Uint32 octet=1; octet<=4; octet++)
489 {
490 Uint32 octetValue = 0;
491
|
492 dave.sudlik 1.42 //----------------------------------------------------------
493 // If a non-digit is encountered in the input parameter,
494 // then break from here and attempt to validate as host name.
495 //----------------------------------------------------------
|
496 kumpf 1.52 if (!(isascii(hostname[i]) && isdigit(hostname[i])))
|
497 kumpf 1.34 {
|
498 dave.sudlik 1.42 isValid = false;
499 break;
|
500 kumpf 1.34 }
501
|
502 kumpf 1.52 // skip over digits
503 while (isascii(hostname[i]) && isdigit(hostname[i]))
|
504 kumpf 1.34 {
505 octetValue = octetValue*10 + (hostname[i] - '0');
506 i++;
507 }
508
509 if (octetValue > 255)
510 {
|
511 dave.sudlik 1.42 isValid = false;
512 break;
|
513 kumpf 1.34 }
514
|
515 dave.sudlik 1.42 // Check for invalid character in IP address
|
516 kumpf 1.34 if ((octet != 4) && (hostname[i++] != '.'))
517 {
|
518 dave.sudlik 1.42 isValid = false;
519 break;
520 }
521
522 // Check for the case where it's a valid host name that happens
523 // to have 4 (or more) leading all-numeric host segments.
524 if ((octet == 4) && (hostname[i] != ':') && hostname[i] != char(0))
525 {
526 isValid = false;
527 break;
|
528 kumpf 1.34 }
529 }
530 }
|
531 dave.sudlik 1.42 if (!isValid) // if it is not a valid IP address
|
532 kumpf 1.34 {
|
533 dave.sudlik 1.42 i = 0; // reset index for host name check
534
535 // Validate a host name
536 isValid = true;
|
537 kumpf 1.34
538 Boolean expectHostSegment = true;
|
539 dave.sudlik 1.42 Boolean hostSegmentIsNumeric;
|
540 kumpf 1.34
541 while (expectHostSegment == true)
542 {
543 expectHostSegment = false;
|
544 dave.sudlik 1.42 hostSegmentIsNumeric = true; // assume all-numeric host segment
|
545 kumpf 1.34
|
546 kumpf 1.53 if (!(isascii(hostname[i]) &&
547 (isalnum(hostname[i]) || (hostname[i] == '_'))))
|
548 kumpf 1.34 {
549 return false;
550 }
551
|
552 kumpf 1.52 while (isascii(hostname[i]) &&
553 (isalnum(hostname[i]) || (hostname[i] == '-') ||
554 (hostname[i] == '_')))
|
555 kumpf 1.34 {
|
556 dave.sudlik 1.42 // If a non-digit is encountered, set "all-numeric"
557 // flag to false
|
558 vijay.eli 1.51 if (isalpha(hostname[i]) || (hostname[i] == '-') ||
559 (hostname[i] == '_')) {
|
560 dave.sudlik 1.42 hostSegmentIsNumeric = false;
561 }
|
562 kumpf 1.34 i++;
563 }
564
565 if (hostname[i] == '.')
566 {
567 i++;
568 expectHostSegment = true;
569 }
570 }
|
571 dave.sudlik 1.42 // If the last Host Segment is all numeric, then return false.
572 // RFC 1123 says "highest-level component label will be alphabetic".
573 if (hostSegmentIsNumeric) {
574 return false;
575 }
576 }
577
578 if (!isValid) // if not a valid IP address or host name
579 {
580 return false;
|
581 kumpf 1.34 }
582
583 // Check for a port number:
584
585 if (hostname[i] == ':')
586 {
|
587 kumpf 1.52 i++;
588 if (!(isascii(hostname[i]) && isdigit(hostname[i])))
|
589 kumpf 1.34 {
590 return false;
591 }
|
592 kumpf 1.52 i++;
|
593 chip 1.47
|
594 kumpf 1.52 while (isascii(hostname[i]) && isdigit(hostname[i]))
595 {
596 i++;
597 }
|
598 kumpf 1.34 }
599
600 return (hostname[i] == char(0));
601 }
602
|
603 kumpf 1.2 //
604 // Contains port as well (e.g., myhost:1234).
605 //
606 String _host;
607
|
608 kumpf 1.7 CIMNamespaceName _nameSpace;
609 CIMName _className;
|
610 kumpf 1.16 Array<CIMKeyBinding> _keyBindings;
|
611 kumpf 1.2 };
612
613
|
614 a.arora 1.39 CIMObjectPath::CIMObjectPath()
|
615 kumpf 1.2 {
|
616 a.arora 1.39 _rep = new CIMObjectPathRep();
|
617 kumpf 1.2 }
618
|
619 a.arora 1.39 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x)
|
620 kumpf 1.2 {
|
621 a.arora 1.39 _rep = new CIMObjectPathRep(*x._rep);
|
622 kumpf 1.2 }
623
624 CIMObjectPath::CIMObjectPath(const String& objectName)
625 {
626 // Test the objectName out to see if we get an exception
627 CIMObjectPath tmpRef;
628 tmpRef.set(objectName);
629
|
630 a.arora 1.39 _rep = new CIMObjectPathRep(*tmpRef._rep);
|
631 kumpf 1.2 }
632
633 CIMObjectPath::CIMObjectPath(
634 const String& host,
|
635 kumpf 1.7 const CIMNamespaceName& nameSpace,
636 const CIMName& className,
|
637 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
638 kumpf 1.2 {
639 // Test the objectName out to see if we get an exception
640 CIMObjectPath tmpRef;
641 tmpRef.set(host, nameSpace, className, keyBindings);
642
|
643 a.arora 1.39 _rep = new CIMObjectPathRep(*tmpRef._rep);
|
644 kumpf 1.2 }
645
646 CIMObjectPath::~CIMObjectPath()
647 {
|
648 a.arora 1.39 delete _rep;
|
649 kumpf 1.2 }
650
651 CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
652 {
|
653 a.arora 1.39 *_rep = *x._rep;
|
654 kumpf 1.2 return *this;
655 }
656
657 void CIMObjectPath::clear()
658 {
659 _rep->_host.clear();
660 _rep->_nameSpace.clear();
661 _rep->_className.clear();
662 _rep->_keyBindings.clear();
663 }
664
665 void CIMObjectPath::set(
666 const String& host,
|
667 kumpf 1.7 const CIMNamespaceName& nameSpace,
668 const CIMName& className,
|
669 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
670 kumpf 1.2 {
671 setHost(host);
672 setNameSpace(nameSpace);
673 setClassName(className);
674 setKeyBindings(keyBindings);
675 }
676
|
677 kumpf 1.22 Boolean _parseHostElement(
|
678 kumpf 1.2 const String& objectName,
679 char*& p,
|
680 kumpf 1.9 String& host)
|
681 kumpf 1.2 {
682 // See if there is a host name (true if it begins with "//"):
|
683 kumpf 1.32 // Host is of the form <hostname>:<port> and begins with "//"
|
684 kumpf 1.2 // and ends with "/":
685
686 if (p[0] != '/' || p[1] != '/')
687 {
688 return false;
689 }
690
691 p += 2;
692
|
693 kumpf 1.34 char* slash = strchr(p, '/');
694 if (!slash)
|
695 chuck 1.23 {
|
696 kumpf 1.34 throw MalformedObjectNameException(objectName);
|
697 kumpf 1.2 }
698
|
699 kumpf 1.34 String hostname = String(p, (Uint32)(slash - p));
700 if (!CIMObjectPathRep::isValidHostname(hostname))
|
701 kumpf 1.2 {
|
702 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
703 kumpf 1.2 }
|
704 kumpf 1.34 host = hostname;
|
705 kumpf 1.2
|
706 kumpf 1.31 // Do not step past the '/'; it will be consumed by the namespace parser
|
707 kumpf 1.34 p = slash;
|
708 kumpf 1.2
709 return true;
710 }
711
|
712 kumpf 1.22 Boolean _parseNamespaceElement(
|
713 kumpf 1.2 const String& objectName,
714 char*& p,
|
715 kumpf 1.7 CIMNamespaceName& nameSpace)
|
716 kumpf 1.2 {
717 // If we don't find a valid namespace name followed by a ':', we
718 // assume we're not looking at a namespace name.
719
|
720 kumpf 1.7 char* colon = strchr(p, ':');
721 if (!colon)
722 {
723 return false;
724 }
725
|
726 chip 1.47 // A ':' as part of a keybinding value should not be interpreted as
|
727 kumpf 1.25 // a namespace delimiter. Since keybinding pairs follow the first '.'
728 // in the object path string, the ':' delimiter only counts if it
729 // appears before the '.'.
730
731 char* dot = strchr(p, '.');
732 if (dot && (dot < colon))
733 {
734 return false;
735 }
736
|
737 kumpf 1.2 //----------------------------------------------------------------------
738 // Validate the namespace path. Namespaces must match the following
739 // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
740 //----------------------------------------------------------------------
741
|
742 david 1.27 String namespaceName = String(p, (Uint32)(colon - p));
|
743 kumpf 1.7 if (!CIMNamespaceName::legal(namespaceName))
|
744 kumpf 1.2 {
|
745 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
746 kumpf 1.2 }
|
747 kumpf 1.7 nameSpace = namespaceName;
|
748 kumpf 1.2
|
749 kumpf 1.7 p = colon+1;
|
750 kumpf 1.2 return true;
751 }
752
753 /**
|
754 kumpf 1.29 ATTN-RK: The DMTF specification for the string form of an
755 object path makes it impossible for a parser to distinguish
756 between a key values of String type and Reference type.
757
758 Given the ambiguity, this implementation takes a guess at the
759 type of a quoted key value. If the value can be parsed into
760 a CIMObjectPath with at least one key binding, the type is
761 set to REFERENCE. Otherwise, the type is set to STRING.
762 Note: This algorithm appears to be in line with what the Sun
763 WBEM Services implementation does.
764
765 To be totally correct, it would be necessary to retrieve the
766 class definition and look up the types of the key properties
767 to determine how to interpret the key values. This is clearly
768 too inefficient for internal transformations between
769 CIMObjectPaths and String values.
|
770 kumpf 1.2 */
|
771 kumpf 1.22 void _parseKeyBindingPairs(
|
772 kumpf 1.2 const String& objectName,
773 char*& p,
|
774 chip 1.47 Array<CIMKeyBinding>& keyBindings)
|
775 kumpf 1.2 {
776 // Get the key-value pairs:
777
778 while (*p)
779 {
780 // Get key part:
781
|
782 kumpf 1.5 char* equalsign = strchr(p, '=');
783 if (!equalsign)
|
784 kumpf 1.2 {
|
785 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
786 kumpf 1.2 }
787
|
788 kumpf 1.5 *equalsign = 0;
|
789 kumpf 1.2
|
790 kumpf 1.17 if (!CIMName::legal(p))
|
791 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
792 kumpf 1.2
|
793 kumpf 1.17 CIMName keyName (p);
794
|
795 kumpf 1.2 // Get the value part:
796
797 String valueString;
|
798 kumpf 1.5 p = equalsign + 1;
|
799 kumpf 1.16 CIMKeyBinding::Type type;
|
800 kumpf 1.2
|
801 kumpf 1.29 if (*p == '"')
|
802 kumpf 1.2 {
|
803 kumpf 1.29 // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
804
|
805 kumpf 1.2 p++;
806
807 while (*p && *p != '"')
808 {
809 if (*p == '\\')
|
810 kumpf 1.28 {
|
811 kumpf 1.2 *p++;
812
|
813 kumpf 1.28 if ((*p != '\\') && (*p != '"'))
814 {
815 throw MalformedObjectNameException(objectName);
816 }
817 }
818
|
819 kumpf 1.2 valueString.append(*p++);
820 }
821
822 if (*p++ != '"')
|
823 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
824 kumpf 1.2
|
825 kumpf 1.29 /*
826 Guess at the type of this quoted key value. If the value
827 can be parsed into a CIMObjectPath with at least one key
828 binding, the type is assumed to be a REFERENCE. Otherwise,
829 the type is set to STRING. (See method header for details.)
830 */
|
831 kumpf 1.16 type = CIMKeyBinding::STRING;
|
832 kumpf 1.2
|
833 kumpf 1.29 try
|
834 kumpf 1.2 {
|
835 kumpf 1.29 CIMObjectPath testForPath(valueString);
836 if (testForPath.getKeyBindings().size() > 0)
|
837 kumpf 1.28 {
|
838 kumpf 1.29 // We've found a reference value!
839 type = CIMKeyBinding::REFERENCE;
|
840 kumpf 1.28 }
|
841 kumpf 1.2 }
|
842 david.dillard 1.41 catch (const Exception &)
|
843 kumpf 1.29 {
844 // Not a reference value; leave type as STRING
845 }
|
846 kumpf 1.2 }
847 else if (toupper(*p) == 'T' || toupper(*p) == 'F')
848 {
|
849 kumpf 1.16 type = CIMKeyBinding::BOOLEAN;
|
850 kumpf 1.2
851 char* r = p;
852 Uint32 n = 0;
853
854 while (*r && *r != ',')
855 {
856 *r = toupper(*r);
857 r++;
858 n++;
859 }
860
861 if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
862 ((strncmp(p, "FALSE", n) == 0) && n == 5)))
|
863 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
864 kumpf 1.2
865 valueString.assign(p, n);
866
867 p = p + n;
868 }
869 else
870 {
|
871 kumpf 1.16 type = CIMKeyBinding::NUMERIC;
|
872 kumpf 1.2
873 char* r = p;
874 Uint32 n = 0;
875
876 while (*r && *r != ',')
877 {
878 r++;
879 n++;
880 }
881
882 Boolean isComma = false;
883 if (*r)
884 {
885 *r = '\0';
886 isComma = true;
887 }
888
889 Sint64 x;
890
891 if (!XmlReader::stringToSignedInteger(p, x))
|
892 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
893 kumpf 1.2
894 valueString.assign(p, n);
895
896 if (isComma)
897 {
898 *r = ',';
899 }
900
901 p = p + n;
902 }
903
|
904 chip 1.47 keyBindings.append(CIMKeyBinding(keyName.getString (), valueString,
|
905 kumpf 1.17 type));
|
906 kumpf 1.2
907 if (*p)
908 {
909 if (*p++ != ',')
910 {
|
911 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
912 kumpf 1.2 }
913 }
914 }
915
916 _BubbleSort(keyBindings);
917 }
918
|
919 chip 1.47 void CIMObjectPath::set(const String& objectName)
|
920 kumpf 1.2 {
921 clear();
922
923 //--------------------------------------------------------------------------
924 // We will extract components from an object name. Here is an sample
925 // object name:
926 //
927 // //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
928 //--------------------------------------------------------------------------
929
930 // Convert to a C String first:
931
|
932 david 1.37 CString pCString = objectName.getCString();
|
933 kumpf 1.26 char* p = const_cast<char*>((const char*) pCString);
|
934 kumpf 1.2 Boolean gotHost;
935 Boolean gotNamespace;
936
937 gotHost = _parseHostElement(objectName, p, _rep->_host);
938 gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
939
940 if (gotHost && !gotNamespace)
941 {
|
942 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
943 kumpf 1.2 }
944
945 // Extract the class name:
946
947 char* dot = strchr(p, '.');
948
949 if (!dot)
950 {
951 if (!CIMName::legal(p))
952 {
|
953 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
954 kumpf 1.2 }
955
956 // ATTN: remove this later: a reference should only be able to hold
957 // an instance name.
958
|
959 kumpf 1.17 _rep->_className = CIMName (p);
|
960 kumpf 1.2 return;
961 }
962
|
963 david 1.27 String className = String(p, (Uint32)(dot - p));
|
964 kumpf 1.7 if (!CIMName::legal(className))
965 {
|
966 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
967 kumpf 1.7 }
968 _rep->_className = className;
|
969 kumpf 1.2
970 // Advance past dot:
971
972 p = dot + 1;
973
974 _parseKeyBindingPairs(objectName, p, _rep->_keyBindings);
975 }
976
977 CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
978 {
979 set(objectName);
980 return *this;
981 }
982
983 const String& CIMObjectPath::getHost() const
984 {
985 return _rep->_host;
986 }
987
988 void CIMObjectPath::setHost(const String& host)
989 {
|
990 kumpf 1.35 if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
991 {
992 throw MalformedObjectNameException(host);
993 }
994
|
995 kumpf 1.2 _rep->_host = host;
996 }
997
|
998 kumpf 1.7 const CIMNamespaceName& CIMObjectPath::getNameSpace() const
|
999 kumpf 1.2 {
1000 return _rep->_nameSpace;
1001 }
1002
|
1003 kumpf 1.7 void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
|
1004 kumpf 1.2 {
1005 _rep->_nameSpace = nameSpace;
1006 }
1007
|
1008 kumpf 1.7 const CIMName& CIMObjectPath::getClassName() const
|
1009 kumpf 1.2 {
1010 return _rep->_className;
1011 }
1012
|
1013 kumpf 1.7 void CIMObjectPath::setClassName(const CIMName& className)
|
1014 kumpf 1.2 {
1015 _rep->_className = className;
1016 }
1017
|
1018 kumpf 1.16 const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
|
1019 kumpf 1.2 {
1020 return _rep->_keyBindings;
1021 }
1022
|
1023 kumpf 1.16 void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
|
1024 kumpf 1.2 {
1025 _rep->_keyBindings = keyBindings;
1026 _BubbleSort(_rep->_keyBindings);
1027 }
1028
|
1029 kumpf 1.15 String CIMObjectPath::toString() const
|
1030 kumpf 1.2 {
1031 String objectName;
1032
1033 // Get the host:
1034
|
1035 kumpf 1.15 if (_rep->_host.size())
|
1036 kumpf 1.2 {
1037 objectName = "//";
|
1038 kumpf 1.13 objectName.append(_rep->_host);
1039 objectName.append("/");
|
1040 kumpf 1.2 }
1041
1042 // Get the namespace (if we have a host name, we must write namespace):
1043
|
1044 kumpf 1.7 if (!_rep->_nameSpace.isNull() || _rep->_host.size())
|
1045 kumpf 1.2 {
|
1046 kumpf 1.17 objectName.append(_rep->_nameSpace.getString ());
|
1047 kumpf 1.13 objectName.append(":");
|
1048 kumpf 1.2 }
1049
1050 // Get the class name:
1051
|
1052 kumpf 1.17 objectName.append(getClassName().getString ());
|
1053 kumpf 1.2
|
1054 kumpf 1.9 //
1055 // ATTN-CAKG-P2-20020726: The following condition does not correctly
1056 // distinguish instanceNames from classNames in every case
1057 // The instanceName of a singleton instance of a keyless class has no
1058 // key bindings
1059 //
1060 if (_rep->_keyBindings.size () != 0)
|
1061 kumpf 1.2 {
1062 objectName.append('.');
1063
1064 // Append each key-value pair:
1065
|
1066 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
|
1067 kumpf 1.2
1068 for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
1069 {
|
1070 kumpf 1.17 objectName.append(keyBindings[i].getName().getString ());
|
1071 kumpf 1.2 objectName.append('=');
1072
1073 const String& value = _escapeSpecialCharacters(
1074 keyBindings[i].getValue());
1075
|
1076 kumpf 1.16 CIMKeyBinding::Type type = keyBindings[i].getType();
|
1077 chip 1.47
|
1078 kumpf 1.16 if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
|
1079 kumpf 1.2 objectName.append('"');
1080
1081 objectName.append(value);
1082
|
1083 kumpf 1.16 if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
|
1084 kumpf 1.2 objectName.append('"');
1085
1086 if (i + 1 != n)
1087 objectName.append(',');
1088 }
1089 }
1090
1091 return objectName;
1092 }
1093
|
1094 kumpf 1.15 String CIMObjectPath::_toStringCanonical() const
|
1095 kumpf 1.2 {
1096 CIMObjectPath ref = *this;
1097
|
1098 kumpf 1.33 // Normalize hostname by changing to lower case
|
1099 chip 1.47 ref._rep->_host.toLower(); // ICU_TODO:
|
1100 kumpf 1.2
|
1101 kumpf 1.33 // Normalize namespace by changing to lower case
1102 if (!ref._rep->_nameSpace.isNull())
1103 {
1104 String nameSpaceLower = ref._rep->_nameSpace.getString();
|
1105 chip 1.47 nameSpaceLower.toLower(); // ICU_TODO:
|
1106 kumpf 1.33 ref._rep->_nameSpace = nameSpaceLower;
1107 }
1108
1109 // Normalize class name by changing to lower case
1110 if (!ref._rep->_className.isNull())
1111 {
1112 String classNameLower = ref._rep->_className.getString();
|
1113 chip 1.47 classNameLower.toLower(); // ICU_TODO:
|
1114 kumpf 1.33 ref._rep->_className = classNameLower;
1115 }
|
1116 kumpf 1.2
1117 for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
1118 {
|
1119 kumpf 1.33 // Normalize key binding name by changing to lower case
1120 if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
1121 {
|
1122 chip 1.47 String keyBindingNameLower =
|
1123 kumpf 1.33 ref._rep->_keyBindings[i]._rep->_name.getString();
1124 keyBindingNameLower.toLower(); // ICU_TODO:
1125 ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
1126 }
1127
1128 // Normalize the key value
1129 switch (ref._rep->_keyBindings[i]._rep->_type)
1130 {
1131 case CIMKeyBinding::REFERENCE:
1132 try
1133 {
1134 // Convert reference to CIMObjectPath and recurse
1135 ref._rep->_keyBindings[i]._rep->_value =
1136 CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
1137 _toStringCanonical();
1138 }
1139 catch (Exception&)
1140 {
1141 // Leave value unchanged if the CIMObjectPath parsing fails
1142 }
1143 break;
1144 kumpf 1.33 case CIMKeyBinding::BOOLEAN:
1145 // Normalize the boolean string by changing to lower case
1146 ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
1147 break;
1148 case CIMKeyBinding::NUMERIC:
1149 // Normalize the numeric string by converting to integer and back
1150 Uint64 uValue;
1151 Sint64 sValue;
1152 // First try converting to unsigned integer
1153 if (XmlReader::stringToUnsignedInteger(
1154 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1155 uValue))
1156 {
1157 char buffer[32]; // Should need 21 chars max
1158 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
1159 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1160 }
1161 // Next try converting to signed integer
1162 else if (XmlReader::stringToSignedInteger(
1163 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1164 sValue))
1165 kumpf 1.33 {
1166 char buffer[32]; // Should need 21 chars max
1167 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
1168 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1169 }
1170 // Leave value unchanged if it cannot be converted to an integer
1171 break;
1172 default: // CIMKeyBinding::STRING
1173 // No normalization required for STRING
1174 break;
1175 }
|
1176 kumpf 1.2 }
1177
|
1178 kumpf 1.33 // Note: key bindings are sorted when set in the CIMObjectPath
|
1179 kumpf 1.12
|
1180 kumpf 1.15 return ref.toString();
|
1181 kumpf 1.2 }
1182
1183 Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
1184 {
1185 return
|
1186 kumpf 1.33 String::equalNoCase(_rep->_host, x._rep->_host) &&
|
1187 kumpf 1.7 _rep->_nameSpace.equal(x._rep->_nameSpace) &&
1188 _rep->_className.equal(x._rep->_className) &&
|
1189 kumpf 1.2 _rep->_keyBindings == x._rep->_keyBindings;
1190 }
1191
1192 Uint32 CIMObjectPath::makeHashCode() const
1193 {
|
1194 kumpf 1.12 return HashFunc<String>::hash(_toStringCanonical());
|
1195 kumpf 1.2 }
1196
1197 Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
1198 {
1199 return x.identical(y);
1200 }
1201
1202 Boolean operator!=(const CIMObjectPath& x, const CIMObjectPath& y)
1203 {
1204 return !operator==(x, y);
1205 }
1206
|
1207 chip 1.1 PEGASUS_NAMESPACE_END
|