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 chip 1.1 //
37 //%/////////////////////////////////////////////////////////////////////////////
38
|
39 kumpf 1.2 #include <Pegasus/Common/Config.h>
40 #include <cstring>
|
41 kumpf 1.22 #include <iostream>
|
42 kumpf 1.2 #include "HashTable.h"
43 #include "CIMObjectPath.h"
44 #include "Indentor.h"
45 #include "CIMName.h"
|
46 a.arora 1.39 #include "Destroyer.h"
|
47 kumpf 1.2 #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 david.dillard 1.48 if (hostname[0].isDigit())
|
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 david.dillard 1.48 if (!hostname[i].isDigit())
|
489 kumpf 1.34 {
|
490 dave.sudlik 1.42 isValid = false;
491 break;
|
492 kumpf 1.34 }
493
|
494 david.dillard 1.48 while (hostname[i].isDigit()) // skip over digits
|
495 kumpf 1.34 {
496 octetValue = octetValue*10 + (hostname[i] - '0');
497 i++;
498 }
499
500 if (octetValue > 255)
501 {
|
502 dave.sudlik 1.42 isValid = false;
503 break;
|
504 kumpf 1.34 }
505
|
506 dave.sudlik 1.42 // Check for invalid character in IP address
|
507 kumpf 1.34 if ((octet != 4) && (hostname[i++] != '.'))
508 {
|
509 dave.sudlik 1.42 isValid = false;
510 break;
511 }
512
513 // Check for the case where it's a valid host name that happens
514 // to have 4 (or more) leading all-numeric host segments.
515 if ((octet == 4) && (hostname[i] != ':') && hostname[i] != char(0))
516 {
517 isValid = false;
518 break;
|
519 kumpf 1.34 }
520 }
521 }
|
522 dave.sudlik 1.42 if (!isValid) // if it is not a valid IP address
|
523 kumpf 1.34 {
|
524 dave.sudlik 1.42 i = 0; // reset index for host name check
525
526 // Validate a host name
527 isValid = true;
|
528 kumpf 1.34
529 Boolean expectHostSegment = true;
|
530 dave.sudlik 1.42 Boolean hostSegmentIsNumeric;
|
531 kumpf 1.34
532 while (expectHostSegment == true)
533 {
534 expectHostSegment = false;
|
535 dave.sudlik 1.42 hostSegmentIsNumeric = true; // assume all-numeric host segment
|
536 kumpf 1.34
|
537 david.dillard 1.48 if (!hostname[i].isAlnum())
|
538 kumpf 1.34 {
539 return false;
540 }
541
|
542 david.dillard 1.48 while (hostname[i].isAlnum() || (hostname[i] == '-'))
|
543 kumpf 1.34 {
|
544 dave.sudlik 1.42 // If a non-digit is encountered, set "all-numeric"
545 // flag to false
|
546 david.dillard 1.48 if (hostname[i].isAlpha() || (hostname[i] == '-')) {
|
547 dave.sudlik 1.42 hostSegmentIsNumeric = false;
548 }
|
549 kumpf 1.34 i++;
550 }
551
552 if (hostname[i] == '.')
553 {
554 i++;
555 expectHostSegment = true;
556 }
557 }
|
558 dave.sudlik 1.42 // If the last Host Segment is all numeric, then return false.
559 // RFC 1123 says "highest-level component label will be alphabetic".
560 if (hostSegmentIsNumeric) {
561 return false;
562 }
563 }
564
565 if (!isValid) // if not a valid IP address or host name
566 {
567 return false;
|
568 kumpf 1.34 }
569
570 // Check for a port number:
571
572 if (hostname[i] == ':')
573 {
|
574 david.dillard 1.48 if (!hostname[++i].isDigit())
|
575 kumpf 1.34 {
576 return false;
577 }
|
578 chip 1.47
|
579 david.dillard 1.48 while (hostname[++i].isDigit());
|
580 kumpf 1.34 }
581
582 return (hostname[i] == char(0));
583 }
584
|
585 kumpf 1.2 //
586 // Contains port as well (e.g., myhost:1234).
587 //
588 String _host;
589
|
590 kumpf 1.7 CIMNamespaceName _nameSpace;
591 CIMName _className;
|
592 kumpf 1.16 Array<CIMKeyBinding> _keyBindings;
|
593 kumpf 1.2 };
594
595
|
596 a.arora 1.39 CIMObjectPath::CIMObjectPath()
|
597 kumpf 1.2 {
|
598 a.arora 1.39 _rep = new CIMObjectPathRep();
|
599 kumpf 1.2 }
600
|
601 a.arora 1.39 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x)
|
602 kumpf 1.2 {
|
603 a.arora 1.39 _rep = new CIMObjectPathRep(*x._rep);
|
604 kumpf 1.2 }
605
606 CIMObjectPath::CIMObjectPath(const String& objectName)
607 {
608 // Test the objectName out to see if we get an exception
609 CIMObjectPath tmpRef;
610 tmpRef.set(objectName);
611
|
612 a.arora 1.39 _rep = new CIMObjectPathRep(*tmpRef._rep);
|
613 kumpf 1.2 }
614
615 CIMObjectPath::CIMObjectPath(
616 const String& host,
|
617 kumpf 1.7 const CIMNamespaceName& nameSpace,
618 const CIMName& className,
|
619 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
620 kumpf 1.2 {
621 // Test the objectName out to see if we get an exception
622 CIMObjectPath tmpRef;
623 tmpRef.set(host, nameSpace, className, keyBindings);
624
|
625 a.arora 1.39 _rep = new CIMObjectPathRep(*tmpRef._rep);
|
626 kumpf 1.2 }
627
628 CIMObjectPath::~CIMObjectPath()
629 {
|
630 a.arora 1.39 delete _rep;
|
631 kumpf 1.2 }
632
633 CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
634 {
|
635 a.arora 1.39 *_rep = *x._rep;
|
636 kumpf 1.2 return *this;
637 }
638
639 void CIMObjectPath::clear()
640 {
641 _rep->_host.clear();
642 _rep->_nameSpace.clear();
643 _rep->_className.clear();
644 _rep->_keyBindings.clear();
645 }
646
647 void CIMObjectPath::set(
648 const String& host,
|
649 kumpf 1.7 const CIMNamespaceName& nameSpace,
650 const CIMName& className,
|
651 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
652 kumpf 1.2 {
653 setHost(host);
654 setNameSpace(nameSpace);
655 setClassName(className);
656 setKeyBindings(keyBindings);
657 }
658
|
659 kumpf 1.22 Boolean _parseHostElement(
|
660 kumpf 1.2 const String& objectName,
661 char*& p,
|
662 kumpf 1.9 String& host)
|
663 kumpf 1.2 {
664 // See if there is a host name (true if it begins with "//"):
|
665 kumpf 1.32 // Host is of the form <hostname>:<port> and begins with "//"
|
666 kumpf 1.2 // and ends with "/":
667
668 if (p[0] != '/' || p[1] != '/')
669 {
670 return false;
671 }
672
673 p += 2;
674
|
675 kumpf 1.34 char* slash = strchr(p, '/');
676 if (!slash)
|
677 chuck 1.23 {
|
678 kumpf 1.34 throw MalformedObjectNameException(objectName);
|
679 kumpf 1.2 }
680
|
681 kumpf 1.34 String hostname = String(p, (Uint32)(slash - p));
682 if (!CIMObjectPathRep::isValidHostname(hostname))
|
683 kumpf 1.2 {
|
684 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
685 kumpf 1.2 }
|
686 kumpf 1.34 host = hostname;
|
687 kumpf 1.2
|
688 kumpf 1.31 // Do not step past the '/'; it will be consumed by the namespace parser
|
689 kumpf 1.34 p = slash;
|
690 kumpf 1.2
691 return true;
692 }
693
|
694 kumpf 1.22 Boolean _parseNamespaceElement(
|
695 kumpf 1.2 const String& objectName,
696 char*& p,
|
697 kumpf 1.7 CIMNamespaceName& nameSpace)
|
698 kumpf 1.2 {
699 // If we don't find a valid namespace name followed by a ':', we
700 // assume we're not looking at a namespace name.
701
|
702 kumpf 1.7 char* colon = strchr(p, ':');
703 if (!colon)
704 {
705 return false;
706 }
707
|
708 chip 1.47 // A ':' as part of a keybinding value should not be interpreted as
|
709 kumpf 1.25 // a namespace delimiter. Since keybinding pairs follow the first '.'
710 // in the object path string, the ':' delimiter only counts if it
711 // appears before the '.'.
712
713 char* dot = strchr(p, '.');
714 if (dot && (dot < colon))
715 {
716 return false;
717 }
718
|
719 kumpf 1.2 //----------------------------------------------------------------------
720 // Validate the namespace path. Namespaces must match the following
721 // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
722 //----------------------------------------------------------------------
723
|
724 david 1.27 String namespaceName = String(p, (Uint32)(colon - p));
|
725 kumpf 1.7 if (!CIMNamespaceName::legal(namespaceName))
|
726 kumpf 1.2 {
|
727 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
728 kumpf 1.2 }
|
729 kumpf 1.7 nameSpace = namespaceName;
|
730 kumpf 1.2
|
731 kumpf 1.7 p = colon+1;
|
732 kumpf 1.2 return true;
733 }
734
735 /**
|
736 kumpf 1.29 ATTN-RK: The DMTF specification for the string form of an
737 object path makes it impossible for a parser to distinguish
738 between a key values of String type and Reference type.
739
740 Given the ambiguity, this implementation takes a guess at the
741 type of a quoted key value. If the value can be parsed into
742 a CIMObjectPath with at least one key binding, the type is
743 set to REFERENCE. Otherwise, the type is set to STRING.
744 Note: This algorithm appears to be in line with what the Sun
745 WBEM Services implementation does.
746
747 To be totally correct, it would be necessary to retrieve the
748 class definition and look up the types of the key properties
749 to determine how to interpret the key values. This is clearly
750 too inefficient for internal transformations between
751 CIMObjectPaths and String values.
|
752 kumpf 1.2 */
|
753 kumpf 1.22 void _parseKeyBindingPairs(
|
754 kumpf 1.2 const String& objectName,
755 char*& p,
|
756 chip 1.47 Array<CIMKeyBinding>& keyBindings)
|
757 kumpf 1.2 {
758 // Get the key-value pairs:
759
760 while (*p)
761 {
762 // Get key part:
763
|
764 kumpf 1.5 char* equalsign = strchr(p, '=');
765 if (!equalsign)
|
766 kumpf 1.2 {
|
767 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
768 kumpf 1.2 }
769
|
770 kumpf 1.5 *equalsign = 0;
|
771 kumpf 1.2
|
772 kumpf 1.17 if (!CIMName::legal(p))
|
773 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
774 kumpf 1.2
|
775 kumpf 1.17 CIMName keyName (p);
776
|
777 kumpf 1.2 // Get the value part:
778
779 String valueString;
|
780 kumpf 1.5 p = equalsign + 1;
|
781 kumpf 1.16 CIMKeyBinding::Type type;
|
782 kumpf 1.2
|
783 kumpf 1.29 if (*p == '"')
|
784 kumpf 1.2 {
|
785 kumpf 1.29 // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
786
|
787 kumpf 1.2 p++;
788
789 while (*p && *p != '"')
790 {
791 if (*p == '\\')
|
792 kumpf 1.28 {
|
793 kumpf 1.2 *p++;
794
|
795 kumpf 1.28 if ((*p != '\\') && (*p != '"'))
796 {
797 throw MalformedObjectNameException(objectName);
798 }
799 }
800
|
801 kumpf 1.2 valueString.append(*p++);
802 }
803
804 if (*p++ != '"')
|
805 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
806 kumpf 1.2
|
807 kumpf 1.29 /*
808 Guess at the type of this quoted key value. If the value
809 can be parsed into a CIMObjectPath with at least one key
810 binding, the type is assumed to be a REFERENCE. Otherwise,
811 the type is set to STRING. (See method header for details.)
812 */
|
813 kumpf 1.16 type = CIMKeyBinding::STRING;
|
814 kumpf 1.2
|
815 kumpf 1.29 try
|
816 kumpf 1.2 {
|
817 kumpf 1.29 CIMObjectPath testForPath(valueString);
818 if (testForPath.getKeyBindings().size() > 0)
|
819 kumpf 1.28 {
|
820 kumpf 1.29 // We've found a reference value!
821 type = CIMKeyBinding::REFERENCE;
|
822 kumpf 1.28 }
|
823 kumpf 1.2 }
|
824 david.dillard 1.41 catch (const Exception &)
|
825 kumpf 1.29 {
826 // Not a reference value; leave type as STRING
827 }
|
828 kumpf 1.2 }
829 else if (toupper(*p) == 'T' || toupper(*p) == 'F')
830 {
|
831 kumpf 1.16 type = CIMKeyBinding::BOOLEAN;
|
832 kumpf 1.2
833 char* r = p;
834 Uint32 n = 0;
835
836 while (*r && *r != ',')
837 {
838 *r = toupper(*r);
839 r++;
840 n++;
841 }
842
843 if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
844 ((strncmp(p, "FALSE", n) == 0) && n == 5)))
|
845 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
846 kumpf 1.2
847 valueString.assign(p, n);
848
849 p = p + n;
850 }
851 else
852 {
|
853 kumpf 1.16 type = CIMKeyBinding::NUMERIC;
|
854 kumpf 1.2
855 char* r = p;
856 Uint32 n = 0;
857
858 while (*r && *r != ',')
859 {
860 r++;
861 n++;
862 }
863
864 Boolean isComma = false;
865 if (*r)
866 {
867 *r = '\0';
868 isComma = true;
869 }
870
871 Sint64 x;
872
873 if (!XmlReader::stringToSignedInteger(p, x))
|
874 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
875 kumpf 1.2
876 valueString.assign(p, n);
877
878 if (isComma)
879 {
880 *r = ',';
881 }
882
883 p = p + n;
884 }
885
|
886 chip 1.47 keyBindings.append(CIMKeyBinding(keyName.getString (), valueString,
|
887 kumpf 1.17 type));
|
888 kumpf 1.2
889 if (*p)
890 {
891 if (*p++ != ',')
892 {
|
893 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
894 kumpf 1.2 }
895 }
896 }
897
898 _BubbleSort(keyBindings);
899 }
900
|
901 chip 1.47 void CIMObjectPath::set(const String& objectName)
|
902 kumpf 1.2 {
903 clear();
904
905 //--------------------------------------------------------------------------
906 // We will extract components from an object name. Here is an sample
907 // object name:
908 //
909 // //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
910 //--------------------------------------------------------------------------
911
912 // Convert to a C String first:
913
|
914 david 1.37 CString pCString = objectName.getCString();
|
915 kumpf 1.26 char* p = const_cast<char*>((const char*) pCString);
|
916 kumpf 1.2 Boolean gotHost;
917 Boolean gotNamespace;
918
919 gotHost = _parseHostElement(objectName, p, _rep->_host);
920 gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
921
922 if (gotHost && !gotNamespace)
923 {
|
924 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
925 kumpf 1.2 }
926
927 // Extract the class name:
928
929 char* dot = strchr(p, '.');
930
931 if (!dot)
932 {
933 if (!CIMName::legal(p))
934 {
|
935 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
936 kumpf 1.2 }
937
938 // ATTN: remove this later: a reference should only be able to hold
939 // an instance name.
940
|
941 kumpf 1.17 _rep->_className = CIMName (p);
|
942 kumpf 1.2 return;
943 }
944
|
945 david 1.27 String className = String(p, (Uint32)(dot - p));
|
946 kumpf 1.7 if (!CIMName::legal(className))
947 {
|
948 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
949 kumpf 1.7 }
950 _rep->_className = className;
|
951 kumpf 1.2
952 // Advance past dot:
953
954 p = dot + 1;
955
956 _parseKeyBindingPairs(objectName, p, _rep->_keyBindings);
957 }
958
959 CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
960 {
961 set(objectName);
962 return *this;
963 }
964
965 const String& CIMObjectPath::getHost() const
966 {
967 return _rep->_host;
968 }
969
970 void CIMObjectPath::setHost(const String& host)
971 {
|
972 kumpf 1.35 if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
973 {
974 throw MalformedObjectNameException(host);
975 }
976
|
977 kumpf 1.2 _rep->_host = host;
978 }
979
|
980 kumpf 1.7 const CIMNamespaceName& CIMObjectPath::getNameSpace() const
|
981 kumpf 1.2 {
982 return _rep->_nameSpace;
983 }
984
|
985 kumpf 1.7 void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
|
986 kumpf 1.2 {
987 _rep->_nameSpace = nameSpace;
988 }
989
|
990 kumpf 1.7 const CIMName& CIMObjectPath::getClassName() const
|
991 kumpf 1.2 {
992 return _rep->_className;
993 }
994
|
995 kumpf 1.7 void CIMObjectPath::setClassName(const CIMName& className)
|
996 kumpf 1.2 {
997 _rep->_className = className;
998 }
999
|
1000 kumpf 1.16 const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
|
1001 kumpf 1.2 {
1002 return _rep->_keyBindings;
1003 }
1004
|
1005 kumpf 1.16 void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
|
1006 kumpf 1.2 {
1007 _rep->_keyBindings = keyBindings;
1008 _BubbleSort(_rep->_keyBindings);
1009 }
1010
|
1011 kumpf 1.15 String CIMObjectPath::toString() const
|
1012 kumpf 1.2 {
1013 String objectName;
1014
1015 // Get the host:
1016
|
1017 kumpf 1.15 if (_rep->_host.size())
|
1018 kumpf 1.2 {
1019 objectName = "//";
|
1020 kumpf 1.13 objectName.append(_rep->_host);
1021 objectName.append("/");
|
1022 kumpf 1.2 }
1023
1024 // Get the namespace (if we have a host name, we must write namespace):
1025
|
1026 kumpf 1.7 if (!_rep->_nameSpace.isNull() || _rep->_host.size())
|
1027 kumpf 1.2 {
|
1028 kumpf 1.17 objectName.append(_rep->_nameSpace.getString ());
|
1029 kumpf 1.13 objectName.append(":");
|
1030 kumpf 1.2 }
1031
1032 // Get the class name:
1033
|
1034 kumpf 1.17 objectName.append(getClassName().getString ());
|
1035 kumpf 1.2
|
1036 kumpf 1.9 //
1037 // ATTN-CAKG-P2-20020726: The following condition does not correctly
1038 // distinguish instanceNames from classNames in every case
1039 // The instanceName of a singleton instance of a keyless class has no
1040 // key bindings
1041 //
1042 if (_rep->_keyBindings.size () != 0)
|
1043 kumpf 1.2 {
1044 objectName.append('.');
1045
1046 // Append each key-value pair:
1047
|
1048 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
|
1049 kumpf 1.2
1050 for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
1051 {
|
1052 kumpf 1.17 objectName.append(keyBindings[i].getName().getString ());
|
1053 kumpf 1.2 objectName.append('=');
1054
1055 const String& value = _escapeSpecialCharacters(
1056 keyBindings[i].getValue());
1057
|
1058 kumpf 1.16 CIMKeyBinding::Type type = keyBindings[i].getType();
|
1059 chip 1.47
|
1060 kumpf 1.16 if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
|
1061 kumpf 1.2 objectName.append('"');
1062
1063 objectName.append(value);
1064
|
1065 kumpf 1.16 if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
|
1066 kumpf 1.2 objectName.append('"');
1067
1068 if (i + 1 != n)
1069 objectName.append(',');
1070 }
1071 }
1072
1073 return objectName;
1074 }
1075
|
1076 kumpf 1.15 String CIMObjectPath::_toStringCanonical() const
|
1077 kumpf 1.2 {
1078 CIMObjectPath ref = *this;
1079
|
1080 kumpf 1.33 // Normalize hostname by changing to lower case
|
1081 chip 1.47 ref._rep->_host.toLower(); // ICU_TODO:
|
1082 kumpf 1.2
|
1083 kumpf 1.33 // Normalize namespace by changing to lower case
1084 if (!ref._rep->_nameSpace.isNull())
1085 {
1086 String nameSpaceLower = ref._rep->_nameSpace.getString();
|
1087 chip 1.47 nameSpaceLower.toLower(); // ICU_TODO:
|
1088 kumpf 1.33 ref._rep->_nameSpace = nameSpaceLower;
1089 }
1090
1091 // Normalize class name by changing to lower case
1092 if (!ref._rep->_className.isNull())
1093 {
1094 String classNameLower = ref._rep->_className.getString();
|
1095 chip 1.47 classNameLower.toLower(); // ICU_TODO:
|
1096 kumpf 1.33 ref._rep->_className = classNameLower;
1097 }
|
1098 kumpf 1.2
1099 for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
1100 {
|
1101 kumpf 1.33 // Normalize key binding name by changing to lower case
1102 if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
1103 {
|
1104 chip 1.47 String keyBindingNameLower =
|
1105 kumpf 1.33 ref._rep->_keyBindings[i]._rep->_name.getString();
1106 keyBindingNameLower.toLower(); // ICU_TODO:
1107 ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
1108 }
1109
1110 // Normalize the key value
1111 switch (ref._rep->_keyBindings[i]._rep->_type)
1112 {
1113 case CIMKeyBinding::REFERENCE:
1114 try
1115 {
1116 // Convert reference to CIMObjectPath and recurse
1117 ref._rep->_keyBindings[i]._rep->_value =
1118 CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
1119 _toStringCanonical();
1120 }
1121 catch (Exception&)
1122 {
1123 // Leave value unchanged if the CIMObjectPath parsing fails
1124 }
1125 break;
1126 kumpf 1.33 case CIMKeyBinding::BOOLEAN:
1127 // Normalize the boolean string by changing to lower case
1128 ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
1129 break;
1130 case CIMKeyBinding::NUMERIC:
1131 // Normalize the numeric string by converting to integer and back
1132 Uint64 uValue;
1133 Sint64 sValue;
1134 // First try converting to unsigned integer
1135 if (XmlReader::stringToUnsignedInteger(
1136 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1137 uValue))
1138 {
1139 char buffer[32]; // Should need 21 chars max
1140 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
1141 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1142 }
1143 // Next try converting to signed integer
1144 else if (XmlReader::stringToSignedInteger(
1145 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1146 sValue))
1147 kumpf 1.33 {
1148 char buffer[32]; // Should need 21 chars max
1149 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
1150 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1151 }
1152 // Leave value unchanged if it cannot be converted to an integer
1153 break;
1154 default: // CIMKeyBinding::STRING
1155 // No normalization required for STRING
1156 break;
1157 }
|
1158 kumpf 1.2 }
1159
|
1160 kumpf 1.33 // Note: key bindings are sorted when set in the CIMObjectPath
|
1161 kumpf 1.12
|
1162 kumpf 1.15 return ref.toString();
|
1163 kumpf 1.2 }
1164
1165 Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
1166 {
1167 return
|
1168 kumpf 1.33 String::equalNoCase(_rep->_host, x._rep->_host) &&
|
1169 kumpf 1.7 _rep->_nameSpace.equal(x._rep->_nameSpace) &&
1170 _rep->_className.equal(x._rep->_className) &&
|
1171 kumpf 1.2 _rep->_keyBindings == x._rep->_keyBindings;
1172 }
1173
1174 Uint32 CIMObjectPath::makeHashCode() const
1175 {
|
1176 kumpf 1.12 return HashFunc<String>::hash(_toStringCanonical());
|
1177 kumpf 1.2 }
1178
1179 Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
1180 {
1181 return x.identical(y);
1182 }
1183
1184 Boolean operator!=(const CIMObjectPath& x, const CIMObjectPath& y)
1185 {
1186 return !operator==(x, y);
1187 }
1188
|
1189 chip 1.1 PEGASUS_NAMESPACE_END
|