public void printUsers(tcDataProvider dp) {
    try {

      tcUserOperationsIntf usrIntf =
          (tcUserOperationsIntf)
              tcUtilityFactory.getUtility(dp, "Thor.API.Operations.tcUserOperationsIntf");

      /*
               ConfigurationClient.ComplexSetting config =
                   ConfigurationClient.getComplexSettingByPath("Discovery.CoreServer");
               final Hashtable env = config.getAllSettings();
               tcSignatureMessage moSignature =
                   tcCryptoUtil.sign("xelsysadm", "PrivateKey");
               tcUtilityFactory m_utilFactory =
                   new tcUtilityFactory(env, moSignature);

               tcUserOperationsIntf userIntf =
                   (tcUserOperationsIntf)m_utilFactory.getUtility("Thor.API.Operations.tcUserOperationsIntf");
      */

      tcResultSet rs =
          usrIntf.findUsersFiltered(
              new HashMap(), new String[] {"Users.User ID", "Users.First Name", "Users.Last Name"});

      for (int i = 0; i < rs.getRowCount(); i++) {
        rs.goToRow(i);
        System.out.println(
            rs.getStringValue("Users.User ID")
                + " "
                + rs.getStringValue("Users.First Name")
                + rs.getStringValue("Users.Last Name"));
      }

    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
  private void revokeMailbox(long userKey) {
    // revokeProvisioning(dataProvider, userKey, "COMMSDIR_CREATEMAILBOX");
    tcUserOperationsIntf rUserUtility = null;
    tcProvisioningOperationsIntf rProvUtility = null;
    TaskDefinitionOperationsIntf rTaskUtility = null;

    try {
      tcDataProvider dataProvider = this.getDataBase();
      rProvUtility =
          (tcProvisioningOperationsIntf)
              tcUtilityFactory.getUtility(
                  dataProvider, "Thor.API.Operations.tcProvisioningOperationsIntf");
      rUserUtility =
          (tcUserOperationsIntf)
              tcUtilityFactory.getUtility(dataProvider, "Thor.API.Operations.tcUserOperationsIntf");
      rTaskUtility =
          (TaskDefinitionOperationsIntf)
              tcUtilityFactory.getUtility(
                  dataProvider, "Thor.API.Operations.TaskDefinitionOperationsIntf");
    } catch (Exception e) {
      logger.error(
          connectorName
              + " Failed to get prov/task/user utility for revoking mailbox -- returning");
      return;
    }

    HashMap<String, Long> taskkeys = null;
    tcResultSet rResultSet = null;

    try {
      rResultSet = rUserUtility.getObjects(userKey);
    } catch (Exception e) {
      logger.warn(
          connectorName
              + " Exception getting objects for user during revocation process -- returning, but you may want to investigate the exception: "
              + e.getMessage());
    }
    try {
      long processInstanceKey = -1;
      for (int i = 0; i < rResultSet.getRowCount(); i++) {
        rResultSet.goToRow(i);
        String objectName = rResultSet.getStringValue("Objects.Name");
        String objectStatus = rResultSet.getStringValue("Objects.Object Status.Status");
        if (objectName != null
            && objectName.equals("COMMSDIR_CREATEMAILBOX")
            && objectStatus != null
            && objectStatus.equals("Provisioned")) {
          processInstanceKey = rResultSet.getLongValue("Process Instance.Key");
          break;
        }
      }
      if (processInstanceKey == -1) {
        logger.warn(
            connectorName
                + " Attempted to revoke mailbox provisioning for users key "
                + userKey
                + " but user is not provisioned -- returning");
        return;
      }

      long taskKey = getTaskKeys(rTaskUtility, processInstanceKey);

      long taskInstanceKey = rProvUtility.addProcessTaskInstance(taskKey, processInstanceKey);
      logger.info(connectorName + " revoked mailbox for users key " + userKey);
    } catch (Exception e) {
      logger.warn(
          connectorName
              + " Was unable to revoke mailbox provisioning for user with users key "
              + userKey
              + ". Returning, but you need to investigate further");
      return;
    }
  }
  /**
   * Method to acquire the duACMailboxExists attributes for all users listed in the OIM database,
   * and return the result as a large HashMap. This map is from String to String, and indexed by
   * unique ID.
   *
   * <p>The map is used for the comparison process by which we determine whether to update
   * duACMailboxExists for a user (and whether to trigger the revocation process for provisioning
   * for the mailbox).
   */
  private HashMap<String, String> getOIMData() {
    Hashtable mhPeopleSearchCriteria = new Hashtable();
    Hashtable mhAccountsSearchCriteria = new Hashtable();
    Hashtable mhTestSearchCriteria = new Hashtable();
    mhPeopleSearchCriteria.put("USR_UDF_ENTRYTYPE", "people"); // get people
    mhAccountsSearchCriteria.put("USR_UDF_ENTRYTYPE", "accounts");
    mhTestSearchCriteria.put("USR_UDF_ENTRYTYPE", "test");
    mhPeopleSearchCriteria.put("Users.Status", "Active");
    mhAccountsSearchCriteria.put("Users.Status", "Active");
    mhTestSearchCriteria.put("Users.Status", "Active");

    tcResultSet moResultSet;
    HashMap retval = new HashMap();
    String[] attrsToGet = {"Users.User ID", "USR_UDF_ACMAILBOXEXISTS"};

    try {
      moUserUtility =
          (tcUserOperationsIntf) super.getUtility("Thor.API.Operations.tcUserOperationsIntf");

      // Do the work for people first, since they're the bulk of us
      try {
        moResultSet = moUserUtility.findUsersFiltered(mhPeopleSearchCriteria, attrsToGet);
      } catch (Exception e) {
        logger.error(
            connectorName
                + " Exception trying to find all people in the OIM database "
                + e.getMessage());
        return null; // null return to signal failure
      }
      if (moResultSet.getRowCount() < 1) {
        logger.error(
            connectorName + " Failed to find any people in OIM -- something must be wrong here");
        return null;
      }
      // Otherwise, we have at least one user
      // add to the hashmap
      for (int i = 0; i < moResultSet.getRowCount(); i++) {
        moResultSet.goToRow(i);
        retval.put(
            moResultSet.getStringValue("Users.User ID"),
            moResultSet.getStringValue("USR_UDF_ACMAILBOXEXISTS"));
      }
    } catch (Exception e) {
      // Exception whiel retrieving OIM user data
      logger.error(
          connectorName
              + " Unexpected exception while retrieving OIM user information set "
              + e.getMessage());
      throw new RuntimeException(
          connectorName
              + " Exception while retrieving OIM user (people) information set "
              + e.getMessage(),
          e);
    }
    try {
      moUserUtility =
          (tcUserOperationsIntf) super.getUtility("Thor.API.Operations.tcUserOperationsIntf");

      // Do the work for people first, since they're the bulk of us
      try {
        moResultSet = moUserUtility.findUsersFiltered(mhAccountsSearchCriteria, attrsToGet);
      } catch (Exception e) {
        logger.error(
            connectorName
                + " Exception trying to find all accounts in the OIM database "
                + e.getMessage());
        return null; // null return to signal failure
      }
      if (moResultSet.getRowCount() < 1) {
        logger.error(
            connectorName + " Failed to find any accounts in OIM -- something must be wrong here");
        return null;
      }
      // Otherwise, we have at least one user
      // add to the hashmap
      for (int i = 0; i < moResultSet.getRowCount(); i++) {
        moResultSet.goToRow(i);
        retval.put(
            moResultSet.getStringValue("Users.User ID"),
            moResultSet.getStringValue("USR_UDF_ACMAILBOXEXISTS"));
      }
    } catch (Exception e) {
      // Exception whiel retrieving OIM user data
      logger.error(
          connectorName
              + " Unexpected exception while retrieving OIM user information set "
              + e.getMessage());
      throw new RuntimeException(
          connectorName
              + " Exception while retrieving OIM user (accounts) information set "
              + e.getMessage(),
          e);
    }
    try {
      moUserUtility =
          (tcUserOperationsIntf) super.getUtility("Thor.API.Operations.tcUserOperationsIntf");

      // Do the work for people first, since they're the bulk of us
      try {
        moResultSet = moUserUtility.findUsersFiltered(mhTestSearchCriteria, attrsToGet);
      } catch (Exception e) {
        logger.error(
            connectorName
                + " Exception trying to find all tests in the OIM database "
                + e.getMessage());
        return null; // null return to signal failure
      }
      if (moResultSet.getRowCount() < 1) {
        logger.error(
            connectorName + " Failed to find any tests in OIM -- something must be wrong here");
        return null;
      }
      // Otherwise, we have at least one user
      // add to the hashmap
      for (int i = 0; i < moResultSet.getRowCount(); i++) {
        moResultSet.goToRow(i);
        retval.put(
            moResultSet.getStringValue("Users.User ID"),
            moResultSet.getStringValue("USR_UDF_ACMAILBOXEXISTS"));
      }
    } catch (Exception e) {
      // Exception whiel retrieving OIM user data
      logger.error(
          connectorName
              + " Unexpected exception while retrieving OIM user information set "
              + e.getMessage());
      throw new RuntimeException(
          connectorName
              + " Exception while retrieving OIM user (test) information set "
              + e.getMessage(),
          e);
    }
    return (retval);
  }
  /**
   * This is where it all happens
   *
   * <p>Logic here is as follows (1) Get all user information out of the comms directories (2) Get
   * all user information out of the OIM (3) For each user in the comms directories (4) If the user
   * exists in OIM (5) If status in comms is true and duacmailboxexists = 1 (6) continue, removing
   * user from OIM list (7) If status in comms is false and duacmailboxexists = 0 (8) continue,
   * removing user from OIM list (9) If status in comms is true and duacmailboxexists = 0 (10) set
   * duacmailboxexists = 1, remove user from OIM list (11) if status in comms is false and
   * duacmailboxexists = 1 (12) set duacmailboxexists = 0, remove user from OIM list, and call
   * revokeMailbox (14) For each user left in the OIM list (15) if user does not apear in the comms
   * directories (16) if duacmailboxexists = 1 (17) set duacmailboxexists = 0, remove user from OIM
   * list, call revokeMailbox
   *
   * <p>Really not as complex as it looks.
   */
  public void execute() {

    // Get the LDAP user data first
    ldapMap = getLDAPData();

    // Check whether the response was null and die if it was
    if (ldapMap == null) {
      logger.error(connectorName + " getLDAPData failed to return data -- bailing out");
      return;
    }

    // Get OIM user data next
    OIMMap = getOIMData();

    // Check whether the response was null and die if it was
    if (OIMMap == null) {
      logger.error(connectorName + " getOIMData failed to return user data -- bailing out");
      return;
    }

    // Now run logic from 3-12
    Set ldapKeys = ldapMap.keySet();
    Iterator iter = ldapKeys.iterator();
    while (iter.hasNext()) {
      // for each key in the ldapMap hash
      String lk = (String) iter.next();

      // Check whether OIM has this user somewhere
      if (OIMMap.containsKey(lk)) {
        // OIM has this user, so proceed
        Boolean lb = (Boolean) ldapMap.get(lk);
        if (lb.booleanValue() && OIMMap.get(lk) != null && OIMMap.get(lk).equals("1")) {
          // has mailbox and exists is 1 -- leave it alone
          OIMMap.remove(lk);
          continue;
        }
        if ((lb.booleanValue() && OIMMap.get(lk) != null && OIMMap.get(lk).equals("0"))
            || (lb.booleanValue() && OIMMap.get(lk) != null && OIMMap.get(lk).equals(""))) {
          // has mailbox and exists is 0 -- set exists
          // this should be very unlikely, but...
          HashMap<String, String> doSearchCriteria = new HashMap<String, String>();
          doSearchCriteria.put("Users.User ID", lk);
          doSearchCriteria.put("Users.Status", "Active");
          String[] doattrs = {"Users.User ID"};

          try {
            tcResultSet doResultSet = moUserUtility.findUsersFiltered(doSearchCriteria, doattrs);

            if (doResultSet.getRowCount() != 1) {
              logger.error(
                  connectorName
                      + " Search in OIM for user "
                      + lk
                      + " returned "
                      + doResultSet.getRowCount()
                      + " results - something is wrong");
              OIMMap.remove(lk);
              continue;
            } else {
              HashMap<String, String> attrsForOIM = new HashMap<String, String>();
              attrsForOIM.put("USR_UDF_ACMAILBOXEXISTS", "1");
              try {
                moUserUtility.updateUser(doResultSet, attrsForOIM);
                logger.info(connectorName + " Added duacmailboxexists to user " + lk);
              } catch (Exception e) {
                // Failed the update
                logger.error(
                    connectorName
                        + " Failed add of duacmailboxexists for user "
                        + lk
                        + " due to exception: "
                        + e.getMessage()
                        + " but moving on");
              }
              OIMMap.remove(lk);
              continue;
            }
          } catch (Exception e) {
            // we failed to get the user from OIM, so nothing to do here -- go back to our homes
            // except we log it, since we appear to have failed finding a user who is there
            logger.error(
                connectorName
                    + " User in OIMMap not present in OIM or setting duACMailboxExists failed -- very odd, but nothing to do here -- might want to investigate "
                    + lk
                    + " though");
            OIMMap.remove(lk); // remove it anyway
            continue;
          }
        }
        if (!lb.booleanValue() && OIMMap.get(lk) != null && OIMMap.get(lk).equals("1")) {
          // mailbox no longer exists in LDAP, but is on in OIM
          // turn it off in OIM now
          HashMap<String, String> doSearchCriteria = new HashMap<String, String>();
          doSearchCriteria.put("Users.User ID", lk);
          doSearchCriteria.put("Users.Status", "Active");
          String[] doattrs = {"Users.User ID", "Users.Key"};

          try {
            tcResultSet doResultSet = moUserUtility.findUsersFiltered(doSearchCriteria, doattrs);
            if (doResultSet.getRowCount() != 1) {
              logger.error(
                  connectorName
                      + " Search in OIM for user "
                      + lk
                      + " returned "
                      + doResultSet.getRowCount()
                      + " results - something is wrong");
              OIMMap.remove(lk);
              continue;
            } else {
              HashMap<String, String> attrsForOIM = new HashMap<String, String>();
              attrsForOIM.put("USR_UDF_ACMAILBOXEXISTS", "");
              // need to call revokeMailbox() here, once it's written
              revokeMailbox(doResultSet.getLongValue("Users.Key"));
              try {
                moUserUtility.updateUser(doResultSet, attrsForOIM);
                logger.info(connectorName + " Removed duacmailboxexists from user " + lk);
              } catch (Exception e) {
                logger.error(
                    connectorName
                        + " Failed removing duacmailboxexists for "
                        + lk
                        + " please investigate -- moving on past "
                        + e.getMessage());
              }
              OIMMap.remove(lk);
              continue;
            }
          } catch (Exception e) {
            // We missed on the findUsersFiltered in some fashion, so log an error and move on
            logger.error(
                connectorName
                    + " User in OIMap does not exist or failed removing duacmailboxexists for "
                    + lk
                    + " very odd, but nothing to do here -- please investigate");
            OIMMap.remove(lk); // remove anyway again
            continue;
          }
        }
        // Fallthru case, then, is mailbox doesn't exist and the user doesn't have duacmailboxexists
        // so we leave the fallthru alone, but remove the OIM entry anyway
        OIMMap.remove(lk); // remove anyway
        continue;
      } else {
        // this user exists in LDAP but not in OIM
        // we should note that and move on
        logger.warn(
            connectorName
                + " User "
                + lk
                + " present in comms directory but missing in OIM.  Nothing to do, but be aware this is strange");
        // no need to remove, since we're not present in the OIMMap
        OIMMap.remove(lk); // but remove anyway
      }
    }
    // Now do the same thing with what's left in the OIMMap, but in reverse
    Set OIMKeys = OIMMap.keySet();
    iter = OIMKeys.iterator();
    while (iter.hasNext()) {
      // for each key in the ldapMap hash
      String ok = (String) iter.next();
      // At this point, no one left in the OIM list should be in
      // the comms list, but we need to be certain, so...
      if (!ldapMap.containsKey(ok)) {
        // This is correct -- we're here because the LDAP doesn't contain this user anymore
        if (OIMMap.get(ok) != null && OIMMap.get(ok).equals("1")) {
          // We need to undo a duacmailboxexists setting here
          HashMap<String, String> doSearchCriteria = new HashMap<String, String>();
          doSearchCriteria.put("Users.User ID", ok);
          doSearchCriteria.put("Users.Status", "Active");
          String[] doattrs = {"Users.User ID", "Users.Key"};

          try {
            tcResultSet doResultSet = moUserUtility.findUsersFiltered(doSearchCriteria, doattrs);
            if (doResultSet.getRowCount() != 1) {
              logger.error(
                  connectorName
                      + " Search in OIM for user "
                      + ok
                      + " returned "
                      + doResultSet.getRowCount()
                      + " results - something is wrong");
              continue;
            } else {
              HashMap<String, String> attrsForOIM = new HashMap<String, String>();
              attrsForOIM.put("USR_UDF_ACMAILBOXEXISTS", "");
              // need to call revokeMailbox() here, once it's written
              revokeMailbox(doResultSet.getLongValue("Users.Key"));
              try {
                moUserUtility.updateUser(doResultSet, attrsForOIM);
                logger.info(connectorName + " Removed duacmailboxexists from user " + ok);
              } catch (Exception e) {
                // same as above
                logger.error(
                    connectorName
                        + " caught eception when trying to remove duacmailboxexists from "
                        + ok
                        + " moving on, but you probably need to investigate "
                        + e.getMessage());
              }
            }
          } catch (Exception e) {
            // same story as above
            logger.error(
                connectorName
                    + " Failed to find OIM user "
                    + ok
                    + " or otherwise lost on the OIM search -- continuing, but you should investigate");
          }
        }
        // otherwise, nothing to do -- we're empty in OIM and there is no mailbox
        // so we're all set.
      } else {
        // Something is awry -- we have the user in the LDAP but we got to this branch of the code
        // indicating that we fell through some sort of wormhole.
        logger.error(
            connectorName
                + " Impossible situation -- comms dir entry cannot exist, yet it does for user "
                + ok
                + " -- doing nothing with this case -- please investigate");
      }
    }
  }
  protected void execute() {
    logger.info(connectorName + ": Starting task.");

//    //Get the tcGroupOperationsIntf object
//    try {
//      moGroupUtility = (tcGroupOperationsIntf)super.getUtility("Thor.API.Operations.tcGroupOperationsIntf");
//    } catch (tcAPIException e) {
//      logger.error(connectorName + ": Unable to get an instance of tcGroupOperationsIntf");
//      return;
//    }
//
//    //Get the tcUserOperationsIntf object
//    try {
//      moUserUtility = (tcUserOperationsIntf)super.getUtility("Thor.API.Operations.tcUserOperationsIntf");
//    } catch (tcAPIException e) {
//      logger.error(connectorName + ": Unable to get an instance of tcUserOperationsIntf");
//      return;
//    }


    // Process changes in Grouper sequentially
    ResultSet rs = null;
    PreparedStatement psSelect = null;
    PreparedStatement psDelete = null;
    PreparedStatement psUpdateToFailure = null;

    try {
      ldapConnectionWrapper = new LDAPConnectionWrapper(DEBUG);

      grouperConn = getGrouperConnection();
      psDelete = grouperConn.prepareStatement("DELETE FROM "+userName+".grp_event_log_for_oim WHERE consumer = 'grouper_ldap' AND record_id=?");
      psSelect = grouperConn.prepareStatement("SELECT record_id, group_name, action, field_1, status FROM "+userName+".grp_event_log_for_oim WHERE consumer = 'grouper_ldap' ORDER BY record_id");
      psUpdateToFailure = grouperConn.prepareStatement("UPDATE "+userName+".grp_event_log_for_oim SET status='FAILED' where consumer = 'grouper_ldap' AND record_id=?");

      rs = psSelect.executeQuery();
      while (rs.next()) {
        long recordId = rs.getLong(1);
        String groupName = rs.getString(2);
        String action = rs.getString(3);
        String field1 = rs.getString(4);
        String status = rs.getString(5);

        if (status.equals("FAILED")) {
          updateFailures(action, groupName, field1);
          continue;
        }
        
        groupName = urnizeGroupName(groupName);

        // If an add_member or delete_member fails, we won't process anymore events for that user.
        // If a create, delete, or rename fails, we won't process anymore events for that group.
        if (mustSkipUserOrGroup(action, groupName, field1)) {
          logger.warn(connectorName + ": Skipping record " + recordId + " due to a previous failure with another record with the same user or group.");
          continue;
        }

        // this part is going to be in a separate try-catch block because
        // if an individual update fails, we don't want to stop processing
        boolean isSuccess = false;
        try {
          if (action.equals("create")) {
            processCreate(groupName);
          } else if (action.equals("delete")) {
            processDelete(groupName);
          } else if (action.equals("rename")) {
            processRename(groupName, field1);
          } else if (action.equals("add_member")) {
            processAddMember(groupName, field1);
          } else if (action.equals("delete_member")) {
            processDeleteMember(groupName, field1);
          } else {
            throw new Exception("Unknown action for record id " + recordId);
          }

          // If we get here, then the OIM update succeeded.
          isSuccess = true;
        } catch (Exception e2) {
          logger.error(connectorName + ": Error while processing record " + recordId + ".", e2);
        }

        if (isSuccess) {
          // remove the event from the grouper db
          psDelete.setLong(1, recordId);
          psDelete.executeUpdate();
        } else {
          // mark the event as failed
          psUpdateToFailure.setLong(1, recordId);
          psUpdateToFailure.executeUpdate();
          updateFailures(action, groupName, field1);
        }
      }
    } catch (Exception e) {
      logger.error(connectorName + ": Error while running connector.", e);
    } finally {
      if (rs != null) {
        try {
          rs.close();
        } catch (SQLException e) {
          // this is okay
        }
      }

      if (psSelect != null) {
        try {
          psSelect.close();
        } catch (SQLException e) {
          // this is okay
        }
      }

      if (psDelete != null) {
        try {
          psDelete.close();
        } catch (SQLException e) {
          // this is okay
        }
      }

      if (psUpdateToFailure != null) {
        try {
          psUpdateToFailure.close();
        } catch (SQLException e) {
          // this is okay
        }
      }

      if (grouperConn != null) {
        try {
          grouperConn.close();
        } catch (SQLException e) {
          // this is okay
        }
      }

      if (moGroupUtility != null) {
        moGroupUtility.close();
      }

      if (moUserUtility != null) {
        moUserUtility.close();
      }
    }

    logger.info(connectorName + ": Ending task.");
  }