(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 a.arora 1.38 //              Amit K Arora, IBM (amita@in.ibm.com)
  32 chip    1.1  //
  33              //%/////////////////////////////////////////////////////////////////////////////
  34              
  35 kumpf   1.2  #include <Pegasus/Common/Config.h>
  36              #include <cctype>
  37              #include <cstring>
  38 kumpf   1.22 #include <iostream>
  39 kumpf   1.2  #include "HashTable.h"
  40              #include "CIMObjectPath.h"
  41              #include "Indentor.h"
  42              #include "CIMName.h"
  43              #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.38 CIMKeyBinding::CIMKeyBinding():
 181                          _rep(new CIMKeyBindingRep()) 
 182 kumpf   1.2  {
 183              }
 184              
 185 a.arora 1.38 CIMKeyBinding::CIMKeyBinding(const CIMKeyBinding& x):
 186                          _rep(new CIMKeyBindingRep(*(x._rep.get())))
 187 kumpf   1.2  {
 188              }
 189              
 190 a.arora 1.38 CIMKeyBinding::CIMKeyBinding(const CIMName& name, const String& value, Type type) :
 191                          _rep(new CIMKeyBindingRep(name, value, type)) 
 192 kumpf   1.2  {
 193              }
 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.38     _rep.reset(new CIMKeyBindingRep(name, kbValue, kbType));
 224 kumpf   1.18 }
 225              
 226 kumpf   1.16 CIMKeyBinding::~CIMKeyBinding()
 227 kumpf   1.2  {
 228              }
 229              
 230 kumpf   1.16 CIMKeyBinding& CIMKeyBinding::operator=(const CIMKeyBinding& x)
 231 kumpf   1.2  {
 232 a.arora 1.38     CIMKeyBindingRep *tmp = new CIMKeyBindingRep(*x._rep.get());
 233                  _rep.reset(tmp);
 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.38 CIMObjectPath::CIMObjectPath() :
 525                       _rep(new CIMObjectPathRep()) 
 526 kumpf   1.2  {
 527 a.arora 1.38     
 528 kumpf   1.2  }
 529              
 530 a.arora 1.38 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x) :
 531                       _rep(new CIMObjectPathRep(*x._rep.get())) 
 532 kumpf   1.2  {
 533              }
 534              
 535              CIMObjectPath::CIMObjectPath(const String& objectName)
 536              {
 537                  // Test the objectName out to see if we get an exception
 538                  CIMObjectPath tmpRef;
 539                  tmpRef.set(objectName);
 540              
 541 a.arora 1.38     _rep.reset(new CIMObjectPathRep(*tmpRef._rep.get()));
 542 kumpf   1.2  }
 543              
 544              CIMObjectPath::CIMObjectPath(
 545                  const String& host,
 546 kumpf   1.7      const CIMNamespaceName& nameSpace,
 547                  const CIMName& className,
 548 kumpf   1.16     const Array<CIMKeyBinding>& keyBindings)
 549 kumpf   1.2  {
 550                  // Test the objectName out to see if we get an exception
 551                  CIMObjectPath tmpRef;
 552                  tmpRef.set(host, nameSpace, className, keyBindings);
 553              
 554 a.arora 1.38     _rep.reset(new CIMObjectPathRep(*tmpRef._rep.get()));
 555 kumpf   1.2  }
 556              
 557              CIMObjectPath::~CIMObjectPath()
 558              {
 559              }
 560              
 561              CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
 562              {
 563 a.arora 1.38     CIMObjectPathRep *tmp = new CIMObjectPathRep(*x._rep.get());
 564                  _rep.reset(tmp);
 565 kumpf   1.2      return *this;
 566              }
 567              
 568              void CIMObjectPath::clear()
 569              {
 570                  _rep->_host.clear();
 571                  _rep->_nameSpace.clear();
 572                  _rep->_className.clear();
 573                  _rep->_keyBindings.clear();
 574              }
 575              
 576              void CIMObjectPath::set(
 577                  const String& host,
 578 kumpf   1.7      const CIMNamespaceName& nameSpace,
 579                  const CIMName& className,
 580 kumpf   1.16     const Array<CIMKeyBinding>& keyBindings)
 581 kumpf   1.2  {
 582                 setHost(host);
 583                 setNameSpace(nameSpace);
 584                 setClassName(className);
 585                 setKeyBindings(keyBindings);
 586              }
 587              
 588 kumpf   1.22 Boolean _parseHostElement(
 589 kumpf   1.2      const String& objectName,
 590                  char*& p,
 591 kumpf   1.9      String& host)
 592 kumpf   1.2  {
 593                  // See if there is a host name (true if it begins with "//"):
 594 kumpf   1.32     // Host is of the form <hostname>:<port> and begins with "//"
 595 kumpf   1.2      // and ends with "/":
 596              
 597                  if (p[0] != '/' || p[1] != '/')
 598                  {
 599                      return false;
 600                  }
 601              
 602                  p += 2;
 603              
 604 kumpf   1.34     char* slash = strchr(p, '/');
 605                  if (!slash)
 606 chuck   1.23     {
 607 kumpf   1.34         throw MalformedObjectNameException(objectName);
 608 kumpf   1.2      }
 609              
 610 kumpf   1.34     String hostname = String(p, (Uint32)(slash - p));
 611                  if (!CIMObjectPathRep::isValidHostname(hostname))
 612 kumpf   1.2      {
 613 kumpf   1.10         throw MalformedObjectNameException(objectName);
 614 kumpf   1.2      }
 615 kumpf   1.34     host = hostname;
 616 kumpf   1.2  
 617 kumpf   1.31     // Do not step past the '/'; it will be consumed by the namespace parser
 618 kumpf   1.34     p = slash;
 619 kumpf   1.2  
 620                  return true;
 621              }
 622              
 623 kumpf   1.22 Boolean _parseNamespaceElement(
 624 kumpf   1.2      const String& objectName,
 625                  char*& p,
 626 kumpf   1.7      CIMNamespaceName& nameSpace)
 627 kumpf   1.2  {
 628                  // If we don't find a valid namespace name followed by a ':', we
 629                  // assume we're not looking at a namespace name.
 630              
 631 kumpf   1.7      char* colon = strchr(p, ':');
 632                  if (!colon)
 633                  {
 634                      return false;
 635                  }
 636              
 637 kumpf   1.25     // A ':' as part of a keybinding value should not be interpreted as 
 638                  // a namespace delimiter.  Since keybinding pairs follow the first '.'
 639                  // in the object path string, the ':' delimiter only counts if it
 640                  // appears before the '.'.
 641              
 642                  char* dot = strchr(p, '.');
 643                  if (dot && (dot < colon))
 644                  {
 645                      return false;
 646                  }
 647              
 648 kumpf   1.2      //----------------------------------------------------------------------
 649                  // Validate the namespace path.  Namespaces must match the following
 650                  // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
 651                  //----------------------------------------------------------------------
 652              
 653 david   1.27     String namespaceName = String(p, (Uint32)(colon - p));
 654 kumpf   1.7      if (!CIMNamespaceName::legal(namespaceName))
 655 kumpf   1.2      {
 656 kumpf   1.10         throw MalformedObjectNameException(objectName);
 657 kumpf   1.2      }
 658 kumpf   1.7      nameSpace = namespaceName;
 659 kumpf   1.2  
 660 kumpf   1.7      p = colon+1;
 661 kumpf   1.2      return true;
 662              }
 663              
 664              /**
 665 kumpf   1.29     ATTN-RK: The DMTF specification for the string form of an
 666                  object path makes it impossible for a parser to distinguish
 667                  between a key values of String type and Reference type.
 668              
 669                  Given the ambiguity, this implementation takes a guess at the
 670                  type of a quoted key value.  If the value can be parsed into
 671                  a CIMObjectPath with at least one key binding, the type is
 672                  set to REFERENCE.  Otherwise, the type is set to STRING.
 673                  Note: This algorithm appears to be in line with what the Sun
 674                  WBEM Services implementation does.
 675              
 676                  To be totally correct, it would be necessary to retrieve the
 677                  class definition and look up the types of the key properties
 678                  to determine how to interpret the key values.  This is clearly
 679                  too inefficient for internal transformations between
 680                  CIMObjectPaths and String values.
 681 kumpf   1.2  */
 682 kumpf   1.22 void _parseKeyBindingPairs(
 683 kumpf   1.2      const String& objectName,
 684                  char*& p,
 685 kumpf   1.16     Array<CIMKeyBinding>& keyBindings)  
 686 kumpf   1.2  {
 687                  // Get the key-value pairs:
 688              
 689                  while (*p)
 690                  {
 691                      // Get key part:
 692              
 693 kumpf   1.5          char* equalsign = strchr(p, '=');
 694                      if (!equalsign)
 695 kumpf   1.2          {
 696 kumpf   1.10             throw MalformedObjectNameException(objectName);
 697 kumpf   1.2          }
 698              
 699 kumpf   1.5          *equalsign = 0;
 700 kumpf   1.2  
 701 kumpf   1.17         if (!CIMName::legal(p))
 702 kumpf   1.10             throw MalformedObjectNameException(objectName);
 703 kumpf   1.2  
 704 kumpf   1.17         CIMName keyName (p);
 705              
 706 kumpf   1.2          // Get the value part:
 707              
 708                      String valueString;
 709 kumpf   1.5          p = equalsign + 1;
 710 kumpf   1.16         CIMKeyBinding::Type type;
 711 kumpf   1.2  
 712 kumpf   1.29         if (*p == '"')
 713 kumpf   1.2          {
 714 kumpf   1.29             // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
 715              
 716 kumpf   1.2              p++;
 717              
 718                          while (*p && *p != '"')
 719                          {
 720                              if (*p == '\\')
 721 kumpf   1.28                 {
 722 kumpf   1.2                      *p++;
 723              
 724 kumpf   1.28                     if ((*p != '\\') && (*p != '"'))
 725                                  {
 726                                      throw MalformedObjectNameException(objectName);
 727                                  }
 728                              }
 729              
 730 kumpf   1.2                  valueString.append(*p++);
 731                          }
 732              
 733                          if (*p++ != '"')
 734 kumpf   1.10                 throw MalformedObjectNameException(objectName);
 735 kumpf   1.2  
 736 kumpf   1.29             /*
 737                              Guess at the type of this quoted key value.  If the value
 738                              can be parsed into a CIMObjectPath with at least one key
 739                              binding, the type is assumed to be a REFERENCE.  Otherwise,
 740                              the type is set to STRING.  (See method header for details.)
 741                           */
 742 kumpf   1.16             type = CIMKeyBinding::STRING;
 743 kumpf   1.2  
 744 kumpf   1.29             try
 745 kumpf   1.2              {
 746 kumpf   1.29                 CIMObjectPath testForPath(valueString);
 747                              if (testForPath.getKeyBindings().size() > 0)
 748 kumpf   1.28                 {
 749 kumpf   1.29                     // We've found a reference value!
 750                                  type = CIMKeyBinding::REFERENCE;
 751 kumpf   1.28                 }
 752 kumpf   1.2              }
 753 kumpf   1.29             catch (Exception & e)
 754                          {
 755                              // Not a reference value; leave type as STRING
 756                          }
 757 kumpf   1.2          }
 758                      else if (toupper(*p) == 'T' || toupper(*p) == 'F')
 759                      {
 760 kumpf   1.16             type = CIMKeyBinding::BOOLEAN;
 761 kumpf   1.2  
 762                          char* r = p;
 763                          Uint32 n = 0;
 764              
 765                          while (*r && *r != ',')
 766                          {
 767                              *r = toupper(*r);
 768                              r++;
 769                              n++;
 770                          }
 771              
 772                          if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
 773                                ((strncmp(p, "FALSE", n) == 0) && n == 5)))
 774 kumpf   1.10                 throw MalformedObjectNameException(objectName);
 775 kumpf   1.2  
 776                          valueString.assign(p, n);
 777              
 778                          p = p + n;
 779                      }
 780                      else
 781                      {
 782 kumpf   1.16             type = CIMKeyBinding::NUMERIC;
 783 kumpf   1.2  
 784                          char* r = p;
 785                          Uint32 n = 0;
 786              
 787                          while (*r && *r != ',')
 788                          {
 789                              r++;
 790                              n++;
 791                          }
 792              
 793                          Boolean isComma = false;
 794                          if (*r)
 795                          {
 796                              *r = '\0';
 797                              isComma = true;
 798                          }
 799              
 800                          Sint64 x;
 801              
 802                          if (!XmlReader::stringToSignedInteger(p, x))
 803 kumpf   1.10                 throw MalformedObjectNameException(objectName);
 804 kumpf   1.2  
 805                          valueString.assign(p, n);
 806              
 807                          if (isComma)
 808                          {
 809                              *r = ',';
 810                          }
 811              
 812                          p = p + n;
 813                      }
 814              
 815 kumpf   1.17         keyBindings.append(CIMKeyBinding(keyName.getString (), valueString, 
 816                          type));
 817 kumpf   1.2  
 818                      if (*p)
 819                      {
 820                          if (*p++ != ',')
 821                          {
 822 kumpf   1.10                 throw MalformedObjectNameException(objectName);
 823 kumpf   1.2              }
 824                      }
 825                  }
 826              
 827                  _BubbleSort(keyBindings);
 828              }
 829              
 830 kumpf   1.9  void CIMObjectPath::set(const String& objectName)  
 831 kumpf   1.2  {
 832                  clear();
 833              
 834                  //--------------------------------------------------------------------------
 835                  // We will extract components from an object name. Here is an sample
 836                  // object name:
 837                  //
 838                  //     //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
 839                  //--------------------------------------------------------------------------
 840              
 841                  // Convert to a C String first:
 842              
 843 david   1.37     CString pCString = objectName.getCString();
 844 kumpf   1.26     char* p = const_cast<char*>((const char*) pCString);
 845 kumpf   1.2      Boolean gotHost;
 846                  Boolean gotNamespace;
 847              
 848                  gotHost = _parseHostElement(objectName, p, _rep->_host);
 849                  gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
 850              
 851                  if (gotHost && !gotNamespace)
 852                  {
 853 kumpf   1.10         throw MalformedObjectNameException(objectName);
 854 kumpf   1.2      }
 855              
 856                  // Extract the class name:
 857              
 858                  char* dot = strchr(p, '.');
 859              
 860                  if (!dot)
 861                  {
 862                      if (!CIMName::legal(p))
 863                      {
 864 kumpf   1.10             throw MalformedObjectNameException(objectName);
 865 kumpf   1.2          }
 866              
 867                      // ATTN: remove this later: a reference should only be able to hold
 868                      // an instance name.
 869              
 870 kumpf   1.17         _rep->_className = CIMName (p);
 871 kumpf   1.2          return;
 872                  }
 873              
 874 david   1.27     String className = String(p, (Uint32)(dot - p));
 875 kumpf   1.7      if (!CIMName::legal(className))
 876                  {
 877 kumpf   1.10         throw MalformedObjectNameException(objectName);
 878 kumpf   1.7      }
 879                  _rep->_className = className;
 880 kumpf   1.2  
 881                  // Advance past dot:
 882              
 883                  p = dot + 1;
 884              
 885                  _parseKeyBindingPairs(objectName, p, _rep->_keyBindings);
 886              }
 887              
 888              CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
 889              {
 890                  set(objectName);
 891                  return *this;
 892              }
 893              
 894              const String& CIMObjectPath::getHost() const
 895              {
 896                  return _rep->_host;
 897              }
 898              
 899              void CIMObjectPath::setHost(const String& host)
 900              {
 901 kumpf   1.35     if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
 902                  {
 903                      throw MalformedObjectNameException(host);
 904                  }
 905              
 906 kumpf   1.2      _rep->_host = host;
 907              }
 908              
 909 kumpf   1.7  const CIMNamespaceName& CIMObjectPath::getNameSpace() const
 910 kumpf   1.2  {
 911                  return _rep->_nameSpace;
 912              }
 913              
 914 kumpf   1.7  void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
 915 kumpf   1.2  {
 916                 _rep->_nameSpace = nameSpace;
 917              }
 918              
 919 kumpf   1.7  const CIMName& CIMObjectPath::getClassName() const
 920 kumpf   1.2  {
 921                  return _rep->_className;
 922              }
 923              
 924 kumpf   1.7  void CIMObjectPath::setClassName(const CIMName& className)
 925 kumpf   1.2  {
 926                  _rep->_className = className;
 927              }
 928              
 929 kumpf   1.16 const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
 930 kumpf   1.2  {
 931                  return _rep->_keyBindings;
 932              }
 933              
 934 kumpf   1.16 void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
 935 kumpf   1.2  {
 936                  _rep->_keyBindings = keyBindings;
 937                  _BubbleSort(_rep->_keyBindings);
 938              }
 939              
 940 kumpf   1.15 String CIMObjectPath::toString() const
 941 kumpf   1.2  {
 942                  String objectName;
 943              
 944                  // Get the host:
 945              
 946 kumpf   1.15     if (_rep->_host.size())
 947 kumpf   1.2      {
 948                      objectName = "//";
 949 kumpf   1.13         objectName.append(_rep->_host);
 950                      objectName.append("/");
 951 kumpf   1.2      }
 952              
 953                  // Get the namespace (if we have a host name, we must write namespace):
 954              
 955 kumpf   1.7      if (!_rep->_nameSpace.isNull() || _rep->_host.size())
 956 kumpf   1.2      {
 957 kumpf   1.17         objectName.append(_rep->_nameSpace.getString ());
 958 kumpf   1.13         objectName.append(":");
 959 kumpf   1.2      }
 960              
 961                  // Get the class name:
 962              
 963 kumpf   1.17     objectName.append(getClassName().getString ());
 964 kumpf   1.2  
 965 kumpf   1.9      //
 966                  //  ATTN-CAKG-P2-20020726:  The following condition does not correctly
 967                  //  distinguish instanceNames from classNames in every case
 968                  //  The instanceName of a singleton instance of a keyless class has no
 969                  //  key bindings
 970                  //
 971                  if (_rep->_keyBindings.size () != 0)
 972 kumpf   1.2      {
 973                      objectName.append('.');
 974              
 975                      // Append each key-value pair:
 976              
 977 kumpf   1.16         const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
 978 kumpf   1.2  
 979                      for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
 980                      {
 981 kumpf   1.17             objectName.append(keyBindings[i].getName().getString ());
 982 kumpf   1.2              objectName.append('=');
 983              
 984                          const String& value = _escapeSpecialCharacters(
 985                              keyBindings[i].getValue());
 986              
 987 kumpf   1.16             CIMKeyBinding::Type type = keyBindings[i].getType();
 988 kumpf   1.2          
 989 kumpf   1.16             if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
 990 kumpf   1.2                  objectName.append('"');
 991              
 992                          objectName.append(value);
 993              
 994 kumpf   1.16             if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
 995 kumpf   1.2                  objectName.append('"');
 996              
 997                          if (i + 1 != n)
 998                              objectName.append(',');
 999                      }
1000                  }
1001              
1002                  return objectName;
1003              }
1004              
1005 kumpf   1.15 String CIMObjectPath::_toStringCanonical() const
1006 kumpf   1.2  {
1007                  CIMObjectPath ref = *this;
1008              
1009 kumpf   1.33     // Normalize hostname by changing to lower case
1010                  ref._rep->_host.toLower(); // ICU_TODO:  
1011 kumpf   1.2  
1012 kumpf   1.33     // Normalize namespace by changing to lower case
1013                  if (!ref._rep->_nameSpace.isNull())
1014                  {
1015                      String nameSpaceLower = ref._rep->_nameSpace.getString();
1016                      nameSpaceLower.toLower(); // ICU_TODO:  
1017                      ref._rep->_nameSpace = nameSpaceLower;
1018                  }
1019              
1020                  // Normalize class name by changing to lower case
1021                  if (!ref._rep->_className.isNull())
1022                  {
1023                      String classNameLower = ref._rep->_className.getString();
1024                      classNameLower.toLower(); // ICU_TODO:  
1025                      ref._rep->_className = classNameLower;
1026                  }
1027 kumpf   1.2  
1028                  for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
1029                  {
1030 kumpf   1.33         // Normalize key binding name by changing to lower case
1031                      if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
1032                      {
1033                          String keyBindingNameLower = 
1034                              ref._rep->_keyBindings[i]._rep->_name.getString();
1035                          keyBindingNameLower.toLower(); // ICU_TODO:
1036                          ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
1037                      }
1038              
1039                      // Normalize the key value
1040                      switch (ref._rep->_keyBindings[i]._rep->_type)
1041                      {
1042                      case CIMKeyBinding::REFERENCE:
1043                          try
1044                          {
1045                              // Convert reference to CIMObjectPath and recurse
1046                              ref._rep->_keyBindings[i]._rep->_value =
1047                                  CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
1048                                      _toStringCanonical();
1049                          }
1050                          catch (Exception&)
1051 kumpf   1.33             {
1052                              // Leave value unchanged if the CIMObjectPath parsing fails
1053                          }
1054                          break;
1055                      case CIMKeyBinding::BOOLEAN:
1056                          // Normalize the boolean string by changing to lower case
1057                          ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
1058                          break;
1059                      case CIMKeyBinding::NUMERIC:
1060                          // Normalize the numeric string by converting to integer and back
1061                          Uint64 uValue;
1062                          Sint64 sValue;
1063                          // First try converting to unsigned integer
1064                          if (XmlReader::stringToUnsignedInteger(
1065                                  ref._rep->_keyBindings[i]._rep->_value.getCString(),
1066                                      uValue))
1067                          {
1068                              char buffer[32];  // Should need 21 chars max
1069                              sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
1070                              ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1071                          }
1072 kumpf   1.33             // Next try converting to signed integer
1073                          else if (XmlReader::stringToSignedInteger(
1074                                       ref._rep->_keyBindings[i]._rep->_value.getCString(),
1075                                           sValue))
1076                          {
1077                              char buffer[32];  // Should need 21 chars max
1078                              sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
1079                              ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1080                          }
1081                          // Leave value unchanged if it cannot be converted to an integer
1082                          break;
1083                      default:  // CIMKeyBinding::STRING
1084                          // No normalization required for STRING
1085                          break;
1086                      }
1087 kumpf   1.2      }
1088              
1089 kumpf   1.33     // Note: key bindings are sorted when set in the CIMObjectPath
1090 kumpf   1.12 
1091 kumpf   1.15     return ref.toString();
1092 kumpf   1.2  }
1093              
1094              Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
1095              {
1096                  return
1097 kumpf   1.33         String::equalNoCase(_rep->_host, x._rep->_host) &&
1098 kumpf   1.7          _rep->_nameSpace.equal(x._rep->_nameSpace) &&
1099                      _rep->_className.equal(x._rep->_className) &&
1100 kumpf   1.2          _rep->_keyBindings == x._rep->_keyBindings;
1101              }
1102              
1103              Uint32 CIMObjectPath::makeHashCode() const
1104              {
1105 kumpf   1.12     return HashFunc<String>::hash(_toStringCanonical());
1106 kumpf   1.2  }
1107              
1108              Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
1109              {
1110                  return x.identical(y);
1111              }
1112              
1113              Boolean operator!=(const CIMObjectPath& x, const CIMObjectPath& y)
1114              {
1115                  return !operator==(x, y);
1116              }
1117              
1118 kumpf   1.36 #ifdef PEGASUS_USE_DEPRECATED_INTERFACES
1119 kumpf   1.2  PEGASUS_STD(ostream)& operator<<(
1120                  PEGASUS_STD(ostream)& os,
1121                  const CIMObjectPath& x)
1122              {
1123                  return os << x.toString();
1124              }
1125 kumpf   1.22 #endif
1126 chip    1.1  
1127              PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2