Page 1 of 3 123 LastLast
Results 1 to 10 of 23

Thread: How to use an hibernate interceptor with spring

  1. #1
    Join Date
    Nov 2004
    Posts
    6

    Default How to use an hibernate interceptor with spring

    I want to use my own hibernate interceptor to achieve history functions in my database tables.

    My question is how to make spring to use the interceptor.

    The messege i get is :'Bean with name 'personDAOTarget' concluding interceptor chain is not an advisor class: treating it as a target or TargetSourc', and the methods of the interceptor are not called.

    The interceptor i created extends org.springframework.orm.hibernate.HibernateInterce ptor

    I added the following to the applicationContext.

    <bean id="myHibernateInterceptor" class="org.appfuse.MyInterceptor">
    <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>

    <bean id="personDAOTarget" class="org.appfuse.dao.hibernate.PersonDAOHibernat e">
    <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>

    <bean id="personDAO" class="org.springframework.aop.framework.ProxyFact oryBean">
    <property name="proxyInterfaces">
    <value>org.appfuse.dao.PersonDAO</value>
    </property>
    <property name="interceptorNames">
    <list>
    <value>myHibernateInterceptor</value>
    <value>personDAOTarget</value>
    </list>
    </property>
    </bean>

    Regards,
    Rene Boere

  2. #2
    Join Date
    Aug 2004
    Location
    San Mateo, CA
    Posts
    1,265

    Default

    If you want to use your own HibernateInterceptor, use the entityInterceptor property of Spring's LocalSessionFactoryBean.

    Hibernate interceptors are quite separate from Spring's AOP framework.
    Rod Johnson - GM, SpringSource Division, VMware
    http://www.springsource.com
    Spring From the Source

  3. #3
    Join Date
    Sep 2004
    Location
    France
    Posts
    44

    Default

    But is there a way with spring to tell hibernate to use an interceptor each time it opens a session ?

  4. #4

    Default

    Since version 1.1, you can use an entityInterceptorBeanName, and the hibernateInterceptor will request a new Hibernate Interceptor for each request. If you set your entity interceptor to singleton="false", a new entity interceptor will be created for each request.

    Code:
    <beans>
        ...
    
        <bean id="myHibernateInterceptor" 
            class="org.springframework.orm.hibernate.HibernateInterceptor">
            <property name="sessionFactory">
                <ref bean="mySessionFactory"/>
            </property>
    	<property name="entityInterceptorBeanName">
                <value>myEntityInterceptor</value>
    	</property>
        </bean>
    
        <bean id="myEntityInterceptor" class="mypackage.MyEntitiyInterceptor" singleton="false"/>
    
        ...
    </beans>
    If you want to access request specific information, I recommend not to follow this approach but instead call a class where that request-specific information, such as the current user, is currently stored in a threadlocal object.

    Cheers, Stefaan

  5. #5
    Join Date
    Sep 2004
    Location
    France
    Posts
    44

    Default

    There is a naming problem here. I don't want to use spring's HibernateInterceptor but I want to use hibernate's Interceptor which is call on some hibernate events (save/update/delete).

    The hibernate docs says that I have to pass this interceptor to the session when I create it but with spring I have no access to the session creation : this is my problem

  6. #6

    Default

    Yeah, it is really confusing. My reply did indeed speak about hibernate's interceptor, I call it the entity interceptor. You normally configure this entity interceptor (hibernate class) which you define the HibernateInterceptor, which is a Spring AOP interceptor for Hibernate. In that HibernateInterceptor, you set the entityInterceptorBeanName.

    Hope this clearifies

  7. #7
    Join Date
    Nov 2004
    Posts
    159

    Default

    Hi,

    I've the same requirement that i would like to record some history information when the a record in the table is inserted/updated/deleted (CRUD). I'm trying to implement as discussed here....the spring way.

    I've the AuditLogInterceptor class that implements Interceptor as follows:

    Code:
    public class AuditLogRecordInterceptor implements Interceptor &#123;
    .....
    ......
    
    	public void postFlush&#40;Iterator arg0&#41; throws CallbackException &#123;
    		try &#123;
    			for&#40;Iterator itr = inserts.iterator&#40;&#41;; itr.hasNext&#40;&#41;; &#41; &#123;
    				Auditable entity = &#40;Auditable&#41;itr.next&#40;&#41;;
    				AuditLog.logEvent&#40;"create", entity, "testuser"&#41;;
    			&#125;
    			for&#40;Iterator itr = updates.iterator&#40;&#41;; itr.hasNext&#40;&#41;; &#41; &#123;
    				Auditable entity = &#40;Auditable&#41;itr.next&#40;&#41;;
    				AuditLog.logEvent&#40;"update", entity, "testuser"&#41;;
    			&#125;
    		&#125; catch&#40;HibernateException e&#41; &#123;
    			
    		&#125; finally &#123;
    			inserts.clear&#40;&#41;;
    			updates.clear&#40;&#41;;
    		&#125;
    		
    	&#125;
    &#125;
    In this class i'm implementing the required methods such as OnSave, OnPostFlush etc as per the hibernate requirement.

    I also have a class called AuditLog an utility class as follows:

    Code:
    public class AuditLog &#123;
    	private SessionFactory sessionFactory;
    	
    	public void setSessionFactory&#40;SessionFactory sessionFactory&#41; &#123;
    		this.sessionFactory = sessionFactory;
    	&#125;
    	
    	public SessionFactory getSessionFactory&#40;&#41; &#123;
    		return sessionFactory;
    	&#125;
    	
    	public void logEvent&#40;String message, Auditable entity,
    							Long userId&#41; 
    								throws CallbackException &#123;
    		Session session = null;
    		
    		try &#123;
    			AuditLogRecord record = new AuditLogRecord&#40;message, entity.getId&#40;&#41;,
    								entity.getClass&#40;&#41;, userId&#41;;
    		    session = sessionFactory.openSession&#40;&#41;;
    			session.save&#40;record&#41;;
    			session.flush&#40;&#41;;
    		&#125; catch&#40;Exception ex&#41; &#123;
    			throw new CallbackException&#40;ex&#41;;
    		&#125; finally &#123;
    			try &#123;
    				session.close&#40;&#41;;
    			&#125; catch&#40;HibernateException ex&#41; &#123;
    				throw new CallbackException&#40;ex&#41;;				
    			&#125;
    		&#125;
    		
    	&#125;
    &#125;
    Here is my applicationContext.xml file (partial)

    Code:
    	    <!-- Hibernate SessionFactory 2 used for audit log-->
        <bean id="sessionFactory2" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
            <property name="dataSource"><ref local="dataSource"/></property>
     		<property name="mappingResources">
    			<list>
    				<value>com/apple/ermt/model/Project.hbm.xml</value>
    				<value>com/apple/ermt/model/ProjectResource.hbm.xml</value>
    				<value>com/apple/ermt/model/Resource.hbm.xml</value>
    				<value>com/apple/ermt/model/Requirement.hbm.xml</value>	
    				<value>com/apple/ermt/model/TestCase.hbm.xml</value>	
    				<value>com/apple/ermt/model/UseCase.hbm.xml</value>						
    			</list>
    		</property>
        </bean>
     
    	<bean id="auditLogInterceptor" class="com.apple.ermt.persistence.audit.AuditLogInterceptor" singleton="false"/>
    	
    	<bean id="auditLog" class="com.apple.ermt.persistence.audit.AuditLog">
    		<property name="sessionFactory"><ref local="sessionFactory2"/></property>
    	</bean>
    	
        <!-- Hibernate SessionFactory -->
        <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
            <property name="dataSource"><ref local="dataSource"/></property>
     		<property name="mappingResources">
    			<list>
    				<value>com/apple/ermt/model/Project.hbm.xml</value>
    				<value>com/apple/ermt/model/ProjectResource.hbm.xml</value>
    				<value>com/apple/ermt/model/Resource.hbm.xml</value>
    				<value>com/apple/ermt/model/Requirement.hbm.xml</value>	
    				<value>com/apple/ermt/model/TestCase.hbm.xml</value>	
    				<value>com/apple/ermt/model/UseCase.hbm.xml</value>						
    			</list>
    		</property>
            <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
            </property>  
            <property name="entityInterceptor"><ref local="auditLogInterceptor"/></property>
        </bean>
    ........
    ......
    My problem is that per the Hibernate in Action book, the AuditLog can have a static method called logEvent which can be used from the AuditLogRecord class to actually record the entry in the table. If i make this method STATIC, it can't access the instance variable sessionFactory being injected by Spring. The solution is to make this variable also STATIC. But i feel that this is WRONG. So do i need to have the logEvent method to be STATIC? If not, how else should i implement this?

    Could someone please share your experience?


    Thanks very much in advance.

  8. #8
    Join Date
    Nov 2004
    Posts
    159

    Default

    Just one correction.

    I've added the property "entityInterceptor" under the "transactionManager" bean.


    Thanks!

  9. #9

    Default

    Why do you access AuditLog with static methods ? You've configured it using spring as a singleton, then there is no need to define static methods any more. Just add AuditLog as a property of your AuditLogInterceptor.

    Actually, you don't need to configure the AuditLogInterceptor as a non-singleton. It's much simpler without singleton="false". If you say you configered it using the entityInterceptor property, there will be only one instance anyway. Only if you define it using the entityInterceptorBeanName, a new entityInterceptor on each new session.

    If you need to get to the user information, I suggest using a "UserResolver" (interface returing a String getUser()) that looks up in a ThreadLocal the object. You only need to set it into the ThreadLocal by using a Servlet Filter for example. This is the suggested approach in the acegi security framework. This works in my project like a charm.

    Good luck,
    Stefaan.

  10. #10
    Join Date
    Nov 2004
    Posts
    159

    Default

    Thanks Stefaan.

    This is what i've done. As you said, i've added AuditLog as a property in the AuditLogRecordInterceptor as follows:

    Code:
    public class AuditLogRecordInterceptor implements Interceptor &#123;
    	private Log log = LogFactory.getLog&#40;HibernateProjectDAO.class&#41;;
    	
    	private SessionFactory sessionFactory;
    	private AuditLog  auditLog;
    	
    	private Set inserts = new HashSet&#40;&#41;;
    	private Set updates = new HashSet&#40;&#41;;
    	
    
    	public void setSessionFactory&#40;SessionFactory sessionFactory&#41; &#123;
    		this.sessionFactory = sessionFactory;
    	&#125;
    	
    	public SessionFactory getSessionFactory&#40;&#41; &#123;
    		return this.sessionFactory;
    	&#125;
    
    	public void setAuditLog&#40;AuditLog auditLog&#41; &#123;
    		this.auditLog = auditLog;
    	&#125;
    
    	public AuditLog getAuditLog&#40;&#41; &#123;
    		return this.auditLog;
    	&#125;
    
    	
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#onLoad&#40;java.lang.Object, java.io.Serializable, java.lang.Object&#91;&#93;, java.lang.String&#91;&#93;, net.sf.hibernate.type.Type&#91;&#93;&#41;
    	 */
    	public boolean onLoad&#40;Object arg0, Serializable arg1, Object&#91;&#93; arg2, String&#91;&#93; arg3, Type&#91;&#93; arg4&#41; throws CallbackException &#123;
    		// TODO Auto-generated method stub
    		return false;
    	&#125;
    
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#onFlushDirty&#40;java.lang.Object, java.io.Serializable, java.lang.Object&#91;&#93;, java.lang.Object&#91;&#93;, java.lang.String&#91;&#93;, net.sf.hibernate.type.Type&#91;&#93;&#41;
    	 */
    	public boolean onFlushDirty&#40;Object arg0, Serializable arg1, Object&#91;&#93; arg2, Object&#91;&#93; arg3, String&#91;&#93; arg4, Type&#91;&#93; arg5&#41; throws CallbackException &#123;
    		if&#40;arg0 instanceof Auditable&#41;
    			updates.add&#40;arg0&#41;;
    		return false;
    	&#125;
    
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#onSave&#40;java.lang.Object, java.io.Serializable, java.lang.Object&#91;&#93;, java.lang.String&#91;&#93;, net.sf.hibernate.type.Type&#91;&#93;&#41;
    	 */
    	public boolean onSave&#40;Object arg0, Serializable arg1, Object&#91;&#93; arg2, String&#91;&#93; arg3, Type&#91;&#93; arg4&#41; throws CallbackException &#123;
    		if&#40;arg0 instanceof Auditable&#41;
    			inserts.add&#40;arg0&#41;;
    		return false;
    	&#125;
    
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#onDelete&#40;java.lang.Object, java.io.Serializable, java.lang.Object&#91;&#93;, java.lang.String&#91;&#93;, net.sf.hibernate.type.Type&#91;&#93;&#41;
    	 */
    	public void onDelete&#40;Object arg0, Serializable arg1, Object&#91;&#93; arg2, String&#91;&#93; arg3, Type&#91;&#93; arg4&#41; throws CallbackException &#123;
    		// TODO Auto-generated method stub
    		
    	&#125;
    
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#preFlush&#40;java.util.Iterator&#41;
    	 */
    	public void preFlush&#40;Iterator arg0&#41; throws CallbackException &#123;
    		// TODO Auto-generated method stub
    		
    	&#125;
    
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#postFlush&#40;java.util.Iterator&#41;
    	 */
    	public void postFlush&#40;Iterator arg0&#41; throws CallbackException &#123;
    		log.debug&#40;"In postFlush#########.."&#41;;
    		
    		try &#123;
    			for&#40;Iterator itr = inserts.iterator&#40;&#41;; itr.hasNext&#40;&#41;; &#41; &#123;
    				Auditable entity = &#40;Auditable&#41;itr.next&#40;&#41;;
    				auditLog.logEvent&#40;"create", entity, new Long&#40;1&#41;, sessionFactory&#41;;
    			&#125;
    			for&#40;Iterator itr = updates.iterator&#40;&#41;; itr.hasNext&#40;&#41;; &#41; &#123;
    				Auditable entity = &#40;Auditable&#41;itr.next&#40;&#41;;
    				auditLog.logEvent&#40;"update", entity, new Long&#40;1&#41;, sessionFactory&#41;;
    			&#125;
    		&#125; catch&#40;HibernateException e&#41; &#123;
    			
    		&#125; finally &#123;
    			inserts.clear&#40;&#41;;
    			updates.clear&#40;&#41;;
    		&#125;
    		
    	&#125;
    
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#isUnsaved&#40;java.lang.Object&#41;
    	 */
    	public Boolean isUnsaved&#40;Object arg0&#41; &#123;
    		// TODO Auto-generated method stub
    		return null;
    	&#125;
    
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#findDirty&#40;java.lang.Object, java.io.Serializable, java.lang.Object&#91;&#93;, java.lang.Object&#91;&#93;, java.lang.String&#91;&#93;, net.sf.hibernate.type.Type&#91;&#93;&#41;
    	 */
    	public int&#91;&#93; findDirty&#40;Object arg0, Serializable arg1, Object&#91;&#93; arg2, Object&#91;&#93; arg3, String&#91;&#93; arg4, Type&#91;&#93; arg5&#41; &#123;
    		// TODO Auto-generated method stub
    		return null;
    	&#125;
    
    	/* &#40;non-Javadoc&#41;
    	 * @see net.sf.hibernate.Interceptor#instantiate&#40;java.lang.Class, java.io.Serializable&#41;
    	 */
    	public Object instantiate&#40;Class arg0, Serializable arg1&#41; throws CallbackException &#123;
    		// TODO Auto-generated method stub
    		return null;
    	&#125;
    	
    	public void logEvent&#40;String message, Auditable entity, Long userId&#41; 
    				throws CallbackException &#123;
    		Session session = null;
    		
    		try &#123;
    			AuditLogRecord record = new AuditLogRecord&#40;message, entity.getId&#40;&#41;,
    							entity.getClass&#40;&#41;, userId&#41;;
    			session = sessionFactory.openSession&#40;&#41;;
    			session.save&#40;record&#41;;
    			session.flush&#40;&#41;;
    		&#125; catch&#40;Exception ex&#41; &#123;
    			throw new CallbackException&#40;ex&#41;;
    		&#125; finally &#123;
    			try &#123;
    				session.close&#40;&#41;;
    			&#125; catch&#40;HibernateException ex&#41; &#123;
    				throw new CallbackException&#40;ex&#41;;				
    			&#125;
    		&#125;
    	&#125;
    
    
    	
    &#125;
    The AuditLog is the util class which has the logEvent method that logs the event in the DB.

    My Project.java extends Auditable interface.

    Here's my latest applicationContext.xml.

    Code:
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName"><value>$&#123;hibernate.connection.driver_class&#125;</value></property>
    		<property name="url"><value>$&#123;hibernate.connection.url&#125;</value></property>
    		<property name="username"><value>$&#123;hibernate.connection.username&#125;</value></property>
    		<property name="password"><value>$&#123;hibernate.connection.password&#125;</value></property> 
    	</bean>
    	
    	    <!-- Hibernate SessionFactory 2 used for audit log-->
        <bean id="sessionFactory2" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
            <property name="dataSource"><ref local="dataSource"/></property>
     		<property name="mappingResources">
    			<list>
    				<value>com/apple/ermt/model/Project.hbm.xml</value>
    				<value>com/apple/ermt/model/ProjectResource.hbm.xml</value>
    				<value>com/apple/ermt/model/Resource.hbm.xml</value>
    				<value>com/apple/ermt/model/Requirement.hbm.xml</value>	
    				<value>com/apple/ermt/model/TestCase.hbm.xml</value>	
    				<value>com/apple/ermt/persistence/audit/AuditLogRecord.hbm.xml</value>	
    				<value>com/apple/ermt/model/UseCase.hbm.xml</value>						
    			</list>
    		</property>
        </bean>
     
     
    	<bean id="auditLog" class="com.apple.ermt.persistence.audit.interceptor.AuditLog"/>
    
    	<bean id="auditLogRecord" class="com.apple.ermt.persistence.audit.AuditLogRecord"/>
    
        <!-- Hibernate SessionFactory -->
        <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
            <property name="dataSource"><ref local="dataSource"/></property>
     		<property name="mappingResources">
    			<list>
    				<value>com/apple/ermt/model/Project.hbm.xml</value>
    				<value>com/apple/ermt/model/ProjectResource.hbm.xml</value>
    				<value>com/apple/ermt/model/Resource.hbm.xml</value>
    				<value>com/apple/ermt/model/Requirement.hbm.xml</value>	
    				<value>com/apple/ermt/model/TestCase.hbm.xml</value>	
    				<value>com/apple/ermt/persistence/audit/AuditLogRecord.hbm.xml</value>	
    				<value>com/apple/ermt/model/UseCase.hbm.xml</value>								</list>
    		</property>
            <property name="hibernateProperties">
    		<props>
    		    <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
    		    <prop key="hibernate.hbm2ddl.auto">create</prop>
    		</props>
            </property>  
        </bean>
    
    <!--
    	<bean id="myHibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
    	      <property name="sessionFactory"><ref local="sessionFactory2"/></property>
    	      <property name="entityInterceptorBeanName"><value>auditLogInterceptor</value></property>
    	</bean>
     -->
     
    	<bean id="auditLogInterceptor" class="com.apple.ermt.persistence.audit.interceptor.AuditLogRecordInterceptor" singleton="false">
    		<property name="auditLog"><ref local="auditLog"/></property>
    	</bean>
    
        <!-- Transaction manager for a single Hibernate SessionFactory &#40;alternative to JTA&#41; -->
        <bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
            <property name="sessionFactory"><ref local="sessionFactory"/></property>
       		<property name="entityInterceptor"><ref local="auditLogInterceptor"/></property>    
        </bean>

    Please note that i'm wiring the interceptor through the transaction manager.

    My problem is that, when i save the project, the interceptor never gets called.


    Could someone please let me know what is that i'm missing?

    Thanks in advance!

Similar Threads

  1. Replies: 5
    Last Post: Feb 3rd, 2009, 05:19 AM
  2. Replies: 3
    Last Post: Aug 16th, 2007, 12:10 PM
  3. A Spring Class Loader?
    By azzoti in forum Architecture
    Replies: 8
    Last Post: May 7th, 2005, 04:02 AM
  4. Replies: 14
    Last Post: Feb 21st, 2005, 05:41 PM
  5. Replies: 7
    Last Post: Aug 21st, 2004, 03:42 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •