Package com.opengamma.security.auditlog

Source Code of com.opengamma.security.auditlog.HibernateAuditLogger$Flusher

/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.security.auditlog;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.SessionFactoryUtils;

import com.opengamma.security.auditlog.AbstractAuditLogger;
import com.opengamma.security.auditlog.AuditLogEntry;
import com.opengamma.util.ArgumentChecker;

/**
* An audit logger that uses JDBC batch insert (through Hibernate) to insert
* audit log entries into a database. If there is a server crash, audit log
* entries stored in memory that have not yet been committed into
* the database may be lost.
*
*/
public class HibernateAuditLogger extends AbstractAuditLogger implements Closeable {

  /** Logger. */
  private static final Logger s_logger = LoggerFactory.getLogger(HibernateAuditLogger.class);
 
  private HibernateTemplate _hibernateTemplate;

  private final int _batchSize;
 
  /** Keeps track of audit log entries to flush */
  private List<AuditLogEntry> _auditLogCache;
 
  private final Timer _timer;
 
  public HibernateAuditLogger() {
    this(getDefaultOriginatingSystem());
  }
 
  public HibernateAuditLogger(String originatingSystem) {
    this(originatingSystem, 50, 5);
  }
 
  public HibernateAuditLogger(int batchSize, int maxSecondsToKeepInMemory) {
    this(getDefaultOriginatingSystem(), batchSize, maxSecondsToKeepInMemory);
  }
 
  public HibernateAuditLogger(String originatingSystem, int batchSize, int maxSecondsToKeepInMemory) {
    super(originatingSystem);
   
    if (batchSize <= 0) {
      throw new IllegalArgumentException("Please give positive batch size");
    }
    if (maxSecondsToKeepInMemory <= 0) {
      throw new IllegalArgumentException("Please give positive max seconds to keep in memory");
    }
   
    _batchSize = batchSize;
    _auditLogCache = new ArrayList<AuditLogEntry>(_batchSize);
   
    Flusher flusher = new Flusher();
    _timer = new Timer("hibernate-audit-log-flusher");
    _timer.schedule(flusher, 1000 * maxSecondsToKeepInMemory, 1000 * maxSecondsToKeepInMemory);
  }
 
  public void setSessionFactory(SessionFactory sessionFactory) {
    _hibernateTemplate = new HibernateTemplate(sessionFactory);
  }
 
  private Session getSession() {
    return SessionFactoryUtils.getSession(
            _hibernateTemplate.getSessionFactory(),
            _hibernateTemplate.getEntityInterceptor(),
            _hibernateTemplate.getJdbcExceptionTranslator());
  }

  //-------------------------------------------------------------------------
  /**
   * The <code>Flusher</code> background thread ensures that all log entries are written into
   * the DB in a timely fashion, even if the flow of new log entries from clients stops abruptly. 
   */
  private class Flusher extends TimerTask {
    @Override
    public void run() {
      try {
        flushCache();
      } catch (RuntimeException e) {
        // see http://manikandakumar.blogspot.com/2006/09/drawbacks-of-timertask.html
      }
    }
  }
 
  @Override
  public void log(String user, String originatingSystem, String object, String operation, String description, boolean success) {
    ArgumentChecker.notNull(user, "User ID");
    ArgumentChecker.notNull(user, "Originating system name");
    ArgumentChecker.notNull(object, "Object ID");
    ArgumentChecker.notNull(operation, "Operation name");
   
    AuditLogEntry auditLogEntry = new AuditLogEntry(user, originatingSystem, object, operation, description, success, new Date());
    boolean flushCache = false;
    synchronized (this) {
      _auditLogCache.add(auditLogEntry);
      if (_auditLogCache.size() >= _batchSize) {
        flushCache = true;
      }
    }
   
    if (flushCache) {
      flushCache();
    }
  }
 
  @Override
  public void flushCache() {
   
    List<AuditLogEntry> auditLogCache;
    synchronized (this) {
      auditLogCache = _auditLogCache;
      _auditLogCache = new ArrayList<AuditLogEntry>(_batchSize);
    }

    Session session = getSession();
    Transaction tx = null;
    try {
      tx = session.beginTransaction();
      for (int i = 0; i < auditLogCache.size(); i++) {
        AuditLogEntry auditLogEntry = auditLogCache.get(i);
        session.save(auditLogEntry);
       
        if (i != 0 && i % _batchSize == 0) {
          session.flush();
          session.clear();
        }
      }
     
      tx.commit();
    } catch (RuntimeException e) {
      // If this happens, for now, assume that there was something wrong
      // with one of the log messages. Therefore do NOT re-insert
      // the messages into _auditLogCache.
      s_logger.error("Failed to commit batch to Hibernate", e);
      if (tx != null) {
        tx.rollback();
      }
      throw e;
    } finally {
      session.close();
    }
  }

  List<AuditLogEntry> findAll() {
    return _hibernateTemplate.loadAll(AuditLogEntry.class);
  }

  @Override
  public void close() {
    Timer timer = _timer;
    if (timer != null) {
      try {
        _timer.cancel();
      } catch (Throwable ex) {
        s_logger.info("Error during timer cancellation", ex);
      }
      try {
        flushCache();
      } catch (Throwable ex) {
        s_logger.info("Error during flush", ex);
      }
    }
  }

}
TOP

Related Classes of com.opengamma.security.auditlog.HibernateAuditLogger$Flusher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.