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

   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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2