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