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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2