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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2