Java tutorial
/** * 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); } } } }