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 dave.sudlik 1.41.2.1 case CIMTYPE_OBJECT:
219 throw TypeMismatchException();
220 // From PEP 194:
221 // Open Issue for the DMTF: Are EmbeddedObject properties permitted to be keys?
222 break;
|
223 kumpf 1.18 default:
224 kbType = NUMERIC;
225 break;
226 }
227
|
228 a.arora 1.39 _rep = new CIMKeyBindingRep(name, kbValue, kbType);
|
229 kumpf 1.18 }
230
|
231 kumpf 1.16 CIMKeyBinding::~CIMKeyBinding()
|
232 kumpf 1.2 {
|
233 a.arora 1.39 delete _rep;
|
234 kumpf 1.2 }
235
|
236 kumpf 1.16 CIMKeyBinding& CIMKeyBinding::operator=(const CIMKeyBinding& x)
|
237 kumpf 1.2 {
|
238 a.arora 1.39 *_rep = *x._rep;
|
239 kumpf 1.2 return *this;
240 }
241
|
242 kumpf 1.16 const CIMName& CIMKeyBinding::getName() const
|
243 kumpf 1.2 {
244 return _rep->_name;
245 }
246
|
247 kumpf 1.16 void CIMKeyBinding::setName(const CIMName& name)
|
248 kumpf 1.2 {
249 _rep->_name = name;
250 }
251
|
252 kumpf 1.16 const String& CIMKeyBinding::getValue() const
|
253 kumpf 1.2 {
254 return _rep->_value;
255 }
256
|
257 kumpf 1.16 void CIMKeyBinding::setValue(const String& value)
|
258 kumpf 1.2 {
259 _rep->_value = value;
260 }
261
|
262 kumpf 1.16 CIMKeyBinding::Type CIMKeyBinding::getType() const
|
263 kumpf 1.2 {
264 return _rep->_type;
265 }
266
|
267 kumpf 1.16 void CIMKeyBinding::setType(CIMKeyBinding::Type type)
|
268 kumpf 1.2 {
269 _rep->_type = type;
270 }
|
271 kumpf 1.18
272 Boolean CIMKeyBinding::equal(CIMValue value)
273 {
|
274 kumpf 1.21 if (value.isArray())
|
275 kumpf 1.20 {
276 return false;
277 }
278
|
279 kumpf 1.18 CIMValue kbValue;
280
281 try
282 {
283 switch (value.getType())
284 {
285 case CIMTYPE_CHAR16:
|
286 kumpf 1.20 if (getType() != STRING) return false;
|
287 kumpf 1.18 kbValue.set(getValue()[0]);
288 break;
289 case CIMTYPE_DATETIME:
|
290 kumpf 1.20 if (getType() != STRING) return false;
|
291 kumpf 1.18 kbValue.set(CIMDateTime(getValue()));
292 break;
293 case CIMTYPE_STRING:
|
294 kumpf 1.20 if (getType() != STRING) return false;
|
295 kumpf 1.18 kbValue.set(getValue());
296 break;
297 case CIMTYPE_REFERENCE:
|
298 kumpf 1.20 if (getType() != REFERENCE) return false;
|
299 kumpf 1.18 kbValue.set(CIMObjectPath(getValue()));
300 break;
|
301 kumpf 1.20 case CIMTYPE_BOOLEAN:
302 if (getType() != BOOLEAN) return false;
303 kbValue = XmlReader::stringToValue(0, getValue().getCString(),
304 value.getType());
305 break;
|
306 dave.sudlik 1.41.2.1 case CIMTYPE_OBJECT:
307 return false;
308 // From PEP 194:
309 // Open Issue for the DMTF: Are EmbeddedObject properties permitted to be keys?
310 break;
|
311 kumpf 1.20 default: // Numerics
312 if (getType() != NUMERIC) return false;
|
313 kumpf 1.18 kbValue = XmlReader::stringToValue(0, getValue().getCString(),
314 value.getType());
315 break;
316 }
317 }
|
318 kumpf 1.19 catch (Exception&)
|
319 kumpf 1.18 {
320 return false;
321 }
322
323 return value.equal(kbValue);
324 }
|
325 kumpf 1.2
|
326 kumpf 1.16 Boolean operator==(const CIMKeyBinding& x, const CIMKeyBinding& y)
|
327 kumpf 1.2 {
|
328 kumpf 1.33 // Check that the names and types match
329 if (!(x.getName().equal(y.getName())) ||
330 !(x.getType() == y.getType()))
331 {
332 return false;
333 }
334
335 switch (x.getType())
336 {
337 case CIMKeyBinding::REFERENCE:
338 try
339 {
340 // References should be compared as CIMObjectPaths
341 return (CIMObjectPath(x.getValue()) == CIMObjectPath(y.getValue()));
342 }
343 catch (Exception&)
344 {
345 // If CIMObjectPath parsing fails, just compare strings
346 return (String::equal(x.getValue(), y.getValue()));
347 }
348 break;
349 kumpf 1.33 case CIMKeyBinding::BOOLEAN:
350 // Case-insensitive comparison is sufficient for booleans
351 return (String::equalNoCase(x.getValue(), y.getValue()));
352 break;
353 case CIMKeyBinding::NUMERIC:
354 // Note: This comparison assumes XML syntax for integers
355 // First try comparing as unsigned integers
356 {
357 Uint64 xValue;
358 Uint64 yValue;
359 if (XmlReader::stringToUnsignedInteger(
360 x.getValue().getCString(), xValue) &&
361 XmlReader::stringToUnsignedInteger(
362 y.getValue().getCString(), yValue))
363 {
364 return (xValue == yValue);
365 }
366 }
367 // Next try comparing as signed integers
368 {
369 Sint64 xValue;
370 kumpf 1.33 Sint64 yValue;
371 if (XmlReader::stringToSignedInteger(
372 x.getValue().getCString(), xValue) &&
373 XmlReader::stringToSignedInteger(
374 y.getValue().getCString(), yValue))
375 {
376 return (xValue == yValue);
377 }
378 }
379 // Note: Keys may not be real values, so don't try comparing as reals
380 // We couldn't parse the numbers, so just compare the strings
381 return (String::equal(x.getValue(), y.getValue()));
382 break;
383 default: // CIMKeyBinding::STRING
384 return (String::equal(x.getValue(), y.getValue()));
385 break;
386 }
387
388 PEGASUS_UNREACHABLE(return false;)
|
389 kumpf 1.2 }
390
391
392 ////////////////////////////////////////////////////////////////////////////////
393 //
394 // CIMObjectPath
395 //
396 ////////////////////////////////////////////////////////////////////////////////
397
398 class CIMObjectPathRep
399 {
400 public:
401 CIMObjectPathRep()
402 {
403 }
404
405 CIMObjectPathRep(const CIMObjectPathRep& x)
406 : _host(x._host), _nameSpace(x._nameSpace),
407 _className(x._className), _keyBindings(x._keyBindings)
408 {
409 }
410 kumpf 1.2
411 CIMObjectPathRep(
412 const String& host,
|
413 kumpf 1.7 const CIMNamespaceName& nameSpace,
414 const CIMName& className,
|
415 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
416 kumpf 1.2 : _host(host), _nameSpace(nameSpace),
417 _className(className), _keyBindings(keyBindings)
418 {
419 }
420
421 ~CIMObjectPathRep()
422 {
423 }
424
425 CIMObjectPathRep& operator=(const CIMObjectPathRep& x)
426 {
427 if (&x != this)
428 {
429 _host = x._host;
430 _nameSpace = x._nameSpace;
431 _className = x._className;
432 _keyBindings = x._keyBindings;
433 }
434 return *this;
435 }
436
|
437 kumpf 1.34 static Boolean isValidHostname(const String& hostname)
438 {
439 //------------------------------------------------------------------
440 // Validate the hostname. The hostname value may or may not be a
441 // fully-qualified domain name (e.g., xyz.company.com) or may be an
442 // IP address. A port number may follow the hostname.
443 // Hostnames must match one of the following regular expressions:
444 // ^([A-Za-z][A-Za-z0-9-]*)(\.[A-Za-z][A-Za-z0-9-]*)*(:[0-9]*)?$
445 // ^([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)(:[0-9]*)?$
446 //------------------------------------------------------------------
447
448 Uint32 i = 0;
449
450 if (isdigit(hostname[0]))
451 {
452 // Validate an IP address
453
454 for (Uint32 octet=1; octet<=4; octet++)
455 {
456 Uint32 octetValue = 0;
457
458 kumpf 1.34 if (!isdigit(hostname[i]))
459 {
460 return false;
461 }
462
463 while (isdigit(hostname[i]))
464 {
465 octetValue = octetValue*10 + (hostname[i] - '0');
466 i++;
467 }
468
469 if (octetValue > 255)
470 {
471 return false;
472 }
473
474 if ((octet != 4) && (hostname[i++] != '.'))
475 {
476 return false;
477 }
478 }
479 kumpf 1.34 }
480 else
481 {
482 // Validate a hostname
483
484 Boolean expectHostSegment = true;
485
486 while (expectHostSegment == true)
487 {
488 expectHostSegment = false;
489
490 if (!isalpha(hostname[i++]))
491 {
492 return false;
493 }
494
495 while (isalnum(hostname[i]) || (hostname[i] == '-'))
496 {
497 i++;
498 }
499
500 kumpf 1.34 if (hostname[i] == '.')
501 {
502 i++;
503 expectHostSegment = true;
504 }
505 }
506 }
507
508 // Check for a port number:
509
510 if (hostname[i] == ':')
511 {
512 if (!isdigit(hostname[++i]))
513 {
514 return false;
515 }
516
517 while (isdigit(hostname[++i]));
518 }
519
520 return (hostname[i] == char(0));
521 kumpf 1.34 }
522
|
523 kumpf 1.2 //
524 // Contains port as well (e.g., myhost:1234).
525 //
526 String _host;
527
|
528 kumpf 1.7 CIMNamespaceName _nameSpace;
529 CIMName _className;
|
530 kumpf 1.16 Array<CIMKeyBinding> _keyBindings;
|
531 kumpf 1.2 };
532
533
|
534 a.arora 1.39 CIMObjectPath::CIMObjectPath()
|
535 kumpf 1.2 {
|
536 a.arora 1.39 _rep = new CIMObjectPathRep();
|
537 kumpf 1.2 }
538
|
539 a.arora 1.39 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x)
|
540 kumpf 1.2 {
|
541 a.arora 1.39 _rep = new CIMObjectPathRep(*x._rep);
|
542 kumpf 1.2 }
543
544 CIMObjectPath::CIMObjectPath(const String& objectName)
545 {
546 // Test the objectName out to see if we get an exception
547 CIMObjectPath tmpRef;
548 tmpRef.set(objectName);
549
|
550 a.arora 1.39 _rep = new CIMObjectPathRep(*tmpRef._rep);
|
551 kumpf 1.2 }
552
553 CIMObjectPath::CIMObjectPath(
554 const String& host,
|
555 kumpf 1.7 const CIMNamespaceName& nameSpace,
556 const CIMName& className,
|
557 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
558 kumpf 1.2 {
559 // Test the objectName out to see if we get an exception
560 CIMObjectPath tmpRef;
561 tmpRef.set(host, nameSpace, className, keyBindings);
562
|
563 a.arora 1.39 _rep = new CIMObjectPathRep(*tmpRef._rep);
|
564 kumpf 1.2 }
565
566 CIMObjectPath::~CIMObjectPath()
567 {
|
568 a.arora 1.39 delete _rep;
|
569 kumpf 1.2 }
570
571 CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
572 {
|
573 a.arora 1.39 *_rep = *x._rep;
|
574 kumpf 1.2 return *this;
575 }
576
577 void CIMObjectPath::clear()
578 {
579 _rep->_host.clear();
580 _rep->_nameSpace.clear();
581 _rep->_className.clear();
582 _rep->_keyBindings.clear();
583 }
584
585 void CIMObjectPath::set(
586 const String& host,
|
587 kumpf 1.7 const CIMNamespaceName& nameSpace,
588 const CIMName& className,
|
589 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
590 kumpf 1.2 {
591 setHost(host);
592 setNameSpace(nameSpace);
593 setClassName(className);
594 setKeyBindings(keyBindings);
595 }
596
|
597 kumpf 1.22 Boolean _parseHostElement(
|
598 kumpf 1.2 const String& objectName,
599 char*& p,
|
600 kumpf 1.9 String& host)
|
601 kumpf 1.2 {
602 // See if there is a host name (true if it begins with "//"):
|
603 kumpf 1.32 // Host is of the form <hostname>:<port> and begins with "//"
|
604 kumpf 1.2 // and ends with "/":
605
606 if (p[0] != '/' || p[1] != '/')
607 {
608 return false;
609 }
610
611 p += 2;
612
|
613 kumpf 1.34 char* slash = strchr(p, '/');
614 if (!slash)
|
615 chuck 1.23 {
|
616 kumpf 1.34 throw MalformedObjectNameException(objectName);
|
617 kumpf 1.2 }
618
|
619 kumpf 1.34 String hostname = String(p, (Uint32)(slash - p));
620 if (!CIMObjectPathRep::isValidHostname(hostname))
|
621 kumpf 1.2 {
|
622 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
623 kumpf 1.2 }
|
624 kumpf 1.34 host = hostname;
|
625 kumpf 1.2
|
626 kumpf 1.31 // Do not step past the '/'; it will be consumed by the namespace parser
|
627 kumpf 1.34 p = slash;
|
628 kumpf 1.2
629 return true;
630 }
631
|
632 kumpf 1.22 Boolean _parseNamespaceElement(
|
633 kumpf 1.2 const String& objectName,
634 char*& p,
|
635 kumpf 1.7 CIMNamespaceName& nameSpace)
|
636 kumpf 1.2 {
637 // If we don't find a valid namespace name followed by a ':', we
638 // assume we're not looking at a namespace name.
639
|
640 kumpf 1.7 char* colon = strchr(p, ':');
641 if (!colon)
642 {
643 return false;
644 }
645
|
646 kumpf 1.25 // A ':' as part of a keybinding value should not be interpreted as
647 // a namespace delimiter. Since keybinding pairs follow the first '.'
648 // in the object path string, the ':' delimiter only counts if it
649 // appears before the '.'.
650
651 char* dot = strchr(p, '.');
652 if (dot && (dot < colon))
653 {
654 return false;
655 }
656
|
657 kumpf 1.2 //----------------------------------------------------------------------
658 // Validate the namespace path. Namespaces must match the following
659 // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
660 //----------------------------------------------------------------------
661
|
662 david 1.27 String namespaceName = String(p, (Uint32)(colon - p));
|
663 kumpf 1.7 if (!CIMNamespaceName::legal(namespaceName))
|
664 kumpf 1.2 {
|
665 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
666 kumpf 1.2 }
|
667 kumpf 1.7 nameSpace = namespaceName;
|
668 kumpf 1.2
|
669 kumpf 1.7 p = colon+1;
|
670 kumpf 1.2 return true;
671 }
672
673 /**
|
674 kumpf 1.29 ATTN-RK: The DMTF specification for the string form of an
675 object path makes it impossible for a parser to distinguish
676 between a key values of String type and Reference type.
677
678 Given the ambiguity, this implementation takes a guess at the
679 type of a quoted key value. If the value can be parsed into
680 a CIMObjectPath with at least one key binding, the type is
681 set to REFERENCE. Otherwise, the type is set to STRING.
682 Note: This algorithm appears to be in line with what the Sun
683 WBEM Services implementation does.
684
685 To be totally correct, it would be necessary to retrieve the
686 class definition and look up the types of the key properties
687 to determine how to interpret the key values. This is clearly
688 too inefficient for internal transformations between
689 CIMObjectPaths and String values.
|
690 kumpf 1.2 */
|
691 kumpf 1.22 void _parseKeyBindingPairs(
|
692 kumpf 1.2 const String& objectName,
693 char*& p,
|
694 kumpf 1.16 Array<CIMKeyBinding>& keyBindings)
|
695 kumpf 1.2 {
696 // Get the key-value pairs:
697
698 while (*p)
699 {
700 // Get key part:
701
|
702 kumpf 1.5 char* equalsign = strchr(p, '=');
703 if (!equalsign)
|
704 kumpf 1.2 {
|
705 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
706 kumpf 1.2 }
707
|
708 kumpf 1.5 *equalsign = 0;
|
709 kumpf 1.2
|
710 kumpf 1.17 if (!CIMName::legal(p))
|
711 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
712 kumpf 1.2
|
713 kumpf 1.17 CIMName keyName (p);
714
|
715 kumpf 1.2 // Get the value part:
716
717 String valueString;
|
718 kumpf 1.5 p = equalsign + 1;
|
719 kumpf 1.16 CIMKeyBinding::Type type;
|
720 kumpf 1.2
|
721 kumpf 1.29 if (*p == '"')
|
722 kumpf 1.2 {
|
723 kumpf 1.29 // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
724
|
725 kumpf 1.2 p++;
726
727 while (*p && *p != '"')
728 {
729 if (*p == '\\')
|
730 kumpf 1.28 {
|
731 kumpf 1.2 *p++;
732
|
733 kumpf 1.28 if ((*p != '\\') && (*p != '"'))
734 {
735 throw MalformedObjectNameException(objectName);
736 }
737 }
738
|
739 kumpf 1.2 valueString.append(*p++);
740 }
741
742 if (*p++ != '"')
|
743 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
744 kumpf 1.2
|
745 kumpf 1.29 /*
746 Guess at the type of this quoted key value. If the value
747 can be parsed into a CIMObjectPath with at least one key
748 binding, the type is assumed to be a REFERENCE. Otherwise,
749 the type is set to STRING. (See method header for details.)
750 */
|
751 kumpf 1.16 type = CIMKeyBinding::STRING;
|
752 kumpf 1.2
|
753 kumpf 1.29 try
|
754 kumpf 1.2 {
|
755 kumpf 1.29 CIMObjectPath testForPath(valueString);
756 if (testForPath.getKeyBindings().size() > 0)
|
757 kumpf 1.28 {
|
758 kumpf 1.29 // We've found a reference value!
759 type = CIMKeyBinding::REFERENCE;
|
760 kumpf 1.28 }
|
761 kumpf 1.2 }
|
762 david.dillard 1.41 catch (const Exception &)
|
763 kumpf 1.29 {
764 // Not a reference value; leave type as STRING
765 }
|
766 kumpf 1.2 }
767 else if (toupper(*p) == 'T' || toupper(*p) == 'F')
768 {
|
769 kumpf 1.16 type = CIMKeyBinding::BOOLEAN;
|
770 kumpf 1.2
771 char* r = p;
772 Uint32 n = 0;
773
774 while (*r && *r != ',')
775 {
776 *r = toupper(*r);
777 r++;
778 n++;
779 }
780
781 if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
782 ((strncmp(p, "FALSE", n) == 0) && n == 5)))
|
783 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
784 kumpf 1.2
785 valueString.assign(p, n);
786
787 p = p + n;
788 }
789 else
790 {
|
791 kumpf 1.16 type = CIMKeyBinding::NUMERIC;
|
792 kumpf 1.2
793 char* r = p;
794 Uint32 n = 0;
795
796 while (*r && *r != ',')
797 {
798 r++;
799 n++;
800 }
801
802 Boolean isComma = false;
803 if (*r)
804 {
805 *r = '\0';
806 isComma = true;
807 }
808
809 Sint64 x;
810
811 if (!XmlReader::stringToSignedInteger(p, x))
|
812 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
813 kumpf 1.2
814 valueString.assign(p, n);
815
816 if (isComma)
817 {
818 *r = ',';
819 }
820
821 p = p + n;
822 }
823
|
824 kumpf 1.17 keyBindings.append(CIMKeyBinding(keyName.getString (), valueString,
825 type));
|
826 kumpf 1.2
827 if (*p)
828 {
829 if (*p++ != ',')
830 {
|
831 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
832 kumpf 1.2 }
833 }
834 }
835
836 _BubbleSort(keyBindings);
837 }
838
|
839 kumpf 1.9 void CIMObjectPath::set(const String& objectName)
|
840 kumpf 1.2 {
841 clear();
842
843 //--------------------------------------------------------------------------
844 // We will extract components from an object name. Here is an sample
845 // object name:
846 //
847 // //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
848 //--------------------------------------------------------------------------
849
850 // Convert to a C String first:
851
|
852 david 1.37 CString pCString = objectName.getCString();
|
853 kumpf 1.26 char* p = const_cast<char*>((const char*) pCString);
|
854 kumpf 1.2 Boolean gotHost;
855 Boolean gotNamespace;
856
857 gotHost = _parseHostElement(objectName, p, _rep->_host);
858 gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
859
860 if (gotHost && !gotNamespace)
861 {
|
862 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
863 kumpf 1.2 }
864
865 // Extract the class name:
866
867 char* dot = strchr(p, '.');
868
869 if (!dot)
870 {
871 if (!CIMName::legal(p))
872 {
|
873 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
874 kumpf 1.2 }
875
876 // ATTN: remove this later: a reference should only be able to hold
877 // an instance name.
878
|
879 kumpf 1.17 _rep->_className = CIMName (p);
|
880 kumpf 1.2 return;
881 }
882
|
883 david 1.27 String className = String(p, (Uint32)(dot - p));
|
884 kumpf 1.7 if (!CIMName::legal(className))
885 {
|
886 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
887 kumpf 1.7 }
888 _rep->_className = className;
|
889 kumpf 1.2
890 // Advance past dot:
891
892 p = dot + 1;
893
894 _parseKeyBindingPairs(objectName, p, _rep->_keyBindings);
895 }
896
897 CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
898 {
899 set(objectName);
900 return *this;
901 }
902
903 const String& CIMObjectPath::getHost() const
904 {
905 return _rep->_host;
906 }
907
908 void CIMObjectPath::setHost(const String& host)
909 {
|
910 kumpf 1.35 if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
911 {
912 throw MalformedObjectNameException(host);
913 }
914
|
915 kumpf 1.2 _rep->_host = host;
916 }
917
|
918 kumpf 1.7 const CIMNamespaceName& CIMObjectPath::getNameSpace() const
|
919 kumpf 1.2 {
920 return _rep->_nameSpace;
921 }
922
|
923 kumpf 1.7 void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
|
924 kumpf 1.2 {
925 _rep->_nameSpace = nameSpace;
926 }
927
|
928 kumpf 1.7 const CIMName& CIMObjectPath::getClassName() const
|
929 kumpf 1.2 {
930 return _rep->_className;
931 }
932
|
933 kumpf 1.7 void CIMObjectPath::setClassName(const CIMName& className)
|
934 kumpf 1.2 {
935 _rep->_className = className;
936 }
937
|
938 kumpf 1.16 const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
|
939 kumpf 1.2 {
940 return _rep->_keyBindings;
941 }
942
|
943 kumpf 1.16 void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
|
944 kumpf 1.2 {
945 _rep->_keyBindings = keyBindings;
946 _BubbleSort(_rep->_keyBindings);
947 }
948
|
949 kumpf 1.15 String CIMObjectPath::toString() const
|
950 kumpf 1.2 {
951 String objectName;
952
953 // Get the host:
954
|
955 kumpf 1.15 if (_rep->_host.size())
|
956 kumpf 1.2 {
957 objectName = "//";
|
958 kumpf 1.13 objectName.append(_rep->_host);
959 objectName.append("/");
|
960 kumpf 1.2 }
961
962 // Get the namespace (if we have a host name, we must write namespace):
963
|
964 kumpf 1.7 if (!_rep->_nameSpace.isNull() || _rep->_host.size())
|
965 kumpf 1.2 {
|
966 kumpf 1.17 objectName.append(_rep->_nameSpace.getString ());
|
967 kumpf 1.13 objectName.append(":");
|
968 kumpf 1.2 }
969
970 // Get the class name:
971
|
972 kumpf 1.17 objectName.append(getClassName().getString ());
|
973 kumpf 1.2
|
974 kumpf 1.9 //
975 // ATTN-CAKG-P2-20020726: The following condition does not correctly
976 // distinguish instanceNames from classNames in every case
977 // The instanceName of a singleton instance of a keyless class has no
978 // key bindings
979 //
980 if (_rep->_keyBindings.size () != 0)
|
981 kumpf 1.2 {
982 objectName.append('.');
983
984 // Append each key-value pair:
985
|
986 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
|
987 kumpf 1.2
988 for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
989 {
|
990 kumpf 1.17 objectName.append(keyBindings[i].getName().getString ());
|
991 kumpf 1.2 objectName.append('=');
992
993 const String& value = _escapeSpecialCharacters(
994 keyBindings[i].getValue());
995
|
996 kumpf 1.16 CIMKeyBinding::Type type = keyBindings[i].getType();
|
997 kumpf 1.2
|
998 kumpf 1.16 if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
|
999 kumpf 1.2 objectName.append('"');
1000
1001 objectName.append(value);
1002
|
1003 kumpf 1.16 if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
|
1004 kumpf 1.2 objectName.append('"');
1005
1006 if (i + 1 != n)
1007 objectName.append(',');
1008 }
1009 }
1010
1011 return objectName;
1012 }
1013
|
1014 kumpf 1.15 String CIMObjectPath::_toStringCanonical() const
|
1015 kumpf 1.2 {
1016 CIMObjectPath ref = *this;
1017
|
1018 kumpf 1.33 // Normalize hostname by changing to lower case
1019 ref._rep->_host.toLower(); // ICU_TODO:
|
1020 kumpf 1.2
|
1021 kumpf 1.33 // Normalize namespace by changing to lower case
1022 if (!ref._rep->_nameSpace.isNull())
1023 {
1024 String nameSpaceLower = ref._rep->_nameSpace.getString();
1025 nameSpaceLower.toLower(); // ICU_TODO:
1026 ref._rep->_nameSpace = nameSpaceLower;
1027 }
1028
1029 // Normalize class name by changing to lower case
1030 if (!ref._rep->_className.isNull())
1031 {
1032 String classNameLower = ref._rep->_className.getString();
1033 classNameLower.toLower(); // ICU_TODO:
1034 ref._rep->_className = classNameLower;
1035 }
|
1036 kumpf 1.2
1037 for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
1038 {
|
1039 kumpf 1.33 // Normalize key binding name by changing to lower case
1040 if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
1041 {
1042 String keyBindingNameLower =
1043 ref._rep->_keyBindings[i]._rep->_name.getString();
1044 keyBindingNameLower.toLower(); // ICU_TODO:
1045 ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
1046 }
1047
1048 // Normalize the key value
1049 switch (ref._rep->_keyBindings[i]._rep->_type)
1050 {
1051 case CIMKeyBinding::REFERENCE:
1052 try
1053 {
1054 // Convert reference to CIMObjectPath and recurse
1055 ref._rep->_keyBindings[i]._rep->_value =
1056 CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
1057 _toStringCanonical();
1058 }
1059 catch (Exception&)
1060 kumpf 1.33 {
1061 // Leave value unchanged if the CIMObjectPath parsing fails
1062 }
1063 break;
1064 case CIMKeyBinding::BOOLEAN:
1065 // Normalize the boolean string by changing to lower case
1066 ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
1067 break;
1068 case CIMKeyBinding::NUMERIC:
1069 // Normalize the numeric string by converting to integer and back
1070 Uint64 uValue;
1071 Sint64 sValue;
1072 // First try converting to unsigned integer
1073 if (XmlReader::stringToUnsignedInteger(
1074 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1075 uValue))
1076 {
1077 char buffer[32]; // Should need 21 chars max
1078 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
1079 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1080 }
1081 kumpf 1.33 // Next try converting to signed integer
1082 else if (XmlReader::stringToSignedInteger(
1083 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1084 sValue))
1085 {
1086 char buffer[32]; // Should need 21 chars max
1087 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
1088 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1089 }
1090 // Leave value unchanged if it cannot be converted to an integer
1091 break;
1092 default: // CIMKeyBinding::STRING
1093 // No normalization required for STRING
1094 break;
1095 }
|
1096 kumpf 1.2 }
1097
|
1098 kumpf 1.33 // Note: key bindings are sorted when set in the CIMObjectPath
|
1099 kumpf 1.12
|
1100 kumpf 1.15 return ref.toString();
|
1101 kumpf 1.2 }
1102
1103 Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
1104 {
1105 return
|
1106 kumpf 1.33 String::equalNoCase(_rep->_host, x._rep->_host) &&
|
1107 kumpf 1.7 _rep->_nameSpace.equal(x._rep->_nameSpace) &&
1108 _rep->_className.equal(x._rep->_className) &&
|
1109 kumpf 1.2 _rep->_keyBindings == x._rep->_keyBindings;
1110 }
1111
1112 Uint32 CIMObjectPath::makeHashCode() const
1113 {
|
1114 kumpf 1.12 return HashFunc<String>::hash(_toStringCanonical());
|
1115 kumpf 1.2 }
1116
1117 Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
1118 {
1119 return x.identical(y);
1120 }
1121
1122 Boolean operator!=(const CIMObjectPath& x, const CIMObjectPath& y)
1123 {
1124 return !operator==(x, y);
1125 }
1126
|
1127 chip 1.1 PEGASUS_NAMESPACE_END
|