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