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