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