(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 marek       1.77         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 marek       1.77         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 marek       1.77         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 marek       1.77         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 marek       1.77             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 marek       1.77         {
 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 marek       1.77                         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.79             {
 663 marek       1.77                 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.79             {
 724 marek       1.77                 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.79                 {
 761 marek       1.77                     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.79                 {
 775 marek       1.77                     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 marek       1.77                 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 marek       1.77         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 marek       1.77             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 marek       1.77         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 marek       1.77         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.79     //  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