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 kumpf 1.20 default: // Numerics
280 if (getType() != NUMERIC) return false;
|
281 kumpf 1.18 kbValue = XmlReader::stringToValue(0, getValue().getCString(),
282 value.getType());
283 break;
284 }
285 }
|
286 kumpf 1.19 catch (Exception&)
|
287 kumpf 1.18 {
288 return false;
289 }
290
291 return value.equal(kbValue);
292 }
|
293 kumpf 1.2
|
294 kumpf 1.16 Boolean operator==(const CIMKeyBinding& x, const CIMKeyBinding& y)
|
295 kumpf 1.2 {
|
296 kumpf 1.33 // Check that the names and types match
297 if (!(x.getName().equal(y.getName())) ||
298 !(x.getType() == y.getType()))
299 {
300 return false;
301 }
302
303 switch (x.getType())
304 {
305 case CIMKeyBinding::REFERENCE:
306 try
307 {
308 // References should be compared as CIMObjectPaths
309 return (CIMObjectPath(x.getValue()) == CIMObjectPath(y.getValue()));
310 }
311 catch (Exception&)
312 {
313 // If CIMObjectPath parsing fails, just compare strings
|
314 kumpf 1.58 return String::equal(x.getValue(), y.getValue());
|
315 kumpf 1.33 }
316 case CIMKeyBinding::BOOLEAN:
317 // Case-insensitive comparison is sufficient for booleans
|
318 kumpf 1.58 return String::equalNoCase(x.getValue(), y.getValue());
|
319 kumpf 1.33 case CIMKeyBinding::NUMERIC:
320 // Note: This comparison assumes XML syntax for integers
321 // First try comparing as unsigned integers
322 {
323 Uint64 xValue;
324 Uint64 yValue;
|
325 thilo.boehm 1.76 if (StringConversion::stringToUnsignedInteger(
|
326 kumpf 1.33 x.getValue().getCString(), xValue) &&
|
327 thilo.boehm 1.76 StringConversion::stringToUnsignedInteger(
|
328 kumpf 1.33 y.getValue().getCString(), yValue))
329 {
330 return (xValue == yValue);
331 }
332 }
333 // Next try comparing as signed integers
334 {
335 Sint64 xValue;
336 Sint64 yValue;
|
337 thilo.boehm 1.76 if (StringConversion::stringToSignedInteger(
|
338 kumpf 1.33 x.getValue().getCString(), xValue) &&
|
339 thilo.boehm 1.76 StringConversion::stringToSignedInteger(
|
340 kumpf 1.33 y.getValue().getCString(), yValue))
341 {
342 return (xValue == yValue);
343 }
344 }
345 // Note: Keys may not be real values, so don't try comparing as reals
346 // We couldn't parse the numbers, so just compare the strings
|
347 kumpf 1.58 return String::equal(x.getValue(), y.getValue());
|
348 kumpf 1.33 default: // CIMKeyBinding::STRING
|
349 kumpf 1.58 return String::equal(x.getValue(), y.getValue());
|
350 kumpf 1.33 }
351
352 PEGASUS_UNREACHABLE(return false;)
|
353 kumpf 1.2 }
354
355
356 ////////////////////////////////////////////////////////////////////////////////
357 //
358 // CIMObjectPath
359 //
360 ////////////////////////////////////////////////////////////////////////////////
361
|
362 marek 1.64 template<class REP>
363 inline void Ref(REP* rep)
364 {
365 rep->_refCounter++;
366 }
367
368 template<class REP>
369 inline void Unref(REP* rep)
370 {
371 if (rep->_refCounter.decAndTestIfZero())
372 delete rep;
373 }
|
374 kumpf 1.2
|
375 a.arora 1.39 CIMObjectPath::CIMObjectPath()
|
376 kumpf 1.2 {
|
377 a.arora 1.39 _rep = new CIMObjectPathRep();
|
378 kumpf 1.2 }
379
|
380 a.arora 1.39 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x)
|
381 kumpf 1.2 {
|
382 marek 1.64 _rep = x._rep;
383 Ref(_rep);
|
384 kumpf 1.2 }
385
386 CIMObjectPath::CIMObjectPath(const String& objectName)
387 {
388 // Test the objectName out to see if we get an exception
389 CIMObjectPath tmpRef;
390 tmpRef.set(objectName);
|
391 kumpf 1.75
|
392 marek 1.64 _rep = tmpRef._rep;
393 Ref(_rep);
|
394 kumpf 1.2 }
395
396 CIMObjectPath::CIMObjectPath(
397 const String& host,
|
398 kumpf 1.7 const CIMNamespaceName& nameSpace,
399 const CIMName& className,
|
400 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
401 kumpf 1.2 {
402 // Test the objectName out to see if we get an exception
403 CIMObjectPath tmpRef;
404 tmpRef.set(host, nameSpace, className, keyBindings);
|
405 marek 1.64 _rep = tmpRef._rep;
406 Ref(_rep);
|
407 kumpf 1.2 }
408
409 CIMObjectPath::~CIMObjectPath()
410 {
|
411 marek 1.64 Unref(_rep);
|
412 kumpf 1.2 }
413
414 CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
415 {
|
416 marek 1.64 if (x._rep != _rep)
417 {
418 Unref(_rep);
419 _rep = x._rep;
420 Ref(_rep);
421 }
|
422 kumpf 1.2 return *this;
423 }
424
|
425 marek 1.64 static inline CIMObjectPathRep* _copyOnWriteCIMObjectPathRep(
426 CIMObjectPathRep* rep)
427 {
428 if (rep->_refCounter.get() > 1)
429 {
430 CIMObjectPathRep* tmpRep= new CIMObjectPathRep(*rep);
431 Unref(rep);
432 return tmpRep;
433 }
434 else
435 {
436 return rep;
437 }
438 }
439
|
440 kumpf 1.2 void CIMObjectPath::clear()
441 {
|
442 marek 1.64 // If there is more than one reference
443 // remove reference and get a new shiny empty representation
444 if (_rep->_refCounter.get() > 1)
445 {
446 Unref(_rep);
447 _rep = new CIMObjectPathRep();
448 }
449 else
450 {
451 // If there is only one reference
452 // no need to copy the data, we own it
453 // just clear the fields
454 _rep->_host.clear();
455 _rep->_nameSpace.clear();
456 _rep->_className.clear();
457 _rep->_keyBindings.clear();
458 }
|
459 kumpf 1.2 }
460
461 void CIMObjectPath::set(
462 const String& host,
|
463 kumpf 1.7 const CIMNamespaceName& nameSpace,
464 const CIMName& className,
|
465 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
466 kumpf 1.2 {
|
467 marek 1.64 if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
468 {
|
469 karl 1.76.4.1 MessageLoaderParms mlParms(
470 "Common.CIMObjectPath.INVALID_HOSTNAME",
471 "$0, reason:\"invalid hostname\"",
472 host);
473
474 throw MalformedObjectNameException(mlParms);
|
475 marek 1.64 }
|
476 kumpf 1.75
|
477 marek 1.64 _rep = _copyOnWriteCIMObjectPathRep(_rep);
478
479 _rep->_host.assign(host);
480 _rep->_nameSpace = nameSpace;
481 _rep->_className = className;
482 _rep->_keyBindings = keyBindings;
|
483 marek 1.66 _Sort(_rep->_keyBindings);
|
484 kumpf 1.2 }
485
|
486 kumpf 1.22 Boolean _parseHostElement(
|
487 kumpf 1.2 const String& objectName,
488 char*& p,
|
489 kumpf 1.9 String& host)
|
490 kumpf 1.2 {
491 // See if there is a host name (true if it begins with "//"):
|
492 kumpf 1.32 // Host is of the form <hostname>:<port> and begins with "//"
|
493 kumpf 1.2 // and ends with "/":
494
495 if (p[0] != '/' || p[1] != '/')
496 {
497 return false;
498 }
499
500 p += 2;
501
|
502 kumpf 1.34 char* slash = strchr(p, '/');
503 if (!slash)
|
504 chuck 1.23 {
|
505 karl 1.76.4.1 MessageLoaderParms mlParms(
506 "Common.CIMObjectPath.MISSING_SLASH_AFTER_HOST",
507 "$0, reason:\"missing slash after hostname\"",
508 objectName);
509 throw MalformedObjectNameException(mlParms);
|
510 kumpf 1.2 }
511
|
512 kumpf 1.34 String hostname = String(p, (Uint32)(slash - p));
513 if (!CIMObjectPathRep::isValidHostname(hostname))
|
514 kumpf 1.2 {
|
515 karl 1.76.4.1 MessageLoaderParms mlParms(
516 "Common.CIMObjectPath.INVALID_HOSTNAME",
517 "$0, reason:\"invalid hostname\"",
518 objectName);
519 throw MalformedObjectNameException(mlParms);
|
520 kumpf 1.2 }
|
521 kumpf 1.34 host = hostname;
|
522 kumpf 1.2
|
523 kumpf 1.31 // Do not step past the '/'; it will be consumed by the namespace parser
|
524 kumpf 1.34 p = slash;
|
525 kumpf 1.2
526 return true;
527 }
528
|
529 kumpf 1.22 Boolean _parseNamespaceElement(
|
530 kumpf 1.2 const String& objectName,
531 char*& p,
|
532 kumpf 1.7 CIMNamespaceName& nameSpace)
|
533 kumpf 1.2 {
534 // If we don't find a valid namespace name followed by a ':', we
535 // assume we're not looking at a namespace name.
536
|
537 kumpf 1.7 char* colon = strchr(p, ':');
538 if (!colon)
539 {
540 return false;
541 }
542
|
543 chip 1.47 // A ':' as part of a keybinding value should not be interpreted as
|
544 kumpf 1.25 // a namespace delimiter. Since keybinding pairs follow the first '.'
545 // in the object path string, the ':' delimiter only counts if it
546 // appears before the '.'.
547
548 char* dot = strchr(p, '.');
549 if (dot && (dot < colon))
550 {
551 return false;
552 }
553
|
554 kumpf 1.2 //----------------------------------------------------------------------
555 // Validate the namespace path. Namespaces must match the following
556 // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
557 //----------------------------------------------------------------------
558
|
559 david 1.27 String namespaceName = String(p, (Uint32)(colon - p));
|
560 kumpf 1.7 if (!CIMNamespaceName::legal(namespaceName))
|
561 kumpf 1.2 {
|
562 karl 1.76.4.1 MessageLoaderParms mlParms(
563 "Common.CIMObjectPath.INVALID_NAMESPACE",
564 "$0, reason:\"invalid namespace name\"",
565 objectName);
566 throw MalformedObjectNameException(mlParms);
|
567 kumpf 1.2 }
|
568 kumpf 1.7 nameSpace = namespaceName;
|
569 kumpf 1.2
|
570 kumpf 1.7 p = colon+1;
|
571 kumpf 1.2 return true;
572 }
573
574 /**
|
575 kumpf 1.29 ATTN-RK: The DMTF specification for the string form of an
576 object path makes it impossible for a parser to distinguish
577 between a key values of String type and Reference type.
578
579 Given the ambiguity, this implementation takes a guess at the
580 type of a quoted key value. If the value can be parsed into
581 a CIMObjectPath with at least one key binding, the type is
582 set to REFERENCE. Otherwise, the type is set to STRING.
583 Note: This algorithm appears to be in line with what the Sun
584 WBEM Services implementation does.
585
586 To be totally correct, it would be necessary to retrieve the
587 class definition and look up the types of the key properties
588 to determine how to interpret the key values. This is clearly
589 too inefficient for internal transformations between
590 CIMObjectPaths and String values.
|
591 kumpf 1.2 */
|
592 kumpf 1.22 void _parseKeyBindingPairs(
|
593 kumpf 1.2 const String& objectName,
594 char*& p,
|
595 chip 1.47 Array<CIMKeyBinding>& keyBindings)
|
596 kumpf 1.2 {
597 // Get the key-value pairs:
598
599 while (*p)
600 {
601 // Get key part:
602
|
603 kumpf 1.5 char* equalsign = strchr(p, '=');
604 if (!equalsign)
|
605 kumpf 1.2 {
|
606 karl 1.76.4.1 MessageLoaderParms mlParms(
607 "Common.CIMObjectPath.INVALID_KEYVALUEPAIR",
608 "$0, reason:\"invalid key-value pair, missing equal sign\"",
609 objectName);
610 throw MalformedObjectNameException(mlParms);
|
611 kumpf 1.2 }
612
|
613 kumpf 1.5 *equalsign = 0;
|
614 kumpf 1.2
|
615 kumpf 1.17 if (!CIMName::legal(p))
|
616 karl 1.76.4.1 {
617 MessageLoaderParms mlParms(
618 "Common.CIMObjectPath.INVALID_KEYNAME",
619 "$0, reason:\"invalid key-value pair, invalid key name:$1\"",
620 objectName,
621 p);
622 throw MalformedObjectNameException(mlParms);
623 }
|
624 kumpf 1.2
|
625 kumpf 1.17 CIMName keyName (p);
626
|
627 kumpf 1.2 // Get the value part:
628
629 String valueString;
|
630 kumpf 1.5 p = equalsign + 1;
|
631 kumpf 1.16 CIMKeyBinding::Type type;
|
632 kumpf 1.2
|
633 kumpf 1.29 if (*p == '"')
|
634 kumpf 1.2 {
|
635 kumpf 1.29 // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
636
|
637 kumpf 1.2 p++;
638
|
639 marek 1.68 Buffer keyValueUTF8(128);
|
640 kumpf 1.62
|
641 kumpf 1.2 while (*p && *p != '"')
642 {
643 if (*p == '\\')
|
644 kumpf 1.28 {
|
645 kumpf 1.62 p++;
|
646 kumpf 1.2
|
647 kumpf 1.28 if ((*p != '\\') && (*p != '"'))
648 {
|
649 karl 1.76.4.1 MessageLoaderParms mlParms(
650 "Common.CIMObjectPath.INVALID_KEYVALUE",
651 "$0, reason:\"invalid key-value pair, "
652 "malformed value\"",
653 objectName);
654 throw MalformedObjectNameException(mlParms);
|
655 kumpf 1.28 }
656 }
657
|
658 kumpf 1.62 keyValueUTF8.append(*p++);
|
659 kumpf 1.2 }
660
661 if (*p++ != '"')
|
662 karl 1.76.4.3 {
|
663 karl 1.76.4.1 MessageLoaderParms mlParms(
664 "Common.CIMObjectPath.INVALID_KEYVALUEPAIR_MISSINGQUOTE",
665 "$0, reason:\"invalid key-value pair, "
666 "missing quote in key value\"",
667 objectName);
668 throw MalformedObjectNameException(mlParms);
669 }
|
670 kumpf 1.2
|
671 kumpf 1.62 // Convert the UTF-8 value to a UTF-16 String
672
673 valueString.assign(
674 (const char*)keyValueUTF8.getData(),
675 keyValueUTF8.size());
676
|
677 kumpf 1.29 /*
678 Guess at the type of this quoted key value. If the value
679 can be parsed into a CIMObjectPath with at least one key
680 binding, the type is assumed to be a REFERENCE. Otherwise,
681 the type is set to STRING. (See method header for details.)
682 */
|
683 kumpf 1.16 type = CIMKeyBinding::STRING;
|
684 kumpf 1.2
|
685 marek 1.68 /* Performance shortcut will check for
686 equal sign instead of doing the full
687 CIMObjectPath creation and exception handling
688 */
689 if (strchr(keyValueUTF8.getData(), '='))
|
690 kumpf 1.2 {
|
691 marek 1.68 // found an equal sign, high probability for a reference
692 try
|
693 kumpf 1.28 {
|
694 marek 1.68 CIMObjectPath testForPath(valueString);
695 if (testForPath.getKeyBindings().size() > 0)
696 {
697 // We've found a reference value!
698 type = CIMKeyBinding::REFERENCE;
699 }
700 }
701 catch (const Exception &)
702 {
703 // Not a reference value; leave type as STRING
|
704 kumpf 1.28 }
|
705 kumpf 1.2 }
706 }
707 else if (toupper(*p) == 'T' || toupper(*p) == 'F')
708 {
|
709 kumpf 1.16 type = CIMKeyBinding::BOOLEAN;
|
710 kumpf 1.2
711 char* r = p;
712 Uint32 n = 0;
713
714 while (*r && *r != ',')
715 {
716 *r = toupper(*r);
717 r++;
718 n++;
719 }
720
721 if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
722 ((strncmp(p, "FALSE", n) == 0) && n == 5)))
|
723 karl 1.76.4.3 {
|
724 karl 1.76.4.1 MessageLoaderParms mlParms(
725 "Common.CIMObjectPath.INVALID_BOOLVALUE",
726 "$0, reason:\"invalid key-value pair, "
727 "value should be TRUE or FALSE\"",
728 objectName);
729 throw MalformedObjectNameException(mlParms);
730 }
|
731 kumpf 1.2
732 valueString.assign(p, n);
733
734 p = p + n;
735 }
736 else
737 {
|
738 kumpf 1.16 type = CIMKeyBinding::NUMERIC;
|
739 kumpf 1.2
740 char* r = p;
741 Uint32 n = 0;
742
743 while (*r && *r != ',')
744 {
745 r++;
746 n++;
747 }
748
749 Boolean isComma = false;
750 if (*r)
751 {
752 *r = '\0';
753 isComma = true;
754 }
755
|
756 r.kieninger 1.56 if (*p == '-')
757 {
758 Sint64 x;
|
759 thilo.boehm 1.76 if (!StringConversion::stringToSignedInteger(p, x))
|
760 karl 1.76.4.3 {
|
761 karl 1.76.4.1 MessageLoaderParms mlParms(
762 "Common.CIMObjectPath.INVALID_NEGATIVNUMBER_VALUE",
763 "$0, reason:\"invalid key-value pair, "
764 "invalid negative number value $1\"",
765 objectName,
766 p);
767 throw MalformedObjectNameException(mlParms);
768 }
|
769 r.kieninger 1.56 }
770 else
771 {
772 Uint64 x;
|
773 thilo.boehm 1.76 if (!StringConversion::stringToUnsignedInteger(p, x))
|
774 karl 1.76.4.3 {
|
775 karl 1.76.4.1 MessageLoaderParms mlParms(
776 "Common.CIMObjectPath.INVALID_NEGATIVNUMBER_VALUE",
777 "$0, reason:\"invalid key-value pair, "
778 "invalid number value $1\"",
779 objectName,
780 p);
781 throw MalformedObjectNameException(mlParms);
782 }
|
783 r.kieninger 1.56 }
|
784 kumpf 1.2
785 valueString.assign(p, n);
786
787 if (isComma)
788 {
789 *r = ',';
790 }
791
792 p = p + n;
793 }
794
|
795 chip 1.47 keyBindings.append(CIMKeyBinding(keyName.getString (), valueString,
|
796 kumpf 1.17 type));
|
797 kumpf 1.2
798 if (*p)
799 {
800 if (*p++ != ',')
801 {
|
802 karl 1.76.4.1 MessageLoaderParms mlParms(
803 "Common.CIMObjectPath.INVALID_KEYVALUEPAIR_MISSCOMMA",
804 "$0, reason:\"invalid key-value pair, "
805 "next key-value pair has to start with comma\"",
806 objectName);
807 throw MalformedObjectNameException(mlParms);
|
808 kumpf 1.2 }
809 }
810 }
811
|
812 marek 1.66 _Sort(keyBindings);
|
813 kumpf 1.2 }
814
|
815 chip 1.47 void CIMObjectPath::set(const String& objectName)
|
816 kumpf 1.2 {
|
817 marek 1.64 // the clear automatically ensures
818 // we have our own copy of the representation
|
819 kumpf 1.2 clear();
820
821 //--------------------------------------------------------------------------
822 // We will extract components from an object name. Here is an sample
823 // object name:
824 //
825 // //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
826 //--------------------------------------------------------------------------
827
828 // Convert to a C String first:
829
|
830 david 1.37 CString pCString = objectName.getCString();
|
831 kumpf 1.26 char* p = const_cast<char*>((const char*) pCString);
|
832 kumpf 1.2 Boolean gotHost;
833 Boolean gotNamespace;
834
835 gotHost = _parseHostElement(objectName, p, _rep->_host);
836 gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
837
838 if (gotHost && !gotNamespace)
839 {
|
840 karl 1.76.4.1 MessageLoaderParms mlParms(
841 "Common.CIMObjectPath.MISSING_NAMESPACE",
842 "$0, reason:\"host specified, missing namespace\"",
843 objectName);
844 throw MalformedObjectNameException(mlParms);
|
845 kumpf 1.2 }
846
847 // Extract the class name:
848
849 char* dot = strchr(p, '.');
850
851 if (!dot)
852 {
853 if (!CIMName::legal(p))
854 {
|
855 karl 1.76.4.1 MessageLoaderParms mlParms(
856 "Common.CIMObjectPath.INVALID_CLASSNAME",
857 "$0, reason:\"class name $1 not a legal CIM name\"",
858 objectName,
859 p);
860 throw MalformedObjectNameException(mlParms);
|
861 kumpf 1.2 }
862
863 // ATTN: remove this later: a reference should only be able to hold
864 // an instance name.
865
|
866 kumpf 1.17 _rep->_className = CIMName (p);
|
867 kumpf 1.2 return;
868 }
869
|
870 david 1.27 String className = String(p, (Uint32)(dot - p));
|
871 kumpf 1.7 if (!CIMName::legal(className))
872 {
|
873 karl 1.76.4.1 MessageLoaderParms mlParms(
874 "Common.CIMObjectPath.INVALID_CLASSNAME",
875 "$0, reason:\"class name $1 not a legal CIM name\"",
876 objectName,
877 className);
878 throw MalformedObjectNameException(mlParms);
|
879 kumpf 1.7 }
880 _rep->_className = className;
|
881 kumpf 1.2
882 // Advance past dot:
883
884 p = dot + 1;
885
886 _parseKeyBindingPairs(objectName, p, _rep->_keyBindings);
887 }
888
889 CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
890 {
|
891 marek 1.64 // set will call clear, which will cause copyOnWrite if necessary
|
892 kumpf 1.2 set(objectName);
893 return *this;
894 }
895
896 const String& CIMObjectPath::getHost() const
897 {
898 return _rep->_host;
899 }
900
901 void CIMObjectPath::setHost(const String& host)
902 {
|
903 marek 1.65 if ((host != String::EMPTY) &&
904 (host != System::getHostName()) &&
905 !CIMObjectPathRep::isValidHostname(host))
|
906 kumpf 1.35 {
|
907 karl 1.76.4.1 MessageLoaderParms mlParms(
908 "Common.CIMObjectPath.INVALID_HOSTNAME",
909 "$0, reason:\"invalid hostname\"",
910 host);
911 throw MalformedObjectNameException(mlParms);
|
912 kumpf 1.35 }
|
913 marek 1.64 _rep = _copyOnWriteCIMObjectPathRep(_rep);
|
914 kumpf 1.35
|
915 kumpf 1.2 _rep->_host = host;
916 }
917
|
918 kumpf 1.7 const CIMNamespaceName& CIMObjectPath::getNameSpace() const
|
919 kumpf 1.2 {
920 return _rep->_nameSpace;
921 }
922
|
923 kumpf 1.7 void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
|
924 kumpf 1.2 {
|
925 marek 1.64 _rep = _copyOnWriteCIMObjectPathRep(_rep);
|
926 kumpf 1.2 _rep->_nameSpace = nameSpace;
927 }
928
|
929 kumpf 1.7 const CIMName& CIMObjectPath::getClassName() const
|
930 kumpf 1.2 {
931 return _rep->_className;
932 }
933
|
934 kumpf 1.7 void CIMObjectPath::setClassName(const CIMName& className)
|
935 kumpf 1.2 {
|
936 marek 1.64 _rep = _copyOnWriteCIMObjectPathRep(_rep);
|
937 kumpf 1.2 _rep->_className = className;
938 }
939
|
940 kumpf 1.16 const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
|
941 kumpf 1.2 {
942 return _rep->_keyBindings;
943 }
944
|
945 kumpf 1.16 void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
|
946 kumpf 1.2 {
|
947 marek 1.64 _rep = _copyOnWriteCIMObjectPathRep(_rep);
|
948 kumpf 1.2 _rep->_keyBindings = keyBindings;
|
949 marek 1.66 _Sort(_rep->_keyBindings);
|
950 kumpf 1.2 }
951
|
952 kumpf 1.15 String CIMObjectPath::toString() const
|
953 kumpf 1.2 {
954 String objectName;
955
956 // Get the host:
957
|
958 kumpf 1.15 if (_rep->_host.size())
|
959 kumpf 1.2 {
960 objectName = "//";
|
961 kumpf 1.13 objectName.append(_rep->_host);
962 objectName.append("/");
|
963 kumpf 1.2 }
964
965 // Get the namespace (if we have a host name, we must write namespace):
966
|
967 kumpf 1.7 if (!_rep->_nameSpace.isNull() || _rep->_host.size())
|
968 kumpf 1.2 {
|
969 kumpf 1.17 objectName.append(_rep->_nameSpace.getString ());
|
970 kumpf 1.13 objectName.append(":");
|
971 kumpf 1.2 }
972
973 // Get the class name:
974
|
975 kumpf 1.17 objectName.append(getClassName().getString ());
|
976 kumpf 1.2
|
977 kumpf 1.9 //
978 // ATTN-CAKG-P2-20020726: The following condition does not correctly
979 // distinguish instanceNames from classNames in every case
980 // The instanceName of a singleton instance of a keyless class has no
|
981 karl 1.76.4.3 // key bindings. See BUG_3302
|
982 kumpf 1.9 //
983 if (_rep->_keyBindings.size () != 0)
|
984 kumpf 1.2 {
985 objectName.append('.');
986
987 // Append each key-value pair:
988
|
989 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
|
990 kumpf 1.2
991 for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
992 {
|
993 kumpf 1.17 objectName.append(keyBindings[i].getName().getString ());
|
994 kumpf 1.2 objectName.append('=');
995
996 const String& value = _escapeSpecialCharacters(
997 keyBindings[i].getValue());
998
|
999 kumpf 1.16 CIMKeyBinding::Type type = keyBindings[i].getType();
|
1000 chip 1.47
|
1001 kumpf 1.57 if (type == CIMKeyBinding::STRING ||
1002 type == CIMKeyBinding::REFERENCE)
|
1003 kumpf 1.2 objectName.append('"');
1004
1005 objectName.append(value);
1006
|
1007 kumpf 1.57 if (type == CIMKeyBinding::STRING ||
1008 type == CIMKeyBinding::REFERENCE)
|
1009 kumpf 1.2 objectName.append('"');
1010
1011 if (i + 1 != n)
1012 objectName.append(',');
1013 }
1014 }
1015
1016 return objectName;
1017 }
1018
|
1019 kumpf 1.15 String CIMObjectPath::_toStringCanonical() const
|
1020 kumpf 1.2 {
|
1021 marek 1.64 CIMObjectPath ref;
1022 *ref._rep = *this->_rep;
|
1023 kumpf 1.2
|
1024 kumpf 1.33 // Normalize hostname by changing to lower case
|
1025 chip 1.47 ref._rep->_host.toLower(); // ICU_TODO:
|
1026 kumpf 1.2
|
1027 kumpf 1.33 // Normalize namespace by changing to lower case
1028 if (!ref._rep->_nameSpace.isNull())
1029 {
1030 String nameSpaceLower = ref._rep->_nameSpace.getString();
|
1031 chip 1.47 nameSpaceLower.toLower(); // ICU_TODO:
|
1032 kumpf 1.33 ref._rep->_nameSpace = nameSpaceLower;
1033 }
1034
1035 // Normalize class name by changing to lower case
1036 if (!ref._rep->_className.isNull())
1037 {
1038 String classNameLower = ref._rep->_className.getString();
|
1039 chip 1.47 classNameLower.toLower(); // ICU_TODO:
|
1040 kumpf 1.33 ref._rep->_className = classNameLower;
1041 }
|
1042 kumpf 1.2
1043 for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
1044 {
|
1045 kumpf 1.33 // Normalize key binding name by changing to lower case
1046 if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
1047 {
|
1048 chip 1.47 String keyBindingNameLower =
|
1049 kumpf 1.33 ref._rep->_keyBindings[i]._rep->_name.getString();
1050 keyBindingNameLower.toLower(); // ICU_TODO:
1051 ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
1052 }
1053
1054 // Normalize the key value
1055 switch (ref._rep->_keyBindings[i]._rep->_type)
1056 {
1057 case CIMKeyBinding::REFERENCE:
1058 try
1059 {
1060 // Convert reference to CIMObjectPath and recurse
1061 ref._rep->_keyBindings[i]._rep->_value =
1062 CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
1063 _toStringCanonical();
1064 }
1065 catch (Exception&)
1066 {
1067 // Leave value unchanged if the CIMObjectPath parsing fails
1068 }
1069 break;
1070 kumpf 1.33 case CIMKeyBinding::BOOLEAN:
1071 // Normalize the boolean string by changing to lower case
1072 ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
1073 break;
1074 case CIMKeyBinding::NUMERIC:
1075 // Normalize the numeric string by converting to integer and back
1076 Uint64 uValue;
1077 Sint64 sValue;
1078 // First try converting to unsigned integer
|
1079 thilo.boehm 1.76 if (StringConversion::stringToUnsignedInteger(
|
1080 kumpf 1.33 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1081 uValue))
1082 {
1083 char buffer[32]; // Should need 21 chars max
1084 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
1085 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1086 }
1087 // Next try converting to signed integer
|
1088 thilo.boehm 1.76 else if (StringConversion::stringToSignedInteger(
|
1089 kumpf 1.33 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1090 sValue))
1091 {
1092 char buffer[32]; // Should need 21 chars max
1093 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
1094 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1095 }
1096 // Leave value unchanged if it cannot be converted to an integer
1097 break;
1098 default: // CIMKeyBinding::STRING
1099 // No normalization required for STRING
1100 break;
1101 }
|
1102 kumpf 1.2 }
1103
|
1104 kumpf 1.33 // Note: key bindings are sorted when set in the CIMObjectPath
|
1105 kumpf 1.12
|
1106 kumpf 1.15 return ref.toString();
|
1107 kumpf 1.2 }
1108
1109 Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
1110 {
1111 return
|
1112 kumpf 1.63 (_rep == x._rep) ||
1113 (String::equalNoCase(_rep->_host, x._rep->_host) &&
1114 _rep->_nameSpace.equal(x._rep->_nameSpace) &&
1115 _rep->_className.equal(x._rep->_className) &&
1116 (_rep->_keyBindings == x._rep->_keyBindings));
|
1117 kumpf 1.2 }
1118
1119 Uint32 CIMObjectPath::makeHashCode() const
1120 {
|
1121 kumpf 1.12 return HashFunc<String>::hash(_toStringCanonical());
|
1122 kumpf 1.2 }
1123
1124 Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
1125 {
1126 return x.identical(y);
1127 }
1128
1129 Boolean operator!=(const CIMObjectPath& x, const CIMObjectPath& y)
1130 {
1131 return !operator==(x, y);
1132 }
1133
|
1134 chip 1.1 PEGASUS_NAMESPACE_END
|