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