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

   1 karl  1.30 //%2003////////////////////////////////////////////////////////////////////////
   2 chip  1.1  //
   3 karl  1.30 // Copyright (c) 2000, 2001, 2002  BMC Software, Hewlett-Packard Development
   4            // Company, L. P., IBM Corp., The Open Group, Tivoli Systems.
   5            // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L. P.;
   6            // IBM Corp.; EMC Corporation, The Open Group.
   7 chip  1.1  //
   8            // Permission is hereby granted, free of charge, to any person obtaining a copy
   9            // of this software and associated documentation files (the "Software"), to
  10            // deal in the Software without restriction, including without limitation the
  11            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  12            // sell copies of the Software, and to permit persons to whom the Software is
  13            // furnished to do so, subject to the following conditions:
  14 kumpf 1.6  // 
  15 chip  1.1  // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
  16            // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
  17            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  18            // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  19            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  21            // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23            //
  24            //==============================================================================
  25            //
  26 kumpf 1.2  // Author: Mike Brasher (mbrasher@bmc.com)
  27 chip  1.1  //
  28 kumpf 1.2  // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
  29 kumpf 1.9  //              Carol Ann Krug Graves, Hewlett-Packard Company
  30            //                (carolann_graves@hp.com)
  31 chip  1.1  //
  32            //%/////////////////////////////////////////////////////////////////////////////
  33            
  34 kumpf 1.2  #include <Pegasus/Common/Config.h>
  35            #include <cctype>
  36            #include <cstring>
  37 kumpf 1.22 #include <iostream>
  38 kumpf 1.2  #include "HashTable.h"
  39            #include "CIMObjectPath.h"
  40            #include "Indentor.h"
  41            #include "CIMName.h"
  42 a.arora 1.39 #include "Destroyer.h"
  43 kumpf   1.2  #include "XmlWriter.h"
  44              #include "XmlReader.h"
  45 kumpf   1.11 #include "ArrayInternal.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 kumpf   1.16 static void _BubbleSort(Array<CIMKeyBinding>& x)
  98 kumpf   1.2  {
  99                  Uint32 n = x.size();
 100              
 101 kumpf   1.24     //
 102                  //  If the key is a reference, the keys in the reference must also be 
 103                  //  sorted
 104                  //
 105                  for (Uint32 k = 0; k < n ; k++)
 106                      if (x[k].getType () == CIMKeyBinding::REFERENCE)
 107                      {
 108                          CIMObjectPath tmp (x[k].getValue ());
 109                          Array <CIMKeyBinding> keyBindings = tmp.getKeyBindings ();
 110                          _BubbleSort (keyBindings);
 111                          tmp.setKeyBindings (keyBindings);
 112                          x[k].setValue (tmp.toString ());
 113                      }
 114              
 115 kumpf   1.2      if (n < 2)
 116                      return;
 117              
 118                  for (Uint32 i = 0; i < n - 1; i++)
 119                  {
 120                      for (Uint32 j = 0; j < n - 1; j++)
 121                      {
 122 kumpf   1.17             if (String::compareNoCase(x[j].getName().getString(), 
 123                                                    x[j+1].getName().getString()) > 0)
 124 kumpf   1.2              {
 125 kumpf   1.16                 CIMKeyBinding t = x[j];
 126 kumpf   1.2                  x[j] = x[j+1];
 127                              x[j+1] = t;
 128                          }
 129                      }
 130                  }
 131              }
 132              
 133              ////////////////////////////////////////////////////////////////////////////////
 134              //
 135 kumpf   1.16 // CIMKeyBinding
 136 kumpf   1.2  //
 137              ////////////////////////////////////////////////////////////////////////////////
 138              
 139 kumpf   1.16 class CIMKeyBindingRep
 140 kumpf   1.2  {
 141              public:
 142 kumpf   1.16     CIMKeyBindingRep()
 143 kumpf   1.2      {
 144                  }
 145              
 146 kumpf   1.16     CIMKeyBindingRep(const CIMKeyBindingRep& x)
 147 kumpf   1.2          : _name(x._name), _value(x._value), _type(x._type)
 148                  {
 149                  }
 150              
 151 kumpf   1.16     CIMKeyBindingRep(
 152 kumpf   1.7          const CIMName& name,
 153 kumpf   1.2          const String& value,
 154 kumpf   1.16         CIMKeyBinding::Type type)
 155 kumpf   1.2          : _name(name), _value(value), _type(type)
 156                  {
 157                  }
 158              
 159 kumpf   1.16     ~CIMKeyBindingRep()
 160 kumpf   1.2      {
 161                  }
 162              
 163 kumpf   1.16     CIMKeyBindingRep& operator=(const CIMKeyBindingRep& x)
 164 kumpf   1.2      {
 165                      if (&x != this)
 166                      {
 167                          _name = x._name;
 168                          _value = x._value;
 169                          _type = x._type;
 170                      }
 171                      return *this;
 172                  }
 173              
 174 kumpf   1.7      CIMName _name;
 175 kumpf   1.2      String _value;
 176 kumpf   1.16     CIMKeyBinding::Type _type;
 177 kumpf   1.2  };
 178              
 179              
 180 a.arora 1.39 CIMKeyBinding::CIMKeyBinding()
 181 kumpf   1.2  {
 182 a.arora 1.39     _rep = new CIMKeyBindingRep();
 183 kumpf   1.2  }
 184              
 185 a.arora 1.39 CIMKeyBinding::CIMKeyBinding(const CIMKeyBinding& x)
 186 kumpf   1.2  {
 187 a.arora 1.39     _rep = new CIMKeyBindingRep(*x._rep);
 188 kumpf   1.2  }
 189              
 190 a.arora 1.39 CIMKeyBinding::CIMKeyBinding(const CIMName& name, const String& value, Type type)
 191 kumpf   1.2  {
 192 a.arora 1.39     _rep = new CIMKeyBindingRep(name, value, type);
 193 kumpf   1.2  }
 194              
 195 kumpf   1.18 CIMKeyBinding::CIMKeyBinding(const CIMName& name, const CIMValue& value)
 196              {
 197 kumpf   1.21     if (value.isArray())
 198 kumpf   1.20     {
 199                      throw TypeMismatchException();
 200                  }
 201              
 202 kumpf   1.18     String kbValue = value.toString();
 203                  Type kbType;
 204              
 205                  switch (value.getType())
 206                  {
 207                  case CIMTYPE_BOOLEAN:
 208                      kbType = BOOLEAN;
 209                      break;
 210                  case CIMTYPE_CHAR16:
 211                  case CIMTYPE_STRING:
 212                  case CIMTYPE_DATETIME:
 213                      kbType = STRING;
 214                      break;
 215                  case CIMTYPE_REFERENCE:
 216                      kbType = REFERENCE;
 217                      break;
 218                  default:
 219                      kbType = NUMERIC;
 220                      break;
 221                  }
 222              
 223 a.arora 1.39     _rep = new CIMKeyBindingRep(name, kbValue, kbType);
 224 kumpf   1.18 }
 225              
 226 kumpf   1.16 CIMKeyBinding::~CIMKeyBinding()
 227 kumpf   1.2  {
 228 a.arora 1.39     delete _rep;
 229 kumpf   1.2  }
 230              
 231 kumpf   1.16 CIMKeyBinding& CIMKeyBinding::operator=(const CIMKeyBinding& x)
 232 kumpf   1.2  {
 233 a.arora 1.39     *_rep = *x._rep;
 234 kumpf   1.2      return *this;
 235              }
 236              
 237 kumpf   1.16 const CIMName& CIMKeyBinding::getName() const
 238 kumpf   1.2  {
 239                  return _rep->_name;
 240              }
 241              
 242 kumpf   1.16 void CIMKeyBinding::setName(const CIMName& name)
 243 kumpf   1.2  {
 244                  _rep->_name = name;
 245              }
 246              
 247 kumpf   1.16 const String& CIMKeyBinding::getValue() const
 248 kumpf   1.2  {
 249                  return _rep->_value;
 250              }
 251              
 252 kumpf   1.16 void CIMKeyBinding::setValue(const String& value)
 253 kumpf   1.2  {
 254                  _rep->_value = value;
 255              }
 256              
 257 kumpf   1.16 CIMKeyBinding::Type CIMKeyBinding::getType() const
 258 kumpf   1.2  {
 259                  return _rep->_type;
 260              }
 261              
 262 kumpf   1.16 void CIMKeyBinding::setType(CIMKeyBinding::Type type)
 263 kumpf   1.2  {
 264                  _rep->_type = type;
 265              }
 266 kumpf   1.18 
 267              Boolean CIMKeyBinding::equal(CIMValue value)
 268              {
 269 kumpf   1.21     if (value.isArray())
 270 kumpf   1.20     {
 271                      return false;
 272                  }
 273              
 274 kumpf   1.18     CIMValue kbValue;
 275              
 276                  try
 277                  {
 278                      switch (value.getType())
 279                      {
 280                      case CIMTYPE_CHAR16:
 281 kumpf   1.20             if (getType() != STRING) return false;
 282 kumpf   1.18             kbValue.set(getValue()[0]);
 283                          break;
 284                      case CIMTYPE_DATETIME:
 285 kumpf   1.20             if (getType() != STRING) return false;
 286 kumpf   1.18             kbValue.set(CIMDateTime(getValue()));
 287                          break;
 288                      case CIMTYPE_STRING:
 289 kumpf   1.20             if (getType() != STRING) return false;
 290 kumpf   1.18             kbValue.set(getValue());
 291                          break;
 292                      case CIMTYPE_REFERENCE:
 293 kumpf   1.20             if (getType() != REFERENCE) return false;
 294 kumpf   1.18             kbValue.set(CIMObjectPath(getValue()));
 295                          break;
 296 kumpf   1.20         case CIMTYPE_BOOLEAN:
 297                          if (getType() != BOOLEAN) return false;
 298                          kbValue = XmlReader::stringToValue(0, getValue().getCString(),
 299                                                             value.getType());
 300                          break;
 301                      default:  // Numerics
 302                          if (getType() != NUMERIC) return false;
 303 kumpf   1.18             kbValue = XmlReader::stringToValue(0, getValue().getCString(),
 304                                                             value.getType());
 305                          break;
 306                      }
 307                  }
 308 kumpf   1.19     catch (Exception&)
 309 kumpf   1.18     {
 310                      return false;
 311                  }
 312              
 313                  return value.equal(kbValue);
 314              }
 315 kumpf   1.2  
 316 kumpf   1.16 Boolean operator==(const CIMKeyBinding& x, const CIMKeyBinding& y)
 317 kumpf   1.2  {
 318 kumpf   1.33     // Check that the names and types match
 319                  if (!(x.getName().equal(y.getName())) ||
 320                      !(x.getType() == y.getType()))
 321                  {
 322                      return false;
 323                  }
 324              
 325                  switch (x.getType())
 326                  {
 327                  case CIMKeyBinding::REFERENCE:
 328                      try
 329                      {
 330                          // References should be compared as CIMObjectPaths
 331                          return (CIMObjectPath(x.getValue()) == CIMObjectPath(y.getValue()));
 332                      }
 333                      catch (Exception&)
 334                      {
 335                          // If CIMObjectPath parsing fails, just compare strings
 336                          return (String::equal(x.getValue(), y.getValue()));
 337                      }
 338                      break;
 339 kumpf   1.33     case CIMKeyBinding::BOOLEAN:
 340                      // Case-insensitive comparison is sufficient for booleans
 341                      return (String::equalNoCase(x.getValue(), y.getValue()));
 342                      break;
 343                  case CIMKeyBinding::NUMERIC:
 344                      // Note: This comparison assumes XML syntax for integers
 345                      // First try comparing as unsigned integers
 346                      {
 347                          Uint64 xValue;
 348                          Uint64 yValue;
 349                          if (XmlReader::stringToUnsignedInteger(
 350                                  x.getValue().getCString(), xValue) &&
 351                              XmlReader::stringToUnsignedInteger(
 352                                  y.getValue().getCString(), yValue))
 353                          {
 354                              return (xValue == yValue);
 355                          }
 356                      }
 357                      // Next try comparing as signed integers
 358                      {
 359                          Sint64 xValue;
 360 kumpf   1.33             Sint64 yValue;
 361                          if (XmlReader::stringToSignedInteger(
 362                                  x.getValue().getCString(), xValue) &&
 363                              XmlReader::stringToSignedInteger(
 364                                  y.getValue().getCString(), yValue))
 365                          {
 366                              return (xValue == yValue);
 367                          }
 368                      }
 369                      // Note: Keys may not be real values, so don't try comparing as reals
 370                      // We couldn't parse the numbers, so just compare the strings
 371                      return (String::equal(x.getValue(), y.getValue()));
 372                      break;
 373                  default:  // CIMKeyBinding::STRING
 374                      return (String::equal(x.getValue(), y.getValue()));
 375                      break;
 376                  }
 377              
 378                  PEGASUS_UNREACHABLE(return false;)
 379 kumpf   1.2  }
 380              
 381              
 382              ////////////////////////////////////////////////////////////////////////////////
 383              //
 384              // CIMObjectPath
 385              //
 386              ////////////////////////////////////////////////////////////////////////////////
 387              
 388              class CIMObjectPathRep
 389              {
 390              public:
 391                  CIMObjectPathRep()
 392                  {
 393                  }
 394              
 395                  CIMObjectPathRep(const CIMObjectPathRep& x)
 396                      : _host(x._host), _nameSpace(x._nameSpace),
 397                      _className(x._className), _keyBindings(x._keyBindings)
 398                  {
 399                  }
 400 kumpf   1.2  
 401                  CIMObjectPathRep(
 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          : _host(host), _nameSpace(nameSpace),
 407                      _className(className), _keyBindings(keyBindings)
 408                  {
 409                  }
 410              
 411                  ~CIMObjectPathRep()
 412                  {
 413                  }
 414              
 415                  CIMObjectPathRep& operator=(const CIMObjectPathRep& x)
 416                  {
 417                      if (&x != this)
 418                      {
 419                          _host = x._host;
 420                          _nameSpace = x._nameSpace;
 421                          _className = x._className;
 422                          _keyBindings = x._keyBindings;
 423                      }
 424                      return *this;
 425                  }
 426              
 427 kumpf   1.34     static Boolean isValidHostname(const String& hostname)
 428                  {
 429                      //------------------------------------------------------------------
 430                      // Validate the hostname.  The hostname value may or may not be a
 431                      // fully-qualified domain name (e.g., xyz.company.com) or may be an
 432                      // IP address.  A port number may follow the hostname.
 433                      // Hostnames must match one of the following regular expressions:
 434                      // ^([A-Za-z][A-Za-z0-9-]*)(\.[A-Za-z][A-Za-z0-9-]*)*(:[0-9]*)?$
 435                      // ^([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)(:[0-9]*)?$
 436                      //------------------------------------------------------------------
 437              
 438                      Uint32 i = 0;
 439              
 440                      if (isdigit(hostname[0]))
 441                      {
 442                          // Validate an IP address
 443              
 444                          for (Uint32 octet=1; octet<=4; octet++)
 445                          {
 446                              Uint32 octetValue = 0;
 447              
 448 kumpf   1.34                 if (!isdigit(hostname[i]))
 449                              {
 450                                  return false;
 451                              }
 452              
 453                              while (isdigit(hostname[i]))
 454                              {
 455                                  octetValue = octetValue*10 + (hostname[i] - '0');
 456                                  i++;
 457                              }
 458              
 459                              if (octetValue > 255)
 460                              {
 461                                  return false;
 462                              }
 463              
 464                              if ((octet != 4) && (hostname[i++] != '.'))
 465                              {
 466                                  return false;
 467                              }
 468                          }
 469 kumpf   1.34         }
 470                      else
 471                      {
 472                          // Validate a hostname
 473              
 474                          Boolean expectHostSegment = true;
 475              
 476                          while (expectHostSegment == true)
 477                          {
 478                              expectHostSegment = false;
 479              
 480                              if (!isalpha(hostname[i++]))
 481                              {
 482                                  return false;
 483                              }
 484              
 485                              while (isalnum(hostname[i]) || (hostname[i] == '-'))
 486                              {
 487                                  i++;
 488                              }
 489              
 490 kumpf   1.34                 if (hostname[i] == '.')
 491                              {
 492                                  i++;
 493                                  expectHostSegment = true;
 494                              }
 495                          }
 496                      }
 497              
 498                      // Check for a port number:
 499              
 500                      if (hostname[i] == ':')
 501                      {
 502                          if (!isdigit(hostname[++i]))
 503                          {
 504                              return false;
 505                          }
 506                      
 507                          while (isdigit(hostname[++i]));
 508                      }
 509              
 510                      return (hostname[i] == char(0));
 511 kumpf   1.34     }
 512              
 513 kumpf   1.2      //
 514                  // Contains port as well (e.g., myhost:1234).
 515                  //
 516                  String _host;
 517              
 518 kumpf   1.7      CIMNamespaceName _nameSpace;
 519                  CIMName _className;
 520 kumpf   1.16     Array<CIMKeyBinding> _keyBindings;
 521 kumpf   1.2  };
 522              
 523              
 524 a.arora 1.39 CIMObjectPath::CIMObjectPath()
 525 kumpf   1.2  {
 526 a.arora 1.39     _rep = new CIMObjectPathRep();
 527 kumpf   1.2  }
 528              
 529 a.arora 1.39 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x)
 530 kumpf   1.2  {
 531 a.arora 1.39     _rep = new CIMObjectPathRep(*x._rep);
 532 kumpf   1.2  }
 533              
 534              CIMObjectPath::CIMObjectPath(const String& objectName)
 535              {
 536                  // Test the objectName out to see if we get an exception
 537                  CIMObjectPath tmpRef;
 538                  tmpRef.set(objectName);
 539              
 540 a.arora 1.39     _rep = new CIMObjectPathRep(*tmpRef._rep);
 541 kumpf   1.2  }
 542              
 543              CIMObjectPath::CIMObjectPath(
 544                  const String& host,
 545 kumpf   1.7      const CIMNamespaceName& nameSpace,
 546                  const CIMName& className,
 547 kumpf   1.16     const Array<CIMKeyBinding>& keyBindings)
 548 kumpf   1.2  {
 549                  // Test the objectName out to see if we get an exception
 550                  CIMObjectPath tmpRef;
 551                  tmpRef.set(host, nameSpace, className, keyBindings);
 552              
 553 a.arora 1.39     _rep = new CIMObjectPathRep(*tmpRef._rep);
 554 kumpf   1.2  }
 555              
 556              CIMObjectPath::~CIMObjectPath()
 557              {
 558 a.arora 1.39     delete _rep;
 559 kumpf   1.2  }
 560              
 561              CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
 562              {
 563 a.arora 1.39     *_rep = *x._rep;
 564 kumpf   1.2      return *this;
 565              }
 566              
 567              void CIMObjectPath::clear()
 568              {
 569                  _rep->_host.clear();
 570                  _rep->_nameSpace.clear();
 571                  _rep->_className.clear();
 572                  _rep->_keyBindings.clear();
 573              }
 574              
 575              void CIMObjectPath::set(
 576                  const String& host,
 577 kumpf   1.7      const CIMNamespaceName& nameSpace,
 578                  const CIMName& className,
 579 kumpf   1.16     const Array<CIMKeyBinding>& keyBindings)
 580 kumpf   1.2  {
 581                 setHost(host);
 582                 setNameSpace(nameSpace);
 583                 setClassName(className);
 584                 setKeyBindings(keyBindings);
 585              }
 586              
 587 kumpf   1.22 Boolean _parseHostElement(
 588 kumpf   1.2      const String& objectName,
 589                  char*& p,
 590 kumpf   1.9      String& host)
 591 kumpf   1.2  {
 592                  // See if there is a host name (true if it begins with "//"):
 593 kumpf   1.32     // Host is of the form <hostname>:<port> and begins with "//"
 594 kumpf   1.2      // and ends with "/":
 595              
 596                  if (p[0] != '/' || p[1] != '/')
 597                  {
 598                      return false;
 599                  }
 600              
 601                  p += 2;
 602              
 603 kumpf   1.34     char* slash = strchr(p, '/');
 604                  if (!slash)
 605 chuck   1.23     {
 606 kumpf   1.34         throw MalformedObjectNameException(objectName);
 607 kumpf   1.2      }
 608              
 609 kumpf   1.34     String hostname = String(p, (Uint32)(slash - p));
 610                  if (!CIMObjectPathRep::isValidHostname(hostname))
 611 kumpf   1.2      {
 612 kumpf   1.10         throw MalformedObjectNameException(objectName);
 613 kumpf   1.2      }
 614 kumpf   1.34     host = hostname;
 615 kumpf   1.2  
 616 kumpf   1.31     // Do not step past the '/'; it will be consumed by the namespace parser
 617 kumpf   1.34     p = slash;
 618 kumpf   1.2  
 619                  return true;
 620              }
 621              
 622 kumpf   1.22 Boolean _parseNamespaceElement(
 623 kumpf   1.2      const String& objectName,
 624                  char*& p,
 625 kumpf   1.7      CIMNamespaceName& nameSpace)
 626 kumpf   1.2  {
 627                  // If we don't find a valid namespace name followed by a ':', we
 628                  // assume we're not looking at a namespace name.
 629              
 630 kumpf   1.7      char* colon = strchr(p, ':');
 631                  if (!colon)
 632                  {
 633                      return false;
 634                  }
 635              
 636 kumpf   1.25     // A ':' as part of a keybinding value should not be interpreted as 
 637                  // a namespace delimiter.  Since keybinding pairs follow the first '.'
 638                  // in the object path string, the ':' delimiter only counts if it
 639                  // appears before the '.'.
 640              
 641                  char* dot = strchr(p, '.');
 642                  if (dot && (dot < colon))
 643                  {
 644                      return false;
 645                  }
 646              
 647 kumpf   1.2      //----------------------------------------------------------------------
 648                  // Validate the namespace path.  Namespaces must match the following
 649                  // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
 650                  //----------------------------------------------------------------------
 651              
 652 david   1.27     String namespaceName = String(p, (Uint32)(colon - p));
 653 kumpf   1.7      if (!CIMNamespaceName::legal(namespaceName))
 654 kumpf   1.2      {
 655 kumpf   1.10         throw MalformedObjectNameException(objectName);
 656 kumpf   1.2      }
 657 kumpf   1.7      nameSpace = namespaceName;
 658 kumpf   1.2  
 659 kumpf   1.7      p = colon+1;
 660 kumpf   1.2      return true;
 661              }
 662              
 663              /**
 664 kumpf   1.29     ATTN-RK: The DMTF specification for the string form of an
 665                  object path makes it impossible for a parser to distinguish
 666                  between a key values of String type and Reference type.
 667              
 668                  Given the ambiguity, this implementation takes a guess at the
 669                  type of a quoted key value.  If the value can be parsed into
 670                  a CIMObjectPath with at least one key binding, the type is
 671                  set to REFERENCE.  Otherwise, the type is set to STRING.
 672                  Note: This algorithm appears to be in line with what the Sun
 673                  WBEM Services implementation does.
 674              
 675                  To be totally correct, it would be necessary to retrieve the
 676                  class definition and look up the types of the key properties
 677                  to determine how to interpret the key values.  This is clearly
 678                  too inefficient for internal transformations between
 679                  CIMObjectPaths and String values.
 680 kumpf   1.2  */
 681 kumpf   1.22 void _parseKeyBindingPairs(
 682 kumpf   1.2      const String& objectName,
 683                  char*& p,
 684 kumpf   1.16     Array<CIMKeyBinding>& keyBindings)  
 685 kumpf   1.2  {
 686                  // Get the key-value pairs:
 687              
 688                  while (*p)
 689                  {
 690                      // Get key part:
 691              
 692 kumpf   1.5          char* equalsign = strchr(p, '=');
 693                      if (!equalsign)
 694 kumpf   1.2          {
 695 kumpf   1.10             throw MalformedObjectNameException(objectName);
 696 kumpf   1.2          }
 697              
 698 kumpf   1.5          *equalsign = 0;
 699 kumpf   1.2  
 700 kumpf   1.17         if (!CIMName::legal(p))
 701 kumpf   1.10             throw MalformedObjectNameException(objectName);
 702 kumpf   1.2  
 703 kumpf   1.17         CIMName keyName (p);
 704              
 705 kumpf   1.2          // Get the value part:
 706              
 707                      String valueString;
 708 kumpf   1.5          p = equalsign + 1;
 709 kumpf   1.16         CIMKeyBinding::Type type;
 710 kumpf   1.2  
 711 kumpf   1.29         if (*p == '"')
 712 kumpf   1.2          {
 713 kumpf   1.29             // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
 714              
 715 kumpf   1.2              p++;
 716              
 717                          while (*p && *p != '"')
 718                          {
 719                              if (*p == '\\')
 720 kumpf   1.28                 {
 721 kumpf   1.2                      *p++;
 722              
 723 kumpf   1.28                     if ((*p != '\\') && (*p != '"'))
 724                                  {
 725                                      throw MalformedObjectNameException(objectName);
 726                                  }
 727                              }
 728              
 729 kumpf   1.2                  valueString.append(*p++);
 730                          }
 731              
 732                          if (*p++ != '"')
 733 kumpf   1.10                 throw MalformedObjectNameException(objectName);
 734 kumpf   1.2  
 735 kumpf   1.29             /*
 736                              Guess at the type of this quoted key value.  If the value
 737                              can be parsed into a CIMObjectPath with at least one key
 738                              binding, the type is assumed to be a REFERENCE.  Otherwise,
 739                              the type is set to STRING.  (See method header for details.)
 740                           */
 741 kumpf   1.16             type = CIMKeyBinding::STRING;
 742 kumpf   1.2  
 743 kumpf   1.29             try
 744 kumpf   1.2              {
 745 kumpf   1.29                 CIMObjectPath testForPath(valueString);
 746                              if (testForPath.getKeyBindings().size() > 0)
 747 kumpf   1.28                 {
 748 kumpf   1.29                     // We've found a reference value!
 749                                  type = CIMKeyBinding::REFERENCE;
 750 kumpf   1.28                 }
 751 kumpf   1.2              }
 752 kumpf   1.29             catch (Exception & e)
 753                          {
 754                              // Not a reference value; leave type as STRING
 755                          }
 756 kumpf   1.2          }
 757                      else if (toupper(*p) == 'T' || toupper(*p) == 'F')
 758                      {
 759 kumpf   1.16             type = CIMKeyBinding::BOOLEAN;
 760 kumpf   1.2  
 761                          char* r = p;
 762                          Uint32 n = 0;
 763              
 764                          while (*r && *r != ',')
 765                          {
 766                              *r = toupper(*r);
 767                              r++;
 768                              n++;
 769                          }
 770              
 771                          if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
 772                                ((strncmp(p, "FALSE", n) == 0) && n == 5)))
 773 kumpf   1.10                 throw MalformedObjectNameException(objectName);
 774 kumpf   1.2  
 775                          valueString.assign(p, n);
 776              
 777                          p = p + n;
 778                      }
 779                      else
 780                      {
 781 kumpf   1.16             type = CIMKeyBinding::NUMERIC;
 782 kumpf   1.2  
 783                          char* r = p;
 784                          Uint32 n = 0;
 785              
 786                          while (*r && *r != ',')
 787                          {
 788                              r++;
 789                              n++;
 790                          }
 791              
 792                          Boolean isComma = false;
 793                          if (*r)
 794                          {
 795                              *r = '\0';
 796                              isComma = true;
 797                          }
 798              
 799                          Sint64 x;
 800              
 801                          if (!XmlReader::stringToSignedInteger(p, x))
 802 kumpf   1.10                 throw MalformedObjectNameException(objectName);
 803 kumpf   1.2  
 804                          valueString.assign(p, n);
 805              
 806                          if (isComma)
 807                          {
 808                              *r = ',';
 809                          }
 810              
 811                          p = p + n;
 812                      }
 813              
 814 kumpf   1.17         keyBindings.append(CIMKeyBinding(keyName.getString (), valueString, 
 815                          type));
 816 kumpf   1.2  
 817                      if (*p)
 818                      {
 819                          if (*p++ != ',')
 820                          {
 821 kumpf   1.10                 throw MalformedObjectNameException(objectName);
 822 kumpf   1.2              }
 823                      }
 824                  }
 825              
 826                  _BubbleSort(keyBindings);
 827              }
 828              
 829 kumpf   1.9  void CIMObjectPath::set(const String& objectName)  
 830 kumpf   1.2  {
 831                  clear();
 832              
 833                  //--------------------------------------------------------------------------
 834                  // We will extract components from an object name. Here is an sample
 835                  // object name:
 836                  //
 837                  //     //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
 838                  //--------------------------------------------------------------------------
 839              
 840                  // Convert to a C String first:
 841              
 842 david   1.37     CString pCString = objectName.getCString();
 843 kumpf   1.26     char* p = const_cast<char*>((const char*) pCString);
 844 kumpf   1.2      Boolean gotHost;
 845                  Boolean gotNamespace;
 846              
 847                  gotHost = _parseHostElement(objectName, p, _rep->_host);
 848                  gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
 849              
 850                  if (gotHost && !gotNamespace)
 851                  {
 852 kumpf   1.10         throw MalformedObjectNameException(objectName);
 853 kumpf   1.2      }
 854              
 855                  // Extract the class name:
 856              
 857                  char* dot = strchr(p, '.');
 858              
 859                  if (!dot)
 860                  {
 861                      if (!CIMName::legal(p))
 862                      {
 863 kumpf   1.10             throw MalformedObjectNameException(objectName);
 864 kumpf   1.2          }
 865              
 866                      // ATTN: remove this later: a reference should only be able to hold
 867                      // an instance name.
 868              
 869 kumpf   1.17         _rep->_className = CIMName (p);
 870 kumpf   1.2          return;
 871                  }
 872              
 873 david   1.27     String className = String(p, (Uint32)(dot - p));
 874 kumpf   1.7      if (!CIMName::legal(className))
 875                  {
 876 kumpf   1.10         throw MalformedObjectNameException(objectName);
 877 kumpf   1.7      }
 878                  _rep->_className = className;
 879 kumpf   1.2  
 880                  // Advance past dot:
 881              
 882                  p = dot + 1;
 883              
 884                  _parseKeyBindingPairs(objectName, p, _rep->_keyBindings);
 885              }
 886              
 887              CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
 888              {
 889                  set(objectName);
 890                  return *this;
 891              }
 892              
 893              const String& CIMObjectPath::getHost() const
 894              {
 895                  return _rep->_host;
 896              }
 897              
 898              void CIMObjectPath::setHost(const String& host)
 899              {
 900 kumpf   1.35     if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
 901                  {
 902                      throw MalformedObjectNameException(host);
 903                  }
 904              
 905 kumpf   1.2      _rep->_host = host;
 906              }
 907              
 908 kumpf   1.7  const CIMNamespaceName& CIMObjectPath::getNameSpace() const
 909 kumpf   1.2  {
 910                  return _rep->_nameSpace;
 911              }
 912              
 913 kumpf   1.7  void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
 914 kumpf   1.2  {
 915                 _rep->_nameSpace = nameSpace;
 916              }
 917              
 918 kumpf   1.7  const CIMName& CIMObjectPath::getClassName() const
 919 kumpf   1.2  {
 920                  return _rep->_className;
 921              }
 922              
 923 kumpf   1.7  void CIMObjectPath::setClassName(const CIMName& className)
 924 kumpf   1.2  {
 925                  _rep->_className = className;
 926              }
 927              
 928 kumpf   1.16 const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
 929 kumpf   1.2  {
 930                  return _rep->_keyBindings;
 931              }
 932              
 933 kumpf   1.16 void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
 934 kumpf   1.2  {
 935                  _rep->_keyBindings = keyBindings;
 936                  _BubbleSort(_rep->_keyBindings);
 937              }
 938              
 939 kumpf   1.15 String CIMObjectPath::toString() const
 940 kumpf   1.2  {
 941                  String objectName;
 942              
 943                  // Get the host:
 944              
 945 kumpf   1.15     if (_rep->_host.size())
 946 kumpf   1.2      {
 947                      objectName = "//";
 948 kumpf   1.13         objectName.append(_rep->_host);
 949                      objectName.append("/");
 950 kumpf   1.2      }
 951              
 952                  // Get the namespace (if we have a host name, we must write namespace):
 953              
 954 kumpf   1.7      if (!_rep->_nameSpace.isNull() || _rep->_host.size())
 955 kumpf   1.2      {
 956 kumpf   1.17         objectName.append(_rep->_nameSpace.getString ());
 957 kumpf   1.13         objectName.append(":");
 958 kumpf   1.2      }
 959              
 960                  // Get the class name:
 961              
 962 kumpf   1.17     objectName.append(getClassName().getString ());
 963 kumpf   1.2  
 964 kumpf   1.9      //
 965                  //  ATTN-CAKG-P2-20020726:  The following condition does not correctly
 966                  //  distinguish instanceNames from classNames in every case
 967                  //  The instanceName of a singleton instance of a keyless class has no
 968                  //  key bindings
 969                  //
 970                  if (_rep->_keyBindings.size () != 0)
 971 kumpf   1.2      {
 972                      objectName.append('.');
 973              
 974                      // Append each key-value pair:
 975              
 976 kumpf   1.16         const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
 977 kumpf   1.2  
 978                      for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
 979                      {
 980 kumpf   1.17             objectName.append(keyBindings[i].getName().getString ());
 981 kumpf   1.2              objectName.append('=');
 982              
 983                          const String& value = _escapeSpecialCharacters(
 984                              keyBindings[i].getValue());
 985              
 986 kumpf   1.16             CIMKeyBinding::Type type = keyBindings[i].getType();
 987 kumpf   1.2          
 988 kumpf   1.16             if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
 989 kumpf   1.2                  objectName.append('"');
 990              
 991                          objectName.append(value);
 992              
 993 kumpf   1.16             if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
 994 kumpf   1.2                  objectName.append('"');
 995              
 996                          if (i + 1 != n)
 997                              objectName.append(',');
 998                      }
 999                  }
1000              
1001                  return objectName;
1002              }
1003              
1004 kumpf   1.15 String CIMObjectPath::_toStringCanonical() const
1005 kumpf   1.2  {
1006                  CIMObjectPath ref = *this;
1007              
1008 kumpf   1.33     // Normalize hostname by changing to lower case
1009                  ref._rep->_host.toLower(); // ICU_TODO:  
1010 kumpf   1.2  
1011 kumpf   1.33     // Normalize namespace by changing to lower case
1012                  if (!ref._rep->_nameSpace.isNull())
1013                  {
1014                      String nameSpaceLower = ref._rep->_nameSpace.getString();
1015                      nameSpaceLower.toLower(); // ICU_TODO:  
1016                      ref._rep->_nameSpace = nameSpaceLower;
1017                  }
1018              
1019                  // Normalize class name by changing to lower case
1020                  if (!ref._rep->_className.isNull())
1021                  {
1022                      String classNameLower = ref._rep->_className.getString();
1023                      classNameLower.toLower(); // ICU_TODO:  
1024                      ref._rep->_className = classNameLower;
1025                  }
1026 kumpf   1.2  
1027                  for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
1028                  {
1029 kumpf   1.33         // Normalize key binding name by changing to lower case
1030                      if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
1031                      {
1032                          String keyBindingNameLower = 
1033                              ref._rep->_keyBindings[i]._rep->_name.getString();
1034                          keyBindingNameLower.toLower(); // ICU_TODO:
1035                          ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
1036                      }
1037              
1038                      // Normalize the key value
1039                      switch (ref._rep->_keyBindings[i]._rep->_type)
1040                      {
1041                      case CIMKeyBinding::REFERENCE:
1042                          try
1043                          {
1044                              // Convert reference to CIMObjectPath and recurse
1045                              ref._rep->_keyBindings[i]._rep->_value =
1046                                  CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
1047                                      _toStringCanonical();
1048                          }
1049                          catch (Exception&)
1050 kumpf   1.33             {
1051                              // Leave value unchanged if the CIMObjectPath parsing fails
1052                          }
1053                          break;
1054                      case CIMKeyBinding::BOOLEAN:
1055                          // Normalize the boolean string by changing to lower case
1056                          ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
1057                          break;
1058                      case CIMKeyBinding::NUMERIC:
1059                          // Normalize the numeric string by converting to integer and back
1060                          Uint64 uValue;
1061                          Sint64 sValue;
1062                          // First try converting to unsigned integer
1063                          if (XmlReader::stringToUnsignedInteger(
1064                                  ref._rep->_keyBindings[i]._rep->_value.getCString(),
1065                                      uValue))
1066                          {
1067                              char buffer[32];  // Should need 21 chars max
1068                              sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
1069                              ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1070                          }
1071 kumpf   1.33             // Next try converting to signed integer
1072                          else if (XmlReader::stringToSignedInteger(
1073                                       ref._rep->_keyBindings[i]._rep->_value.getCString(),
1074                                           sValue))
1075                          {
1076                              char buffer[32];  // Should need 21 chars max
1077                              sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
1078                              ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1079                          }
1080                          // Leave value unchanged if it cannot be converted to an integer
1081                          break;
1082                      default:  // CIMKeyBinding::STRING
1083                          // No normalization required for STRING
1084                          break;
1085                      }
1086 kumpf   1.2      }
1087              
1088 kumpf   1.33     // Note: key bindings are sorted when set in the CIMObjectPath
1089 kumpf   1.12 
1090 kumpf   1.15     return ref.toString();
1091 kumpf   1.2  }
1092              
1093              Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
1094              {
1095                  return
1096 kumpf   1.33         String::equalNoCase(_rep->_host, x._rep->_host) &&
1097 kumpf   1.7          _rep->_nameSpace.equal(x._rep->_nameSpace) &&
1098                      _rep->_className.equal(x._rep->_className) &&
1099 kumpf   1.2          _rep->_keyBindings == x._rep->_keyBindings;
1100              }
1101              
1102              Uint32 CIMObjectPath::makeHashCode() const
1103              {
1104 kumpf   1.12     return HashFunc<String>::hash(_toStringCanonical());
1105 kumpf   1.2  }
1106              
1107              Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
1108              {
1109                  return x.identical(y);
1110              }
1111              
1112              Boolean operator!=(const CIMObjectPath& x, const CIMObjectPath& y)
1113              {
1114                  return !operator==(x, y);
1115              }
1116              
1117 kumpf   1.36 #ifdef PEGASUS_USE_DEPRECATED_INTERFACES
1118 kumpf   1.2  PEGASUS_STD(ostream)& operator<<(
1119                  PEGASUS_STD(ostream)& os,
1120                  const CIMObjectPath& x)
1121              {
1122                  return os << x.toString();
1123              }
1124 kumpf   1.22 #endif
1125 chip    1.1  
1126              PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2