1 //%/////////////////////////////////////////////////////////////////////////////
3 // Copyright (c) 2000 The Open Group, BMC Software, Tivoli Systems, IBM
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 // DEALINGS IN THE SOFTWARE.
20 //==============================================================================
22 // Author: Mike Brasher (mbrasher@bmc.com)
26 //%/////////////////////////////////////////////////////////////////////////////
30 #include "HashTable.h"
31 #include "CIMReference.h"
34 #include "Destroyer.h"
35 #include "XmlWriter.h"
36 #include "XmlReader.h"
39 PEGASUS_NAMESPACE_BEGIN
41 #define PEGASUS_ARRAY_T CIMReference
42 # include "ArrayImpl.h"
43 #undef PEGASUS_ARRAY_T
45 #define PEGASUS_ARRAY_T KeyBinding
46 # include "ArrayImpl.h"
47 #undef PEGASUS_ARRAY_T
49 // ATTN: add a resolve method to this class to verify that the
50 // reference is correct (that the class name corresponds to a real
51 // class and that the property names are really keys and that all keys
52 // of the class or used. Also be sure that there is a valid conversion
53 // between the string value and the value of that property.
55 static String _escapeSpecialCharacters(const String& str)
59 for (Uint32 i = 0, n = str.size(); i < n; i++)
87 ////////////////////////////////////////////////////////////////////////////////
91 ////////////////////////////////////////////////////////////////////////////////
93 int _Compare(const String& s1_, const String& s2_)
95 const Char16* s1 = s1_.getData();
96 const Char16* s2 = s2_.getData();
100 char c1 = tolower(*s1++);
101 char c2 = tolower(*s2++);
116 static void _BubbleSort(Array<KeyBinding>& x)
123 for (Uint32 i = 0; i < n - 1; i++)
125 for (Uint32 j = 0; j < n - 1; j++)
127 if (_Compare(x[j].getName(), x[j+1].getName()) > 0)
137 ////////////////////////////////////////////////////////////////////////////////
141 ////////////////////////////////////////////////////////////////////////////////
143 KeyBinding::KeyBinding() { }
145 KeyBinding::KeyBinding(const KeyBinding& x)
146 : _name(x._name), _value(x._value), _type(x._type)
151 KeyBinding::KeyBinding(const String& name, const String& value, Type type)
152 : _name(name), _value(value), _type(type)
157 KeyBinding::~KeyBinding()
162 KeyBinding& KeyBinding::operator=(const KeyBinding& x)
170 ////////////////////////////////////////////////////////////////////////////////
174 ////////////////////////////////////////////////////////////////////////////////
176 CIMReference::CIMReference()
181 CIMReference::CIMReference(const CIMReference& x)
182 : _host(x._host), _nameSpace(x._nameSpace),
183 _className(x._className), _keyBindings(x._keyBindings)
185 _BubbleSort(_keyBindings);
188 CIMReference::CIMReference(const String& objectName)
193 CIMReference::CIMReference(const char* objectName)
198 CIMReference::CIMReference(
200 const String& nameSpace,
201 const String& className,
202 const Array<KeyBinding>& keyBindings)
204 set(host, nameSpace, className, keyBindings);
207 CIMReference::~CIMReference()
212 CIMReference& CIMReference::operator=(const CIMReference& x)
217 _nameSpace = x._nameSpace;
218 _className = x._className;
219 _keyBindings = x._keyBindings;
224 void CIMReference::clear()
229 _keyBindings.clear();
232 void CIMReference::set(
234 const String& nameSpace,
235 const String& className,
236 const Array<KeyBinding>& keyBindings)
239 setNameSpace(nameSpace);
240 setClassName(className);
241 setKeyBindings(keyBindings);
244 void CIMReference::set(const String& objectName)
249 _keyBindings.clear();
251 //--------------------------------------------------------------------------
252 // We will extract components from an object name. Here is an sample
255 // //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
256 //--------------------------------------------------------------------------
258 // Convert to a C String first:
260 char* p = objectName.allocateCString();
261 ArrayDestroyer<char> destroyer(p);
263 // See if there is a host name (true if it begins with "//"):
264 // Host is of the from <hostname>-<port> and begins with "//"
265 // and ends with "/":
267 if (p[0] == '/' && p[1] == '/')
271 //----------------------------------------------------------------------
272 // Validate the hostname. Hostnames must match the following
273 // regular expression: "[A-Za-z][A-Za-z0-9-]*"
274 //----------------------------------------------------------------------
279 throw IllformedObjectName(objectName);
283 while (isalnum(*q) || *q == '-')
286 // We now expect a colon (before the port):
289 throw IllformedObjectName(objectName);
293 // Check for a port number:
296 throw IllformedObjectName(objectName);
301 // Check for slash terminating the entire sequence:
304 throw IllformedObjectName(objectName);
306 // Finally, assign the host name:
308 _host.assign(p, q - p);
312 //----------------------------------------------------------------------
313 // Validate the namespace path:
314 //----------------------------------------------------------------------
319 throw IllformedObjectName(objectName);
325 // Pass next next token:
327 if (!*q || (!isalpha(*q) && *q != '_'))
328 throw IllformedObjectName(objectName);
332 while (isalnum(*q) || *q == '_')
336 throw IllformedObjectName(objectName);
347 throw IllformedObjectName(objectName);
350 _nameSpace.assign(p, q - p);
354 // Extract the class name:
356 char* dot = strchr(p, '.');
359 throw IllformedObjectName(objectName);
361 _className.assign(p, dot - p);
367 // Get the key-value pairs:
369 for (p = strtok(p, ","); p; p = strtok(NULL, ","))
371 // Split about the equal sign:
373 char* equal = strchr(p, '=');
376 throw IllformedObjectName(objectName);
384 if (!CIMName::legal(keyString))
385 throw IllformedObjectName(objectName);
387 // Get the value part:
391 KeyBinding::Type type;
397 type = KeyBinding::STRING;
399 while (*q && *q != '"')
401 // ATTN: need to handle special characters here:
406 valueString.append(*q++);
410 throw IllformedObjectName(objectName);
413 throw IllformedObjectName(objectName);
415 else if (toupper(*q) == 'T' || toupper(*q) == 'F')
417 type = KeyBinding::BOOLEAN;
427 if (strcmp(q, "TRUE") != 0 && strcmp(q, "FALSE") != 0)
428 throw IllformedObjectName(objectName);
430 valueString.assign(q);
434 type = KeyBinding::NUMERIC;
438 if (!XmlReader::stringToSignedInteger(q, x))
439 throw IllformedObjectName(objectName);
441 valueString.assign(q);
444 _keyBindings.append(KeyBinding(keyString, valueString, type));
447 _BubbleSort(_keyBindings);
450 void CIMReference::setNameSpace(const String& nameSpace)
454 // check each namespace segment (delimted by '\\') for correctness
455 for(Uint32 i = 0; i < nameSpace.size(); i += temp.size() + 1) {
456 // isolate the segment beginning at i and ending at the first ocurrance of '\\' after i or eos
457 temp = nameSpace.subString(i, nameSpace.subString(i).find('\\'));
459 // check segment for correctness
460 if(!CIMName::legal(temp)) {
461 throw(IllegalName());
465 _nameSpace = nameSpace;
468 void CIMReference::setClassName(const String& className)
470 if (!CIMName::legal(className))
473 _className = className;
476 void CIMReference::setKeyBindings(const Array<KeyBinding>& keyBindings)
478 _keyBindings = keyBindings;
479 _BubbleSort(_keyBindings);
482 String CIMReference::toString() const
488 if (_host.size() && _nameSpace.size())
494 objectName += _nameSpace;
498 // Get the class name:
500 const String& className = getClassName();
501 objectName.append(className);
502 objectName.append('.');
504 // Append each key-value pair:
506 const Array<KeyBinding>& keyBindings = getKeyBindings();
508 for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
510 objectName.append(keyBindings[i].getName());
511 objectName.append('=');
513 const String& value = _escapeSpecialCharacters(
514 keyBindings[i].getValue());
516 KeyBinding::Type type = keyBindings[i].getType();
518 if (type == KeyBinding::STRING)
519 objectName.append('"');
521 objectName.append(value);
523 if (type == KeyBinding::STRING)
524 objectName.append('"');
527 objectName.append(',');
533 String CIMReference::toStringCanonical() const
535 CIMReference ref = *this;
537 ref._className.toLower();
539 for (Uint32 i = 0, n = ref._keyBindings.size(); i < n; i++)
540 ref._keyBindings[i]._name.toLower();
542 return ref.toString();
545 Boolean CIMReference::identical(const CIMReference& x) const
548 String::equal(_host, x._host) &&
549 String::equal(_nameSpace, x._nameSpace) &&
550 CIMName::equal(_className, x._className) &&
551 _keyBindings == x._keyBindings;
554 void CIMReference::nameSpaceToXml(Array<Sint8>& out) const
558 out << "<NAMESPACEPATH>\n";
559 out << "<HOST>" << _host << "</HOST>\n";
562 XmlWriter::appendLocalNameSpaceElement(out, _nameSpace);
565 out << "</NAMESPACEPATH>\n";
568 void CIMReference::localNameSpaceToXml(Array<Sint8>& out) const
570 out << "<LOCALNAMESPACEPATH>\n";
572 char* tmp = _nameSpace.allocateCString();
574 for (char* p = strtok(tmp, "/"); p; p = strtok(NULL, "/"))
576 out << "<NAMESPACE NAME=\"" << p << "\"/>\n";
581 out << "</LOCALNAMESPACEPATH>\n";
584 void CIMReference::classNameToXml(Array<Sint8>& out) const
586 out << "<CLASSNAME NAME=\"" << _className << "\"/>\n";
589 void CIMReference::instanceNameToXml(Array<Sint8>& out) const
591 out << "<INSTANCENAME CLASSNAME=\"" << _className << "\">\n";
593 for (Uint32 i = 0, n = _keyBindings.size(); i < n; i++)
595 out << "<KEYBINDING NAME=\"" << _keyBindings[i].getName() << "\">\n";
597 out << "<KEYVALUE VALUETYPE=\"";
598 out << KeyBinding::typeToString(_keyBindings[i].getType());
601 out << _keyBindings[i].getValue();
602 out << "</KEYVALUE>\n";
604 out << "</KEYBINDING>\n";
607 out << "</INSTANCENAME>\n";
610 void CIMReference::toXml(Array<Sint8>& out) const
612 out << "<VALUE.REFERENCE>\n";
614 // See if it is a class or instance reference (instance references have
615 // key-bindings; class references do not).
617 if (_keyBindings.size())
621 out << "<INSTANCEPATH>\n";
623 instanceNameToXml(out);
624 out << "</INSTANCEPATH>\n";
626 else if (_nameSpace.size())
628 out << "<LOCALINSTANCEPATH>\n";
629 localNameSpaceToXml(out);
630 instanceNameToXml(out);
631 out << "</LOCALINSTANCEPATH>\n";
634 instanceNameToXml(out);
640 out << "<CLASSPATH>\n";
643 out << "</CLASSPATH>";
645 else if (_nameSpace.size())
647 out << "<LOCALCLASSPATH>\n";
650 out << "</LOCALCLASSPATH>";
656 out << "</VALUE.REFERENCE>\n";
659 void CIMReference::print(PEGASUS_STD(ostream)& os) const
663 XmlWriter::indentedPrint(os, tmp.getData());
666 const char* KeyBinding::typeToString(Type type)
670 case KeyBinding::BOOLEAN:
673 case KeyBinding::STRING:
676 case KeyBinding::NUMERIC:
683 Uint32 CIMReference::makeHashCode() const
685 CIMReference ref = *this;
687 ref._className.toLower();
689 for (Uint32 i = 0, n = ref._keyBindings.size(); i < n; i++)
690 ref._keyBindings[i]._name.toLower();
692 return HashFunc<String>::hash(ref.toString());
695 KeyBindingArray CIMReference::getKeyBindingArray()
697 return KeyBindingArray();
700 PEGASUS_NAMESPACE_END