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