/** * Copyright 2008-2009 Dan Pritchett * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * */ package org.addsimplicity.anicetus.hibernate; import java.io.Serializable; import org.addsimplicity.anicetus.TelemetryContext; import org.addsimplicity.anicetus.entity.CompletionStatus; import org.hibernate.EmptyInterceptor; import org.hibernate.Transaction; import org.hibernate.type.Type; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; /** * The telemetry interceptor uses the Hibernate interceptor interface to capture * operations that are performed by Hibernate and create a telemetry artifact. * The telemetry is created at the start of a transaction so that it can gather * all of the entities and operations that are done during the transaction. The * operation timer is started at the beginning of the commit so the time * captured is database processing time. Note that telemetry is not captured if * a Hibernate transaction is not used. * * The interceptor relies upon Spring to retrieve the context used for managing * the state of the transactional stack. * * @author Dan Pritchett (driveawedge@yahoo.com) * */ public class TelemetryInterceptor extends EmptyInterceptor implements BeanFactoryAware { private static final long serialVersionUID = 1L; private transient BeanFactory m_beanFactory; private String m_managerName = "telemetryContext"; /** * This method is called by Hibernate after the begin transaction operation. A * new telemetry artifact is created at the point that this method is called. * */ @Override public void afterTransactionBegin(Transaction tx) { TelemetryContext ctx = (TelemetryContext) m_beanFactory.getBean(m_managerName); HibernateTelemetry telem = new HibernateTelemetry(ctx.peekTransaction()); ctx.pushTransaction(telem); } /** * This method is called by Hibernate when the transaction completes. The * telemetry status is set based on the transaction committed status. */ @Override public void afterTransactionCompletion(Transaction tx) { TelemetryContext ctx = (TelemetryContext) m_beanFactory.getBean(m_managerName); HibernateTelemetry telem = (HibernateTelemetry) ctx.popTransaction(); telem.complete(); if (tx.wasCommitted()) { telem.setStatus(CompletionStatus.Success); } else { telem.setStatus(CompletionStatus.Failure); } } /** * This method is called by Hibernate before the transaction begins to commit * to the database. */ @Override public void beforeTransactionCompletion(Transaction tx) { getTelemetry().startTimer(); } /** * Get the key used to retrieve the TelemetryContext from the Spring context. * * @return the key to the TelemetryContext. */ public String getManagerName() { return m_managerName; } /** * This method is called by Hibernate prior to an entity being deleted. */ @Override public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { HibernateEntity he = new HibernateEntity(entity.getClass().getName(), id.toString(), HibernateOperation.Delete); getTelemetry().addHibernateEntity(he); } /** * This method is called by Hibernate prior to an entity being updated. */ @Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { HibernateEntity he = new HibernateEntity(entity.getClass().getName(), id.toString(), HibernateOperation.Update); getTelemetry().addHibernateEntity(he); return false; } /** * This method is called prior to an object being loaded from the database. */ @Override public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { HibernateEntity he = new HibernateEntity(entity.getClass().getName(), id.toString(), HibernateOperation.Load); getTelemetry().addHibernateEntity(he); return false; } /** * This method is called by Hibernate each time a SQL statement is prepared. */ @Override public String onPrepareStatement(String sql) { getTelemetry().addSQLStatement(sql); return sql; } /** * This method is called by Hibernate each time an entity is being inserted. */ @Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { HibernateEntity he = new HibernateEntity(entity.getClass().getName(), id != null ? id.toString() : "NEW", HibernateOperation.Create); getTelemetry().addHibernateEntity(he); return false; } /** * This method is called by Spring to set the context used to create the bean. */ public void setBeanFactory(BeanFactory factory) throws BeansException { m_beanFactory = factory; } /** * Set the Spring key that is used to retrieve the TelemetryContext from the * Spring container. * * @param managerName * The key to the TelemetryContext */ public void setManagerName(String managerName) { m_managerName = managerName; } private HibernateTelemetry getTelemetry() { TelemetryContext ctx = (TelemetryContext) m_beanFactory.getBean(m_managerName); return (HibernateTelemetry) ctx.peekTransaction(); } }