(file) Return to CIMObjectPath.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

Diff for /pegasus/src/Pegasus/Common/CIMObjectPath.cpp between version 1.2 and 1.73

version 1.2, 2002/05/16 03:07:02 version 1.73, 2008/12/01 17:49:48
Line 1 
Line 1 
 //%/////////////////////////////////////////////////////////////////////////////  //%LICENSE////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001 The Open group, BMC Software, Tivoli Systems, IBM  // Licensed to The Open Group (TOG) under one or more contributor license
   // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
   // this work for additional information regarding copyright ownership.
   // Each contributor licenses this file to you under the OpenPegasus Open
   // Source License; you may not use this file except in compliance with the
   // License.
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a copy  // Permission is hereby granted, free of charge, to any person obtaining a
 // of this software and associated documentation files (the "Software"), to  // copy of this software and associated documentation files (the "Software"),
 // deal in the Software without restriction, including without limitation the  // to deal in the Software without restriction, including without limitation
 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  // the rights to use, copy, modify, merge, publish, distribute, sublicense,
 // sell copies of the Software, and to permit persons to whom the Software is  // and/or sell copies of the Software, and to permit persons to whom the
 // furnished to do so, subject to the following conditions:  // Software is furnished to do so, subject to the following conditions:
 //  
 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN  
 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED  
 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT  
 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR  
 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT  
 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN  
 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION  
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
 // //
 //==============================================================================  // The above copyright notice and this permission notice shall be included
   // in all copies or substantial portions of the Software.
 // //
 // Author: Mike Brasher (mbrasher@bmc.com)  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 // //
 // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)  //////////////////////////////////////////////////////////////////////////
 // //
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
 #include <Pegasus/Common/Config.h> #include <Pegasus/Common/Config.h>
 #include <cctype>  
 #include <cstring> #include <cstring>
   #include <iostream>
 #include "HashTable.h" #include "HashTable.h"
 #include "CIMObjectPath.h" #include "CIMObjectPath.h"
 #include "Indentor.h"  
 #include "CIMName.h" #include "CIMName.h"
 #include "Destroyer.h"  #include "CIMValue.h"
 #include "XmlWriter.h"  
 #include "XmlReader.h" #include "XmlReader.h"
 #include "Array.h"  #include "ArrayInternal.h"
 #include "CIMOMPort.h"  #include "HostLocator.h"
   #include "System.h"
   #include "CIMKeyBindingRep.h"
   #include "CIMObjectPathRep.h"
  
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
  
 #define PEGASUS_ARRAY_T KeyBinding  #define PEGASUS_ARRAY_T CIMKeyBinding
 # include "ArrayImpl.h" # include "ArrayImpl.h"
 #undef PEGASUS_ARRAY_T #undef PEGASUS_ARRAY_T
  
Line 73 
Line 77 
     {     {
         switch (str[i])         switch (str[i])
         {         {
             case '\n':              case '\\':
                 result += "\\n";                  result.append("\\\\");
                 break;  
   
             case '\r':  
                 result += "\\r";  
                 break;  
   
             case '\t':  
                 result += "\\t";  
                 break;                 break;
  
             case '"':             case '"':
                 result += "\\\"";                  result.append("\\\"");
                 break;                 break;
  
             default:             default:
                 result += str[i];                  result.append(str[i]);
         }         }
     }     }
  
     return result;     return result;
 } }
  
 static void _BubbleSort(Array<KeyBinding>& x)  static int _compare(const void* p1, const void* p2)
 { {
     Uint32 n = x.size();      const CIMKeyBinding* kb1 = (const CIMKeyBinding*)p1;
       const CIMKeyBinding* kb2 = (const CIMKeyBinding*)p2;
  
     if (n < 2)      return String::compareNoCase(
         return;          kb1->getName().getString(),
           kb2->getName().getString());
   }
  
     for (Uint32 i = 0; i < n - 1; i++)  static void _Sort(Array<CIMKeyBinding>& x)
     {     {
         for (Uint32 j = 0; j < n - 1; j++)      CIMKeyBinding* data = (CIMKeyBinding*)x.getData();
       Uint32 size = x.size();
   
       //
       //  If the key is a reference, the keys in the reference must also be
       //  sorted
       //
       for (Uint32 k = 0; k < size; k++)
         {         {
             if (String::compareNoCase(x[j].getName(), x[j+1].getName()) > 0)          CIMKeyBinding& kb = data[k];
   
           if (kb.getType() == CIMKeyBinding::REFERENCE)
             {             {
                 KeyBinding t = x[j];              CIMObjectPath tmp(kb.getValue());
                 x[j] = x[j+1];              Array<CIMKeyBinding> keyBindings = tmp.getKeyBindings();
                 x[j+1] = t;              _Sort(keyBindings);
             }              tmp.setKeyBindings(keyBindings);
               kb.setValue(tmp.toString());
         }         }
     }     }
   
       if (size < 2)
           return;
   
       qsort((void*)data, size, sizeof(CIMKeyBinding), _compare);
 } }
  
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
 // //
 // KeyBinding  // CIMKeyBinding
 // //
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
  
 class KeyBindingRep  CIMKeyBinding::CIMKeyBinding()
 {  
 public:  
     KeyBindingRep()  
     {     {
       _rep = new CIMKeyBindingRep();
     }     }
  
     KeyBindingRep(const KeyBindingRep& x)  CIMKeyBinding::CIMKeyBinding(const CIMKeyBinding& x)
         : _name(x._name), _value(x._value), _type(x._type)  
     {     {
       _rep = new CIMKeyBindingRep(*x._rep);
     }     }
  
     KeyBindingRep(  CIMKeyBinding::CIMKeyBinding(
         const String& name,      const CIMName& name,
         const String& value,         const String& value,
         KeyBinding::Type type)      Type type)
         : _name(name), _value(value), _type(type)  
     {     {
       _rep = new CIMKeyBindingRep(name, value, type);
     }     }
  
     ~KeyBindingRep()  CIMKeyBinding::CIMKeyBinding(const CIMName& name, const CIMValue& value)
     {     {
     }      if (value.isArray())
   
     KeyBindingRep& operator=(const KeyBindingRep& x)  
     {     {
         if (&x != this)          throw TypeMismatchException();
         {  
             _name = x._name;  
             _value = x._value;  
             _type = x._type;  
         }  
         return *this;  
     }     }
  
     String _name;      String kbValue = value.toString();
     String _value;      Type kbType;
     KeyBinding::Type _type;  
 };  
   
  
 KeyBinding::KeyBinding()      switch (value.getType())
 { {
     _rep = new KeyBindingRep();      case CIMTYPE_BOOLEAN:
 }          kbType = BOOLEAN;
           break;
 KeyBinding::KeyBinding(const KeyBinding& x)      case CIMTYPE_CHAR16:
 {      case CIMTYPE_STRING:
     _rep = new KeyBindingRep(*x._rep);      case CIMTYPE_DATETIME:
           kbType = STRING;
           break;
       case CIMTYPE_REFERENCE:
           kbType = REFERENCE;
           break;
   //  case CIMTYPE_REAL32:
   //  case CIMTYPE_REAL64:
       case CIMTYPE_OBJECT:
       case CIMTYPE_INSTANCE:
           // From PEP 194: EmbeddedObjects cannot be keys.
           throw TypeMismatchException();
           break;
       default:
           kbType = NUMERIC;
           break;
 } }
  
 KeyBinding::KeyBinding(const String& name, const String& value, Type type)      _rep = new CIMKeyBindingRep(name, kbValue, kbType);
 {  
     _rep = new KeyBindingRep(name, value, type);  
 } }
  
 KeyBinding::~KeyBinding()  CIMKeyBinding::~CIMKeyBinding()
 { {
     delete _rep;     delete _rep;
 } }
  
 KeyBinding& KeyBinding::operator=(const KeyBinding& x)  CIMKeyBinding& CIMKeyBinding::operator=(const CIMKeyBinding& x)
 { {
     *_rep = *x._rep;     *_rep = *x._rep;
     return *this;     return *this;
 } }
  
 const String& KeyBinding::getName() const  const CIMName& CIMKeyBinding::getName() const
 { {
     return _rep->_name;     return _rep->_name;
 } }
  
 void KeyBinding::setName(const String& name)  void CIMKeyBinding::setName(const CIMName& name)
 { {
     _rep->_name = name;     _rep->_name = name;
 } }
  
 const String& KeyBinding::getValue() const  const String& CIMKeyBinding::getValue() const
 { {
     return _rep->_value;     return _rep->_value;
 } }
  
 void KeyBinding::setValue(const String& value)  void CIMKeyBinding::setValue(const String& value)
 { {
     _rep->_value = value;     _rep->_value = value;
 } }
  
 KeyBinding::Type KeyBinding::getType() const  CIMKeyBinding::Type CIMKeyBinding::getType() const
 { {
     return _rep->_type;     return _rep->_type;
 } }
  
 void KeyBinding::setType(KeyBinding::Type type)  void CIMKeyBinding::setType(CIMKeyBinding::Type type)
 { {
     _rep->_type = type;     _rep->_type = type;
 } }
  
 const char* KeyBinding::typeToString(KeyBinding::Type type)  Boolean CIMKeyBinding::equal(CIMValue value)
 { {
     switch (type)      if (value.isArray())
     {     {
         case KeyBinding::BOOLEAN:          return false;
             return "boolean";      }
   
         case KeyBinding::STRING:  
             return "string";  
  
         case KeyBinding::NUMERIC:      CIMValue kbValue;
             return "numeric";  
  
         case KeyBinding::REFERENCE:      try
         default:      {
             PEGASUS_ASSERT(false);          switch (value.getType())
           {
           case CIMTYPE_CHAR16:
               if (getType() != STRING) return false;
               kbValue.set(getValue()[0]);
               break;
           case CIMTYPE_DATETIME:
               if (getType() != STRING) return false;
               kbValue.set(CIMDateTime(getValue()));
               break;
           case CIMTYPE_STRING:
               if (getType() != STRING) return false;
               kbValue.set(getValue());
               break;
           case CIMTYPE_REFERENCE:
               if (getType() != REFERENCE) return false;
               kbValue.set(CIMObjectPath(getValue()));
               break;
           case CIMTYPE_BOOLEAN:
               if (getType() != BOOLEAN) return false;
               kbValue = XmlReader::stringToValue(0, getValue().getCString(),
                                                  value.getType());
               break;
   //      case CIMTYPE_REAL32:
   //      case CIMTYPE_REAL64:
           case CIMTYPE_OBJECT:
           case CIMTYPE_INSTANCE:
               // From PEP 194: EmbeddedObjects cannot be keys.
               return false;
               break;
           default:  // Numerics
               if (getType() != NUMERIC) return false;
               kbValue = XmlReader::stringToValue(0, getValue().getCString(),
                                                  value.getType());
               break;
     }     }
   
     return "unknown";  
 } }
       catch (Exception&)
 Boolean operator==(const KeyBinding& x, const KeyBinding& y)  
 { {
     return          return false;
         CIMName::equal(x.getName(), y.getName()) &&  
         String::equal(x.getValue(), y.getValue()) &&  
         x.getType() == y.getType();  
 } }
  
       return value.equal(kbValue);
   }
  
 ////////////////////////////////////////////////////////////////////////////////  Boolean operator==(const CIMKeyBinding& x, const CIMKeyBinding& y)
 //  
 // CIMObjectPath  
 //  
 ////////////////////////////////////////////////////////////////////////////////  
   
 class CIMObjectPathRep  
 { {
 public:      // Check that the names and types match
     CIMObjectPathRep()      if (!(x.getName().equal(y.getName())) ||
           !(x.getType() == y.getType()))
     {     {
           return false;
     }     }
  
     CIMObjectPathRep(const CIMObjectPathRep& x)      switch (x.getType())
         : _host(x._host), _nameSpace(x._nameSpace),      {
         _className(x._className), _keyBindings(x._keyBindings)      case CIMKeyBinding::REFERENCE:
           try
     {     {
               // References should be compared as CIMObjectPaths
               return (CIMObjectPath(x.getValue()) == CIMObjectPath(y.getValue()));
     }     }
           catch (Exception&)
     CIMObjectPathRep(  
         const String& host,  
         const String& nameSpace,  
         const String& className,  
         const Array<KeyBinding>& keyBindings)  
         : _host(host), _nameSpace(nameSpace),  
         _className(className), _keyBindings(keyBindings)  
     {     {
               // If CIMObjectPath parsing fails, just compare strings
               return String::equal(x.getValue(), y.getValue());
     }     }
           break;
     ~CIMObjectPathRep()      case CIMKeyBinding::BOOLEAN:
           // Case-insensitive comparison is sufficient for booleans
           return String::equalNoCase(x.getValue(), y.getValue());
           break;
       case CIMKeyBinding::NUMERIC:
           // Note: This comparison assumes XML syntax for integers
           // First try comparing as unsigned integers
     {     {
               Uint64 xValue;
               Uint64 yValue;
               if (XmlReader::stringToUnsignedInteger(
                       x.getValue().getCString(), xValue) &&
                   XmlReader::stringToUnsignedInteger(
                       y.getValue().getCString(), yValue))
               {
                   return (xValue == yValue);
     }     }
           }
     CIMObjectPathRep& operator=(const CIMObjectPathRep& x)          // Next try comparing as signed integers
     {     {
         if (&x != this)              Sint64 xValue;
               Sint64 yValue;
               if (XmlReader::stringToSignedInteger(
                       x.getValue().getCString(), xValue) &&
                   XmlReader::stringToSignedInteger(
                       y.getValue().getCString(), yValue))
         {         {
             _host = x._host;                  return (xValue == yValue);
             _nameSpace = x._nameSpace;  
             _className = x._className;  
             _keyBindings = x._keyBindings;  
         }         }
         return *this;  
     }     }
           // Note: Keys may not be real values, so don't try comparing as reals
           // We couldn't parse the numbers, so just compare the strings
           return String::equal(x.getValue(), y.getValue());
           break;
       default:  // CIMKeyBinding::STRING
           return String::equal(x.getValue(), y.getValue());
           break;
       }
   
       PEGASUS_UNREACHABLE(return false;)
   }
   
  
   ////////////////////////////////////////////////////////////////////////////////
     //     //
     // Contains port as well (e.g., myhost:1234).  // CIMObjectPath
     //     //
     String _host;  ////////////////////////////////////////////////////////////////////////////////
  
     String _nameSpace;  template<class REP>
     String _className;  inline void Ref(REP* rep)
     Array<KeyBinding> _keyBindings;  {
 };          rep->_refCounter++;
   }
  
   template<class REP>
   inline void Unref(REP* rep)
   {
       if (rep->_refCounter.decAndTestIfZero())
           delete rep;
   }
  
 CIMObjectPath::CIMObjectPath() CIMObjectPath::CIMObjectPath()
 { {
Line 314 
Line 383 
  
 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x) CIMObjectPath::CIMObjectPath(const CIMObjectPath& x)
 { {
     _rep = new CIMObjectPathRep(*x._rep);      _rep = x._rep;
       Ref(_rep);
 } }
  
 CIMObjectPath::CIMObjectPath(const String& objectName) CIMObjectPath::CIMObjectPath(const String& objectName)
Line 323 
Line 393 
     CIMObjectPath tmpRef;     CIMObjectPath tmpRef;
     tmpRef.set(objectName);     tmpRef.set(objectName);
  
     _rep = new CIMObjectPathRep(*tmpRef._rep);      _rep = tmpRef._rep;
 }      Ref(_rep);
   
 CIMObjectPath::CIMObjectPath(const char* objectName)  
 {  
     // Test the objectName out to see if we get an exception  
     CIMObjectPath tmpRef;  
     tmpRef.set(objectName);  
   
     _rep = new CIMObjectPathRep(*tmpRef._rep);  
 } }
  
 CIMObjectPath::CIMObjectPath( CIMObjectPath::CIMObjectPath(
     const String& host,     const String& host,
     const String& nameSpace,      const CIMNamespaceName& nameSpace,
     const String& className,      const CIMName& className,
     const Array<KeyBinding>& keyBindings)      const Array<CIMKeyBinding>& keyBindings)
 { {
     // Test the objectName out to see if we get an exception     // Test the objectName out to see if we get an exception
     CIMObjectPath tmpRef;     CIMObjectPath tmpRef;
     tmpRef.set(host, nameSpace, className, keyBindings);     tmpRef.set(host, nameSpace, className, keyBindings);
       _rep = tmpRef._rep;
     _rep = new CIMObjectPathRep(*tmpRef._rep);      Ref(_rep);
 } }
  
 CIMObjectPath::~CIMObjectPath() CIMObjectPath::~CIMObjectPath()
 { {
     delete _rep;      Unref(_rep);
 } }
  
 CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x) CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
 { {
     *_rep = *x._rep;      if (x._rep != _rep)
       {
           Unref(_rep);
           _rep = x._rep;
           Ref(_rep);
       }
     return *this;     return *this;
 } }
  
   static inline CIMObjectPathRep* _copyOnWriteCIMObjectPathRep(
       CIMObjectPathRep* rep)
   {
       if (rep->_refCounter.get() > 1)
       {
           CIMObjectPathRep* tmpRep= new CIMObjectPathRep(*rep);
           Unref(rep);
           return tmpRep;
       }
       else
       {
           return rep;
       }
   }
   
 void CIMObjectPath::clear() void CIMObjectPath::clear()
 { {
       // If there is more than one reference
       // remove reference and get a new shiny empty representation
       if (_rep->_refCounter.get() > 1)
       {
           Unref(_rep);
           _rep = new CIMObjectPathRep();
       }
       else
       {
           // If there is only one reference
           // no need to copy the data, we own it
           // just clear the fields
     _rep->_host.clear();     _rep->_host.clear();
     _rep->_nameSpace.clear();     _rep->_nameSpace.clear();
     _rep->_className.clear();     _rep->_className.clear();
     _rep->_keyBindings.clear();     _rep->_keyBindings.clear();
 } }
   }
  
 void CIMObjectPath::set( void CIMObjectPath::set(
     const String& host,     const String& host,
     const String& nameSpace,      const CIMNamespaceName& nameSpace,
     const String& className,      const CIMName& className,
     const Array<KeyBinding>& keyBindings)  throw(IllformedObjectName, IllegalName)      const Array<CIMKeyBinding>& keyBindings)
   {
       if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
 { {
    setHost(host);          throw MalformedObjectNameException(host);
    setNameSpace(nameSpace);  
    setClassName(className);  
    setKeyBindings(keyBindings);  
 } }
  
 Boolean CIMObjectPath::_parseHostElement(      _rep = _copyOnWriteCIMObjectPathRep(_rep);
   
       _rep->_host.assign(host);
       _rep->_nameSpace = nameSpace;
       _rep->_className = className;
       _rep->_keyBindings = keyBindings;
       _Sort(_rep->_keyBindings);
   }
   
   Boolean _parseHostElement(
     const String& objectName,     const String& objectName,
     char*& p,     char*& p,
     String& host) throw(IllformedObjectName)      String& host)
 { {
     // See if there is a host name (true if it begins with "//"):     // See if there is a host name (true if it begins with "//"):
     // Host is of the from <hostname>-<port> and begins with "//"      // Host is of the form <hostname>:<port> and begins with "//"
     // and ends with "/":     // and ends with "/":
  
     if (p[0] != '/' || p[1] != '/')     if (p[0] != '/' || p[1] != '/')
Line 395 
Line 498 
  
     p += 2;     p += 2;
  
     //----------------------------------------------------------------------      char* slash = strchr(p, '/');
     // Validate the hostname. Hostnames must match the following      if (!slash)
     // regular expression: "[A-Za-z][A-Za-z0-9-]*"  
     //----------------------------------------------------------------------  
   
     char* q = p;  
   
     if (!isalpha(*q))  
         throw IllformedObjectName(objectName);  
   
     q++;  
   
     while (isalnum(*q) || *q == '-')  
         q++;  
   
     // We now expect a port (or default the port).  
   
     if (*q == ':')  
     {     {
         q++;          throw MalformedObjectNameException(objectName);
         // Check for a port number:  
   
         if (!isdigit(*q))  
             throw IllformedObjectName(objectName);  
   
         while (isdigit(*q))  
             q++;  
   
         // Finally, assign the host name:  
   
         host.assign(p, q - p);  
     }  
     else  
     {  
         host.assign(p, q - p);  
   
         // Assign the default port number:  
   
         host.append(":");  
         host.append(PEGASUS_CIMOM_DEFAULT_PORT_STRING);  
     }     }
  
     // Check for slash terminating the entire sequence:      String hostname = String(p, (Uint32)(slash - p));
       if (!CIMObjectPathRep::isValidHostname(hostname))
     if (*q != '/')  
     {     {
         host.clear();          throw MalformedObjectNameException(objectName);
         throw IllformedObjectName(objectName);  
     }     }
       host = hostname;
  
     p = ++q;      // Do not step past the '/'; it will be consumed by the namespace parser
       p = slash;
  
     return true;     return true;
 } }
  
 Boolean CIMObjectPath::_parseNamespaceElement(  Boolean _parseNamespaceElement(
     const String& objectName,     const String& objectName,
     char*& p,     char*& p,
     String& nameSpace)      CIMNamespaceName& nameSpace)
 { {
     // If we don't find a valid namespace name followed by a ':', we     // If we don't find a valid namespace name followed by a ':', we
     // assume we're not looking at a namespace name.     // assume we're not looking at a namespace name.
  
     //----------------------------------------------------------------------      char* colon = strchr(p, ':');
     // Validate the namespace path.  Namespaces must match the following      if (!colon)
     // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"  
     //----------------------------------------------------------------------  
   
     char* q = p;  
   
     for (;;)  
     {     {
         // Pass the next token:  
   
         if (!*q || (!isalpha(*q) && *q != '_'))  
             return false;             return false;
       }
  
         q++;      // A ':' as part of a keybinding value should not be interpreted as
       // a namespace delimiter.  Since keybinding pairs follow the first '.'
         while (isalnum(*q) || *q == '_')      // in the object path string, the ':' delimiter only counts if it
             q++;      // appears before the '.'.
  
         if (!*q)      char* dot = strchr(p, '.');
       if (dot && (dot < colon))
       {
             return false;             return false;
       }
  
         if (*q == ':')      //----------------------------------------------------------------------
             break;      // Validate the namespace path.  Namespaces must match the following
       // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
       //----------------------------------------------------------------------
  
         if (*q == '/')      String namespaceName = String(p, (Uint32)(colon - p));
       if (!CIMNamespaceName::legal(namespaceName))
         {         {
             q++;          throw MalformedObjectNameException(objectName);
             continue;  
         }         }
       nameSpace = namespaceName;
  
         return false;      p = colon+1;
     }  
   
     nameSpace.assign(p, q - p);  
     p = ++q;  
     return true;     return true;
 } }
  
 /** /**
     ATTN: RK - Association classes have keys whose types are      ATTN-RK: The DMTF specification for the string form of an
     references.  These reference values must be treated specially      object path makes it impossible for a parser to distinguish
     in the XML encoding, using the VALUE.REFERENCE tag structure.      between a key values of String type and Reference type.
   
     Pegasus had been passing reference values simply as String      Given the ambiguity, this implementation takes a guess at the
     values.  For example, EnumerateInstanceNames returned      type of a quoted key value.  If the value can be parsed into
     KEYVALUEs of string type rather than VALUE.REFERENCEs.      a CIMObjectPath with at least one key binding, the type is
       set to REFERENCE.  Otherwise, the type is set to STRING.
     I've modified the XmlReader::getKeyBindingElement() and      Note: This algorithm appears to be in line with what the Sun
     XmlWriter::appendInstanceNameElement() methods to read and write      WBEM Services implementation does.
     the XML in the proper format.  However, making that change  
     required that a CIMObjectPath object be able to distinguish      To be totally correct, it would be necessary to retrieve the
     between a key of String type and a key of reference type.      class definition and look up the types of the key properties
       to determine how to interpret the key values.  This is clearly
     I've modified the String format of CIMObjectPaths slightly to      too inefficient for internal transformations between
     allow efficient processing of references whose keys are also      CIMObjectPaths and String values.
     of reference type.  The "official" form uses the same  
     encoding for key values of String type and of reference type,  
     and so it would be necessary to retrieve the class definition  
     and look up the types of the key properties to determine how  
     to treat the key values.  This is clearly too inefficient for  
     internal transformations between CIMObjectPaths and String  
     values.  
   
     The workaround is to encode a 'R' at the beginning of the  
     value for a key of reference type (before the opening '"').  
     This allows the parser to know a priori whether the key is of  
     String or reference type.  
   
     In this example:  
   
         MyClass.Key1="StringValue",Key2=R"RefClass.KeyA="StringA",KeyB=10"  
   
     Property Key1 of class MyClass is of String type, and so it  
     gets the usual encoding.  Key2 is a reference property, so  
     the extra 'R' is inserted before its encoded value.  Note  
     that this algorithm is recursive, such that RefClass could  
     include KeyC of reference type, which would also get encoded  
     with the 'R' notation.  
   
     The toString() method inserts the 'R' to provide symmetry.  A  
     new KeyBinding type (REFERENCE) has been defined to denote  
     keys in a CIMObjectPath that are of reference type.  This  
     KeyBinding type must be used appropriately for  
     CIMObjectPath::toString() to behave correctly.  
   
     A result of this change is that instances names in the  
     instance repository will include this extra 'R' character.  
     Note that for user-facing uses of the String encoding of  
     instance names (such as might appear in MOF for static  
     association instances or in the CGI client), this solution  
     is non-standard and therefore unacceptable.  It is likely  
     that these points will need to process the more expensive  
     operation of retrieving the class definition to determine  
     the key property types.  
 */ */
 void CIMObjectPath::_parseKeyBindingPairs(  void _parseKeyBindingPairs(
     const String& objectName,     const String& objectName,
     char*& p,     char*& p,
     Array<KeyBinding>& keyBindings)  throw(IllformedObjectName)      Array<CIMKeyBinding>& keyBindings)
 { {
     // Get the key-value pairs:     // Get the key-value pairs:
  
Line 565 
Line 587 
     {     {
         // Get key part:         // Get key part:
  
         char* key = strtok(p, "=");          char* equalsign = strchr(p, '=');
           if (!equalsign)
         if (!key)  
         {         {
             throw IllformedObjectName(objectName);              throw MalformedObjectNameException(objectName);
         }         }
  
         String keyString(key);          *equalsign = 0;
  
         if (!CIMName::legal(keyString))          if (!CIMName::legal(p))
             throw IllformedObjectName(objectName);              throw MalformedObjectNameException(objectName);
   
           CIMName keyName (p);
  
         // Get the value part:         // Get the value part:
  
         String valueString;         String valueString;
         p = p + strlen(key) + 1;          p = equalsign + 1;
         KeyBinding::Type type;          CIMKeyBinding::Type type;
  
         if (*p == 'R')          if (*p == '"')
         {         {
             p++;              // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
  
             type = KeyBinding::REFERENCE;              p++;
  
             if (*p++ != '"')              Buffer keyValueUTF8(128);
                 throw IllformedObjectName(objectName);  
  
             while (*p && *p != '"')             while (*p && *p != '"')
             {             {
                 // ATTN: need to handle special characters here:  
   
                 if (*p == '\\')                 if (*p == '\\')
                     *p++;                  {
                       p++;
  
                 valueString.append(*p++);                      if ((*p != '\\') && (*p != '"'))
                       {
                           throw MalformedObjectNameException(objectName);
                       }
             }             }
  
             if (*p++ != '"')                  keyValueUTF8.append(*p++);
                 throw IllformedObjectName(objectName);  
         }         }
         else if (*p == '"')  
         {  
             p++;  
  
             type = KeyBinding::STRING;              if (*p++ != '"')
                   throw MalformedObjectNameException(objectName);
  
             while (*p && *p != '"')              // Convert the UTF-8 value to a UTF-16 String
             {  
                 // ATTN: need to handle special characters here:  
  
                 if (*p == '\\')              valueString.assign(
                     *p++;                  (const char*)keyValueUTF8.getData(),
                   keyValueUTF8.size());
   
               /*
                   Guess at the type of this quoted key value.  If the value
                   can be parsed into a CIMObjectPath with at least one key
                   binding, the type is assumed to be a REFERENCE.  Otherwise,
                   the type is set to STRING.  (See method header for details.)
                */
               type = CIMKeyBinding::STRING;
  
                 valueString.append(*p++);              /* Performance shortcut will check for
                  equal sign instead of doing the full
                  CIMObjectPath creation and exception handling
               */
               if (strchr(keyValueUTF8.getData(), '='))
               {
                   // found an equal sign, high probability for a reference
                   try
                   {
                       CIMObjectPath testForPath(valueString);
                       if (testForPath.getKeyBindings().size() > 0)
                       {
                           // We've found a reference value!
                           type = CIMKeyBinding::REFERENCE;
                       }
                   }
                   catch (const Exception &)
                   {
                       // Not a reference value; leave type as STRING
                   }
             }             }
   
             if (*p++ != '"')  
                 throw IllformedObjectName(objectName);  
         }         }
         else if (toupper(*p) == 'T' || toupper(*p) == 'F')         else if (toupper(*p) == 'T' || toupper(*p) == 'F')
         {         {
             type = KeyBinding::BOOLEAN;              type = CIMKeyBinding::BOOLEAN;
  
             char* r = p;             char* r = p;
             Uint32 n = 0;             Uint32 n = 0;
Line 640 
Line 684 
  
             if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||             if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
                   ((strncmp(p, "FALSE", n) == 0) && n == 5)))                   ((strncmp(p, "FALSE", n) == 0) && n == 5)))
                 throw IllformedObjectName(objectName);                  throw MalformedObjectNameException(objectName);
  
             valueString.assign(p, n);             valueString.assign(p, n);
  
Line 648 
Line 692 
         }         }
         else         else
         {         {
             type = KeyBinding::NUMERIC;              type = CIMKeyBinding::NUMERIC;
  
             char* r = p;             char* r = p;
             Uint32 n = 0;             Uint32 n = 0;
Line 666 
Line 710 
                 isComma = true;                 isComma = true;
             }             }
  
               if (*p == '-')
               {
             Sint64 x;             Sint64 x;
   
             if (!XmlReader::stringToSignedInteger(p, x))             if (!XmlReader::stringToSignedInteger(p, x))
                 throw IllformedObjectName(objectName);                      throw MalformedObjectNameException(objectName);
               }
               else
               {
                   Uint64 x;
                   if (!XmlReader::stringToUnsignedInteger(p, x))
                       throw MalformedObjectNameException(objectName);
               }
  
             valueString.assign(p, n);             valueString.assign(p, n);
  
Line 681 
Line 733 
             p = p + n;             p = p + n;
         }         }
  
         keyBindings.append(KeyBinding(keyString, valueString, type));          keyBindings.append(CIMKeyBinding(keyName.getString (), valueString,
               type));
  
         if (*p)         if (*p)
         {         {
             if (*p++ != ',')             if (*p++ != ',')
             {             {
                 throw IllformedObjectName(objectName);                  throw MalformedObjectNameException(objectName);
             }             }
         }         }
     }     }
  
     _BubbleSort(keyBindings);      _Sort(keyBindings);
 } }
  
 void CIMObjectPath::set(const String& objectName)  throw(IllformedObjectName)  void CIMObjectPath::set(const String& objectName)
 { {
       // the clear automatically ensures
       // we have our own copy of the representation
     clear();     clear();
  
     //--------------------------------------------------------------------------     //--------------------------------------------------------------------------
Line 708 
Line 763 
  
     // Convert to a C String first:     // Convert to a C String first:
  
     char* p = objectName.allocateCString(1);      CString pCString = objectName.getCString();
     ArrayDestroyer<char> destroyer(p);      char* p = const_cast<char*>((const char*) pCString);
     Boolean gotHost;     Boolean gotHost;
     Boolean gotNamespace;     Boolean gotNamespace;
  
     // null terminate the C String  
     // ATTN-RK-P3-20020301: Is the +1 correct?  
     p[objectName.size() + 1]= '\0';  
   
     gotHost = _parseHostElement(objectName, p, _rep->_host);     gotHost = _parseHostElement(objectName, p, _rep->_host);
     gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);     gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
  
     if (gotHost && !gotNamespace)     if (gotHost && !gotNamespace)
     {     {
         throw IllformedObjectName(objectName);          throw MalformedObjectNameException(objectName);
     }     }
  
     // Extract the class name:     // Extract the class name:
Line 733 
Line 784 
     {     {
         if (!CIMName::legal(p))         if (!CIMName::legal(p))
         {         {
             throw IllformedObjectName(objectName);              throw MalformedObjectNameException(objectName);
         }         }
  
         // ATTN: remove this later: a reference should only be able to hold         // ATTN: remove this later: a reference should only be able to hold
         // an instance name.         // an instance name.
  
         _rep->_className.assign(p);          _rep->_className = CIMName (p);
         return;         return;
     }     }
  
     _rep->_className.assign(p, dot - p);      String className = String(p, (Uint32)(dot - p));
       if (!CIMName::legal(className))
       {
           throw MalformedObjectNameException(objectName);
       }
       _rep->_className = className;
  
     // Advance past dot:     // Advance past dot:
  
Line 754 
Line 810 
  
 CIMObjectPath& CIMObjectPath::operator=(const String& objectName) CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
 { {
     set(objectName);      // set will call clear, which will cause copyOnWrite if necessary
     return *this;  
 }  
   
 CIMObjectPath& CIMObjectPath::operator=(const char* objectName)  
 {  
     set(objectName);     set(objectName);
     return *this;     return *this;
 } }
Line 771 
Line 822 
  
 void CIMObjectPath::setHost(const String& host) void CIMObjectPath::setHost(const String& host)
 { {
       if ((host != String::EMPTY) &&
           (host != System::getHostName()) &&
           !CIMObjectPathRep::isValidHostname(host))
       {
           throw MalformedObjectNameException(host);
       }
       _rep = _copyOnWriteCIMObjectPathRep(_rep);
   
     _rep->_host = host;     _rep->_host = host;
 } }
  
 const String& CIMObjectPath::getNameSpace() const  const CIMNamespaceName& CIMObjectPath::getNameSpace() const
 { {
     return _rep->_nameSpace;     return _rep->_nameSpace;
 } }
  
 void CIMObjectPath::setNameSpace(const String& nameSpace) throw(IllegalName)  void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
 { {
     String temp;      _rep = _copyOnWriteCIMObjectPathRep(_rep);
   
     // check each namespace segment (delimted by '/') for correctness  
   
     for(Uint32 i = 0; i < nameSpace.size(); i += temp.size() + 1)  
     {  
         // isolate the segment beginning at i and ending at the first  
         // ocurrance of '/' after i or eos  
   
         temp = nameSpace.subString(i, nameSpace.subString(i).find('/'));  
   
         // check segment for correctness  
   
         if(!CIMName::legal(temp))  
         {  
             throw IllegalName() ;  
         }  
     }  
   
    _rep->_nameSpace = nameSpace;    _rep->_nameSpace = nameSpace;
 } }
  
 const String& CIMObjectPath::getClassName() const  const CIMName& CIMObjectPath::getClassName() const
 { {
     return _rep->_className;     return _rep->_className;
 } }
  
 const Boolean CIMObjectPath::equalClassName(const String& classname) const  void CIMObjectPath::setClassName(const CIMName& className)
 { {
     return (String::equalNoCase(classname, CIMObjectPath::getClassName()));      _rep = _copyOnWriteCIMObjectPathRep(_rep);
 }  
   
 void CIMObjectPath::setClassName(const String& className) throw(IllegalName)  
 {  
     if (!CIMName::legal(className))  
         throw IllegalName();  
   
     _rep->_className = className;     _rep->_className = className;
 } }
  
 const Array<KeyBinding>& CIMObjectPath::getKeyBindings() const  const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
 { {
     return _rep->_keyBindings;     return _rep->_keyBindings;
 } }
  
 void CIMObjectPath::setKeyBindings(const Array<KeyBinding>& keyBindings)  void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
 { {
       _rep = _copyOnWriteCIMObjectPathRep(_rep);
     _rep->_keyBindings = keyBindings;     _rep->_keyBindings = keyBindings;
     _BubbleSort(_rep->_keyBindings);      _Sort(_rep->_keyBindings);
 } }
  
 String CIMObjectPath::toString(Boolean includeHost) const  String CIMObjectPath::toString() const
 { {
     String objectName;     String objectName;
  
     // Get the host:     // Get the host:
  
     if (_rep->_host.size() && includeHost)      if (_rep->_host.size())
     {     {
         objectName = "//";         objectName = "//";
         objectName += _rep->_host;          objectName.append(_rep->_host);
         objectName += "/";          objectName.append("/");
     }     }
  
     // Get the namespace (if we have a host name, we must write namespace):     // Get the namespace (if we have a host name, we must write namespace):
  
     if (_rep->_nameSpace.size() || _rep->_host.size())      if (!_rep->_nameSpace.isNull() || _rep->_host.size())
     {     {
         objectName += _rep->_nameSpace;          objectName.append(_rep->_nameSpace.getString ());
         objectName += ":";          objectName.append(":");
     }     }
  
     // Get the class name:     // Get the class name:
  
     objectName.append(getClassName());      objectName.append(getClassName().getString ());
  
     if (isInstanceName())      //
       //  ATTN-CAKG-P2-20020726:  The following condition does not correctly
       //  distinguish instanceNames from classNames in every case
       //  The instanceName of a singleton instance of a keyless class has no
       //  key bindings
       //
       if (_rep->_keyBindings.size () != 0)
     {     {
         objectName.append('.');         objectName.append('.');
  
         // Append each key-value pair:         // Append each key-value pair:
  
         const Array<KeyBinding>& keyBindings = getKeyBindings();          const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
  
         for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)         for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
         {         {
             objectName.append(keyBindings[i].getName());              objectName.append(keyBindings[i].getName().getString ());
             objectName.append('=');             objectName.append('=');
  
             const String& value = _escapeSpecialCharacters(             const String& value = _escapeSpecialCharacters(
                 keyBindings[i].getValue());                 keyBindings[i].getValue());
  
             KeyBinding::Type type = keyBindings[i].getType();              CIMKeyBinding::Type type = keyBindings[i].getType();
  
             if (type == KeyBinding::REFERENCE)              if (type == CIMKeyBinding::STRING ||
                 objectName.append('R');                  type == CIMKeyBinding::REFERENCE)
   
             if (type == KeyBinding::STRING || type == KeyBinding::REFERENCE)  
                 objectName.append('"');                 objectName.append('"');
  
             objectName.append(value);             objectName.append(value);
  
             if (type == KeyBinding::STRING || type == KeyBinding::REFERENCE)              if (type == CIMKeyBinding::STRING ||
                   type == CIMKeyBinding::REFERENCE)
                 objectName.append('"');                 objectName.append('"');
  
             if (i + 1 != n)             if (i + 1 != n)
Line 894 
Line 934 
     return objectName;     return objectName;
 } }
  
 String CIMObjectPath::toStringCanonical(Boolean includeHost) const  String CIMObjectPath::_toStringCanonical() const
 { {
     CIMObjectPath ref = *this;      CIMObjectPath ref;
       *ref._rep = *this->_rep;
     // ATTN-RK-P2-20020510: Need to make hostname and namespace lower case?  
  
     ref._rep->_className.toLower();      // Normalize hostname by changing to lower case
       ref._rep->_host.toLower(); // ICU_TODO:
  
     for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)      // Normalize namespace by changing to lower case
       if (!ref._rep->_nameSpace.isNull())
     {     {
         ref._rep->_keyBindings[i]._rep->_name.toLower();          String nameSpaceLower = ref._rep->_nameSpace.getString();
           nameSpaceLower.toLower(); // ICU_TODO:
           ref._rep->_nameSpace = nameSpaceLower;
     }     }
  
     return ref.toString(includeHost);      // Normalize class name by changing to lower case
       if (!ref._rep->_className.isNull())
       {
           String classNameLower = ref._rep->_className.getString();
           classNameLower.toLower(); // ICU_TODO:
           ref._rep->_className = classNameLower;
 } }
  
 CIMObjectPath CIMObjectPath::clone() const      for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
       {
           // Normalize key binding name by changing to lower case
           if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
 { {
     return CIMObjectPath(*this);              String keyBindingNameLower =
                   ref._rep->_keyBindings[i]._rep->_name.getString();
               keyBindingNameLower.toLower(); // ICU_TODO:
               ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
 } }
  
 Boolean CIMObjectPath::identical(const CIMObjectPath& x) const          // Normalize the key value
           switch (ref._rep->_keyBindings[i]._rep->_type)
 { {
     return          case CIMKeyBinding::REFERENCE:
         String::equal(_rep->_host, x._rep->_host) &&              try
         CIMName::equal(_rep->_nameSpace, x._rep->_nameSpace) &&              {
         CIMName::equal(_rep->_className, x._rep->_className) &&                  // Convert reference to CIMObjectPath and recurse
         _rep->_keyBindings == x._rep->_keyBindings;                  ref._rep->_keyBindings[i]._rep->_value =
                       CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
                           _toStringCanonical();
 } }
               catch (Exception&)
 Uint32 CIMObjectPath::makeHashCode() const  
 { {
     return HashFunc<String>::hash(toStringCanonical());                  // Leave value unchanged if the CIMObjectPath parsing fails
               }
               break;
           case CIMKeyBinding::BOOLEAN:
               // Normalize the boolean string by changing to lower case
               ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
               break;
           case CIMKeyBinding::NUMERIC:
               // Normalize the numeric string by converting to integer and back
               Uint64 uValue;
               Sint64 sValue;
               // First try converting to unsigned integer
               if (XmlReader::stringToUnsignedInteger(
                       ref._rep->_keyBindings[i]._rep->_value.getCString(),
                           uValue))
               {
                   char buffer[32];  // Should need 21 chars max
                   sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
                   ref._rep->_keyBindings[i]._rep->_value = String(buffer);
               }
               // Next try converting to signed integer
               else if (XmlReader::stringToSignedInteger(
                            ref._rep->_keyBindings[i]._rep->_value.getCString(),
                                sValue))
               {
                   char buffer[32];  // Should need 21 chars max
                   sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
                   ref._rep->_keyBindings[i]._rep->_value = String(buffer);
               }
               // Leave value unchanged if it cannot be converted to an integer
               break;
           default:  // CIMKeyBinding::STRING
               // No normalization required for STRING
               break;
           }
 } }
  
 Boolean CIMObjectPath::isInstanceName() const      // Note: key bindings are sorted when set in the CIMObjectPath
 {  
     return _rep->_keyBindings.size() != 0;      return ref.toString();
 } }
  
 KeyBindingArray CIMObjectPath::getKeyBindingArray()  Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
 { {
     return KeyBindingArray();      return
           (_rep == x._rep) ||
           (String::equalNoCase(_rep->_host, x._rep->_host) &&
            _rep->_nameSpace.equal(x._rep->_nameSpace) &&
            _rep->_className.equal(x._rep->_className) &&
            (_rep->_keyBindings == x._rep->_keyBindings));
 } }
  
   Uint32 CIMObjectPath::makeHashCode() const
   {
       return HashFunc<String>::hash(_toStringCanonical());
   }
  
 Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y) Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
 { {
Line 950 
Line 1049 
     return !operator==(x, y);     return !operator==(x, y);
 } }
  
 PEGASUS_STD(ostream)& operator<<(  
     PEGASUS_STD(ostream)& os,  
     const CIMObjectPath& x)  
 {  
     return os << x.toString();  
 }  
   
 PEGASUS_NAMESPACE_END PEGASUS_NAMESPACE_END


Legend:
Removed from v.1.2  
changed lines
  Added in v.1.73

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2