public int compare(CorrelationKey o1, CorrelationKey o2) {
   if (o1 == null || o2 == null) {
     return 0;
   }
   // used only in sorting the correlation keys in the CorrelationKeySet; does not matter with
   // the values
   return o1.getCorrelationSetName().compareTo(o2.getCorrelationSetName());
 }
  /**
   * Adds a correlation key to this correlation key set. If a correlation key with the same
   * correlation set id already exists, the old one is replaced with the given new one.
   *
   * @param ck a correlation key to add
   * @return returns this correlation key set
   */
  public CorrelationKeySet add(CorrelationKey ck) {
    for (CorrelationKey key : correlationKeys) {
      if (key.getCorrelationSetName().equals(ck.getCorrelationSetName())) {
        correlationKeys.remove(ck);
        break;
      }
    }
    correlationKeys.add(ck);

    return this;
  }
  /**
   * Returns a canonical form of this correlation key set.
   *
   * @return
   */
  public String toCanonicalString() {
    StringBuffer buf = new StringBuffer();

    for (CorrelationKey ckey : correlationKeys) {
      if (buf.length() > 0) {
        buf.append(",");
      }
      buf.append("[").append(escapeRightBracket(ckey.toCanonicalString())).append("]");
    }

    return "@" + VERSION_2 + buf.toString();
  }
  /**
   * Finds all subsets of this correlation key set.
   *
   * @return a list of all subset correlation key sets
   */
  public List<CorrelationKeySet> findSubSets() {
    List<CorrelationKeySet> subSets = new ArrayList<CorrelationKeySet>();

    // if the key set contains a opaque key and at least one non-opaque key, take out the opaque key
    CorrelationKey opaqueKey = null;
    boolean containsNonOpaque = false;
    CorrelationKeySet explicitKeySet = new CorrelationKeySet();
    for (CorrelationKey ckey : correlationKeys) {
      // assumes only ONE opaque key if there is
      if (ckey.getCorrelationSetName().equals("-1")) {
        opaqueKey = ckey;
      } else {
        containsNonOpaque = true;
      }
      explicitKeySet.add(ckey);
    }
    if (opaqueKey != null && containsNonOpaque) {
      explicitKeySet.correlationKeys.remove(opaqueKey);
    }

    // we are generating (2 powered by the number of correlation keys) number of sub-sets
    for (int setIndex = 0;
        setIndex < Math.pow(2, explicitKeySet.correlationKeys.size());
        setIndex++) {
      CorrelationKeySet subKeySet = new CorrelationKeySet();
      int bitPattern = setIndex; // the bitPattern will be 0b0000, 0b0001, 0b0010 and so on
      Iterator<CorrelationKey> ckeys = explicitKeySet.iterator();
      while (ckeys.hasNext()
          && bitPattern > 0) { // bitPattern > 0 condition saves half of the iterations
        CorrelationKey ckey = ckeys.next();
        if ((bitPattern & 0x01) > 0) {
          subKeySet.add(ckey);
        }
        bitPattern = bitPattern >> 1;
      }

      if (!subKeySet.isEmpty()) { // we don't want an empty set
        subSets.add(subKeySet);
      }
    }

    if (subSets.isEmpty()) {
      subSets.add(new CorrelationKeySet());
    }

    return subSets;
  }
 /**
  * Returns true if this correlation key set contains the give correlation key.
  *
  * @param correlationKey a correlation key
  * @return
  */
 public boolean contains(CorrelationKey correlationKey) {
   Iterator<CorrelationKey> e = correlationKeys.iterator();
   if (correlationKey == null) {
     while (e.hasNext()) if (e.next() == null) return true;
   } else {
     while (e.hasNext()) {
       if (correlationKey.equals(e.next())) return true;
     }
   }
   return false;
 }