/**
   * Writes cache files, first new mail, than state to avoid client prematurely looking for
   * activation info. Hits nfs.
   */
  private void updateSignalFiles(ClientHashSupport hash, CustomerState state, boolean isDeleted) {

    File base = getCacheBase();
    int userId = hash.getUserId();
    File stateFile = new File(base, hash.getStateCachePath());
    if (isDeleted || state == CustomerState.READY) {
      deleteFileIfNeeded(stateFile, userId);
    } // ready state.
    else {
      byte[] stateData = STATE_DATA_CACHE.get(state);
      touchFile(stateFile, stateData, userId, true);
    }
    File newMailFile = new File(base, hash.getNewMailCachePath());
    if (!isDeleted && state.type() == CustomerState.Type.Active) {
      touchFile(newMailFile, ZERO, userId, true);
    } else {
      deleteFileIfNeeded(newMailFile, userId);
    }
    if (isDeleted || state.type() != CustomerState.Type.Active) {
      File f = getSessionFile(hash.getLastActivationToken());
      deleteFileIfNeeded(f, userId);
    }
  }
  public CacheFileNames getCacheFileNames(final UserAccount user) {

    SecureHashKeyResult toRet =
        executeWithConnection(
            new ConnectionExecuteFunction<SecureHashKeyResult>() {
              public SecureHashKeyResult execute(Connection c) throws SQLException {
                return getSecureHashKey(user, c);
              }
            });

    if (toRet == null) {
      // A DB error should have been logged.
      return null;
    }

    // EMSDEV-7854.  Signal file manipulation is done outside of a DB transaction.
    String stateFile = null;
    String newmailFile = null;
    ClientHashSupport hash = null;
    byte[] key = toRet.getKey();
    if (key != null) {
      hash = new ClientHashSupport();
      hash.setCustomerId(user.getCustomerID());
      hash.setHashKey(key);
      hash.setUserId(user.getUserID());
      hash.getStateCachePath();
      hash.setLastActivationId(user.getLastActivationId());

      // Lines below don't hit the spindle.
      File stateFileF = new File(getCacheBase(), hash.getStateCachePath());
      stateFile = stateFileF.getAbsolutePath();

      File newmailFileF = new File(getCacheBase(), hash.getNewMailCachePath());
      newmailFile = newmailFileF.getAbsolutePath();

      if (toRet.isJustCreated()) {
        // If Webmail doesn't find the signal file, it polls the database,
        // so ensure the files are there.
        updateSignalFiles(hash, user.getUserState(), user.isDeleted());
      }
    }
    return new CacheFileNames(stateFile, newmailFile);
  }
  /** Writes user state information to the shared filesystem */
  private void updateStateCache(
      Customer customer, int transitionId, CustomerState newState, Connection c)
      throws SQLException {
    PreparedStatement pst = null;
    ResultSet rs = null;

    try {
      pst =
          c.prepareStatement(
              "SELECT u.secure_hash_key, u.object_id, u.user_state, u.is_deleted, u.last_activation_id "
                  + "FROM dat_user_account u, dat_transition_users tr "
                  + "WHERE u.object_id = tr.user_id AND u.customer_id=? "
                  + "AND tr.transition_id=?;");

      // The state files are used by Outlook, BB, and maybe future clients.
      pst.setInt(1, customer.getCustID());
      pst.setInt(2, transitionId);
      rs = pst.executeQuery();
      while (rs.next()) {
        int i = 0;
        byte[] key = rs.getBytes(++i);
        int userId = rs.getInt(++i);
        CustomerState state = CustomerState.fromInt(rs.getInt(++i));
        int isDeletedInt = rs.getInt(++i);
        int lastActivationId = rs.getInt(++i);

        // If the user is marked deleted but has a key, we'll try cleaning
        // up state files.
        boolean isDeleted = isDeletedInt != IUserManager.USER_NOT_DELETED;
        if (key == null || key.length == 0) {
          LogMessageGen lmg = new LogMessageGen();
          lmg.setSubject("dat_user_account.secure_hash_key not set");
          lmg.param(LoggingConsts.USER_ID, userId);
          m_logCategory.info(lmg.toString());

          // Without a key, we can't determine the signal filenames
          // so no cleanup is possible.
          continue;
        }

        ClientHashSupport hash = null;
        hash = new ClientHashSupport();
        hash.setCustomerId(customer.getCustID());
        hash.setUserId(userId);
        hash.setHashKey(key);
        hash.setLastActivationId(lastActivationId);

        if (m_logCategory.isInfoEnabled()) {
          LogMessageGen lmg = new LogMessageGen();
          lmg.setSubject("Updating signal files");
          lmg.param(LoggingConsts.USER_ID, userId);
          m_logCategory.info(lmg.toString());
        }
        // wrt EMSDEV-7854 nfs calls and database transactions.
        // Above is only doing a select; no locks are taken and this
        // method is private.
        updateSignalFiles(hash, state, isDeleted);
      } // each row.
    } finally {
      DbUtils.safeClose(rs);
      DbUtils.safeClose(pst);
    }
  }