/** Test whether the (unordered) object class lists of two attributes contain the same */
  public boolean objectClassesChanged(DXAttributes a, DXAttributes b) {
    boolean result = false;
    try {
      String[] A = getAttributeValuesAsStringArray(a.getAllObjectClasses());
      String[] B = getAttributeValuesAsStringArray(b.getAllObjectClasses());

      Object[] test = CBArray.difference(A, B);
      if (test.length > 0) result = true;
      test = CBArray.difference(B, A);
      if (test.length > 0) result = true;

      return result;
    } catch (NamingException e) {
      log.log(Level.WARNING, "Error in TableAttributeEditor:objectClassesChanged ", e);
      return true;
    }
  }
  /** Writes the data currently in the table editor to the directory. */
  public void writeTableData() {

    myEditor.stopCellEditing();

    if (dataSource == null) // if ds is null, data is not modifiable...
    {
      CBUtility.error("no datasource to write data to in writeTableData()");
      return;
    } // shouldn't happen

    DXEntry oldEntry = tableData.getOldEntry();

    DXEntry newEntry = tableData.getNewEntry();

    /*   Check to see if major surgery is needed - whether the user has been
     *   messing with the object class list. */

    if (classChangedOriginalEntry != null) {

      // use the saved state of the pre-class-changed entry as the 'old entry'
      // state.
      oldEntry = classChangedOriginalEntry;
      classChangedOriginalEntry =
          null; // this is only used once! (either the object class change will
      // now succeed, or fail - either way, the entry state is reset to
      // match what's in the directory.)

      if (objectClassesChanged(oldEntry, newEntry)) {
        oldEntry.removeEmptyAttributes();

        newEntry.setStatus(oldEntry.getStatus());

        Object[] delSet =
            CBArray.difference(oldEntry.toIDStringArray(), newEntry.toIDStringArray());

        /* if there *are* attributes that should no longer exist, delete them by adding them (blanked)
         * to the complete 'newAtts' set of *all* known attributes. */

        if ((delSet != null) && (delSet.length > 0)) {
          for (int i = 0; i < delSet.length; i++) {
            newEntry.put(
                new DXAttribute(
                    delSet[i].toString())); // overwrite old values with an empty attribute
          }
        }
      }
    }

    dataSource.modifyEntry(oldEntry, newEntry);
  }