Beispiel #1
0
  public boolean logEvent(
      final IClient client, final String eventText, final InputStream logFileStream) {
    Integer id =
        executeWithConnection(
            new ConnectionExecuteFunction<Integer>() {
              public Integer execute(Connection c) throws SQLException {
                return logEvent(client, eventText, logFileStream, c);
              }
            });

    if (id == null) {
      // DB error would have already been logged.
      return false;
    }

    boolean ok = false;
    if (logFileStream == null) {
      ok = true;
    } else {
      File userMailDir = client.getUserMailbox().getBaseDir();
      File logFile = getEventLogFile(userMailDir, id.intValue());
      try {
        FileUtils.copyStreamToFile(logFileStream, logFile);
        ok = true;
      } catch (IOException ioe) {
        m_logger
            .log("Can't write log file")
            .param(LoggingConsts.USER_ID, client.getUserId())
            .param(LoggingConsts.FILENAME, logFile == null ? "" : logFile.getAbsolutePath())
            .param(LoggingConsts.CONTENT, eventText)
            .error(ioe);
      }
    }
    return ok;
  }
Beispiel #2
0
 /**
  * If 'file' exists, attempt to delete it. Logs, but doesn't throw upon failure.
  *
  * @param file
  * @param userId only for logging.
  */
 private void deleteFileIfNeeded(File file, int userId) {
   if (file.exists()) {
     boolean ok = file.delete();
     if (!ok) {
       // This is a problem because it may delay informing a client to leave
       // activation.
       LogMessageGen lmg = new LogMessageGen();
       lmg.setSubject("Unable to delete file");
       lmg.param(LoggingConsts.USER_ID, userId);
       lmg.param(LoggingConsts.FILENAME, file.getAbsolutePath());
       m_logCategory.error(lmg.toString());
     }
   }
 }
Beispiel #3
0
  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);
  }
Beispiel #4
0
  public ClientSession getClientSession(String activationToken) {
    if (!StringUtils.hasValue(activationToken)) {
      m_logCategory.warn("activationToken is required");
      return null;
    }

    File file = getSessionFile(activationToken);
    if (!file.exists()) {
      // Can't assume it's an authentication problem -- session file is removed
      // during active->recovery transition.
      // If this occurs, the client gets a 401 and will call into 'transition' or 'checkin'.
      LogMessageGen lmg = new LogMessageGen();
      lmg.setSubject("Session file not found");
      lmg.param(LoggingConsts.FILENAME, file.getAbsolutePath());
      m_logCategory.info(lmg.toString());
      return null;
    }
    try {
      ClientSession clientSession = null;
      clientSession = new ClientSession();
      clientSession.read(file);
      clientSession.setActivationToken(activationToken);
      return clientSession;
    } catch (IOException ioe) {
      // Possible if the state file was removed after the file.exists() above,
      // or some other problem.
      // info, not warning because a client could ask for this file right when
      // the session is being removed.  The client will then do a 'checkin',
      // same as described above.
      LogMessageGen lmg = new LogMessageGen();
      lmg.setSubject("Unable to read session file");
      lmg.param(LoggingConsts.FILENAME, file.getAbsolutePath());
      m_logCategory.info(lmg.toString(), ioe);
    }
    return null;
  }
Beispiel #5
0
 /**
  * Doesn't write the file atomically. Logs, but doesn't throw upon failure.
  *
  * @param file can't be null.
  * @param userId only for logging.
  * @param content
  * @param errorLevel if true log an error level message; otherwise warning level.
  */
 private void touchFile(File file, byte[] content, int userId, boolean errorLevel) {
   OutputStream out = null;
   try {
     file.getParentFile().mkdirs();
     out = new FileOutputStream(file);
     out.write(content);
     out.close();
     out = null;
   } catch (IOException ioe) {
     LogMessageGen lmg = new LogMessageGen();
     lmg.setSubject("Unable to touch cache file");
     lmg.param(LoggingConsts.USER_ID, userId);
     lmg.param(LoggingConsts.FILENAME, file.getAbsolutePath());
     lmg.param(LoggingConsts.CONTENT, content);
     if (errorLevel) {
       m_logCategory.error(lmg.toString(), ioe);
     } else {
       m_logCategory.warn(lmg.toString(), ioe);
     }
   } finally {
     // normally closed above; just for leak prevention.
     IOUtils.safeClose(out, false, m_logCategory);
   }
 }
Beispiel #6
0
 /**
  * If we'll block due to an nfs issue, let it block here before we open a DB connection. This
  * reduces the window where an nfs problem can hoard a connection. We don't care if exists() fails
  * because file calls usually create dirs lazily.
  */
 private void blockHereIfBadNfs() {
   m_cacheBaseDir.exists();
 }
Beispiel #7
0
  public void purgeLogEvents(final List<SearchConstraint> constraints, final int daysToKeep) {
    blockHereIfBadNfs();

    StringBuffer sql =
        new StringBuffer(
            "select u.mail_directory || '/logs/' || e.event_id || '.log' "
                + "from dat_client_log_events e, dat_user_account u "
                + "where event_time < current_timestamp - (? || ' days')::interval "
                + "and e.has_log_file != 0 "
                + "and e.user_id = u.object_id");
    appendWhereConstraints(sql, constraints, s_propToColumnMap);
    m_logCategory.info("Purge event logs query is\n" + sql);

    StringBuffer sql2 =
        new StringBuffer(
            "delete from dat_client_log_events "
                + "where event_time < current_timestamp - (? || ' days')::interval");
    if (!constraints.isEmpty()) {
      sql2.append(" and event_id in (select e.event_id from dat_client_log_events e ");
      appendWhere(sql2, constraints, s_propToColumnMap);
      sql2.append(")");
    }
    m_logCategory.info("Purge event logs query is\n" + sql2);

    try {
      Connection c = m_txManager.getConnection();
      PreparedStatement stmt = null;
      ResultSet rs = null;
      boolean needsRollback = true;
      try {
        stmt = c.prepareStatement(sql.toString());
        stmt.setInt(1, daysToKeep);
        rs = stmt.executeQuery();
        while (rs.next()) {
          File logFile = new File(getNfsRoot(), rs.getString(1));
          // nfs usage, but DB transaction takes no locks.
          if (logFile.exists()) {
            boolean ok = logFile.delete();
            if (!ok) {
              m_logger
                  .log("Unable to delete")
                  .param(LoggingConsts.FILENAME, logFile.getAbsolutePath())
                  .warn();
            }
          } // file exists.
        } // each row

        // Below, no nfs usage occurs.  We can use the same connection.
        // the 'sql delete' may use DB locks.
        stmt = c.prepareStatement(sql2.toString());
        stmt.setInt(1, daysToKeep);
        stmt.executeUpdate();
        c.commit();
        needsRollback = false;
      } finally {
        DbUtils.safeClose(rs);
        DbUtils.safeClose(stmt);
        if (needsRollback) {
          c.rollback();
        }
        m_txManager.returnConnection(c);
      }
    } catch (Exception ex) {
      m_logger.log("Error in purgeLogEvents").warn(ex);
    }
  }
Beispiel #8
0
 private File getEventLogFile(File userMailDir, int id) {
   File logDir = new File(userMailDir, "logs");
   logDir.mkdir();
   return new File(logDir, id + ".log");
 }
Beispiel #9
0
  public ClientSession createClientSession(IClientInfo client, String clientType) {

    // Both OE and BB share the session file.  Don't stomp an existing file.
    if (client == null || !client.isConfigured()) {
      throw new IllegalStateException("Client not configured.");
    }

    clientType = clientType == null ? "" : clientType;

    ClientSession session = null;
    String tmpName = null;
    String targetName = null;
    try {
      File targetFile = getSessionFile(client.getLastActivationToken());
      targetName = targetFile.getAbsolutePath();
      if (targetFile.exists()) {
        session = new ClientSession();
        session.read(targetFile);
        if (session.getLastActivationId() != client.getLastActivationId()
            || session.getUserId() != client.getUserId()) {
          // Existing session file found but it's clearly not ours.
          // A hash collision is improbable.  If this occurs, its more likely to be a
          // bug.  We can't safely rewrite the session file because another client
          // might later call getClientSession() and read our email.
          // This is a support concern.
          LogMessageGen lmg = new LogMessageGen();
          lmg.setSubject("Found existing session, but the content is unexpected.");
          lmg.param(LoggingConsts.FILENAME, targetFile.getAbsolutePath());
          m_logCategory.error(lmg.toString());
          throw new ClientServiceException("");
        }
        session.setActivationToken(client.getLastActivationToken());
      } // targetFile already found.

      if (session == null) {
        UserAccount user = m_userService.getUserAccount(client.getCustomerId(), client.getUserId());
        session = client.createSession(user);

        // What if the BB and OE create a session at the same time?
        // This ensures a unique filename.
        // The client who does the last renameTo() below wins the race
        // and that becomes the common session file.

        tmpName = targetFile.getAbsolutePath() + "_tmp_" + clientType;
        File tmpFile = new File(tmpName);
        session.write(tmpFile);

        // If 'targetFile' already exists it'll get clobbered.
        // Makes the session targetFile generation atomic.
        boolean ok = FileUtils.clobberingRename(tmpFile, targetFile);
        if (!ok) {
          throw new IOException("Rename failed");
        }
      } // need to create session.
    } catch (Exception ex) {
      if (ex instanceof ClientServiceException) {
        // We already logged it.
        throw (ClientServiceException) ex;
      }
      LogMessageGen lmg = new LogMessageGen();
      lmg.setSubject("Unable to generate session file.");
      lmg.param(LoggingConsts.USER_ID, client.getUserId());
      lmg.param(LoggingConsts.TEMP_NAME, tmpName);
      lmg.param(LoggingConsts.FILENAME, targetName);

      m_logCategory.error(lmg.toString(), ex);
      throw new ClientServiceException("");
    }
    return session;
  }