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