Results 1 to 5 of 5

Thread: HibernateAuditInterceptor Bean will not initialize

  1. #1
    Join Date
    Jul 2007
    Location
    Berne, Switzerland
    Posts
    7

    Question HibernateAuditInterceptor Bean will not initialize

    Hi there

    I've got some troubles with a portal framework which i had to adapt in my organization. Because I am completely new in Spring I have to search help here (the developer which made the prototype, left our organization recently..).

    Here's what confused me: I initialize in the portal context just the same beans as I do in one of the portlets. But only the portal context will be initialized, the other in the portlet will not.

    Everything is going fine until I add my own HibernateAuditInterceptor bean which will do an audit log on every transaction of the given portlet. If i remove this bean in the second configuration, everything works fine. Because it works in the first case, I don't think that the HibernateAuditInterceptor class is implemented faulty.

    Here is the configuration of the portal application context which works fine with the bean with id hInterceptor:
    Code:
    <beans default-autowire="autodetect">
    
    	<bean id="msSqlServerDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    
    		<!-- MSSQL Server config -->
    		<property name="driverClassName" value="com.microsoft.jdbc.sqlserver.SQLServerDriver" />
    		<property name="url" value="jdbc:microsoft:sqlserver://SERVERXX:1433;DatabaseName=Customerportal" />
    		<property name="username" value="portalservice" />
    		<property name="password" value="password" />
    	</bean>
    
    	<bean id="hInterceptor" class="com.usp.portal.portlets.usermgmt.models.audit.HibernateAuditInterceptor">
    		<property name="sessionFactory" ref="msSqlServerSessionFactory" />
    	</bean>
    
    	<bean id="msSqlServerSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="dataSource" ref="msSqlServerDataSource" />
    
    		<property name="configLocation">
    			<value>classpath:hibernatemapping-usermgmt.cfg.xml</value>
    		</property>
    
    
    		<property name="configurationClass">
    			<value>org.hibernate.cfg.Configuration</value>
    		</property>
    
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    			</props>
    		</property>
    
    		<property name="eventListeners">
    			<map>
    				<entry key="pre-update">
    					<bean class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/>
    				</entry>
    				<entry key="pre-insert">
    					<bean class="org.hibernate.validator.event.ValidatePreInsertEventListener"/>
    				</entry>
    			</map>
    		</property>
    	</bean>
    
    	<bean id="PortalPrincipalResolver"
    		class="com.usp.portal.core.resolver.PortalPrincipalResolver" scope="singleton">
    		<property name="sessionFactory" ref="msSqlServerSessionFactory" />
    	</bean>
    
    </beans>

    But nearly the same configuration will not work in the portlet application context. Note that the bean for the principal resolver was removed and another bean (myHibernate) was added:
    Code:
    <beans default-autowire="autodetect">
    	<bean id="msSqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
                  <snip>...<snap>
    	</bean>
    
    	<bean id="myHibernate" class="com.usp.portal.portlets.usermgmt.dao.Hibernate" scope="singleton">
    		<property name="sessionFactory" ref="msSqlSessionFactory" />
    	</bean>
    
    	<bean id="hInterceptor" class="com.usp.portal.portlets.usermgmt.models.audit.HibernateAuditInterceptor">
    		<property name="sessionFactory" ref="msSqlSessionFactory" />
    	</bean>
    	
    	<bean id="msSqlSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="dataSource" ref="msSqlDataSource" />
    
    		<property name="configLocation">
    			<value>classpath:hibernatemapping-usermgmt.cfg.xml</value>
    		</property>
                    
                    <snip>...<snap>
    
    	</bean>
    </beans>
    After a start of my Tomcat 6 instance of the portal, the following log will appear (the first section shows the init of the portal which works fine (not showed here!)):
    Code:
    xml.XmlBeanDefinitionReader:loadBeanDefinitions() - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring-hibernate-usermgmt.xml]
    support.XmlWebApplicationContext:refreshBeanFactory() - Bean factory for application context [Root WebApplicationContext]: org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [msSqlDataSource,myHibernate,hInterceptor,msSqlSessionFactory]; root of BeanFactory hierarchy
    support.XmlWebApplicationContext:refresh() - 4 beans defined in application context [Root WebApplicationContext]
    support.DefaultListableBeanFactory:preInstantiateSingletons() - Pre-instantiating singletons in factory [org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [msSqlDataSource,myHibernate,hInterceptor,msSqlSessionFactory]; root of BeanFactory hierarchy]
    support.DefaultListableBeanFactory:destroySingletons() - Destroying singletons in {org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [msSqlDataSource,myHibernate,hInterceptor,msSqlSessionFactory]; root of BeanFactory hierarchy}
    context.ContextLoader:initWebApplicationContext() - Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myHibernate' defined in ServletContext resource [/WEB-INF/spring-hibernate-usermgmt.xml]: Cannot resolve reference to bean 'msSqlSessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hInterceptor' defined in ServletContext resource [/WEB-INF/spring-hibernate-usermgmt.xml]: Cannot resolve reference to bean 'msSqlSessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'msSqlSessionFactory': FactoryBean which is currently in creation returned null from getObject
    Caused by: 
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hInterceptor' defined in ServletContext resource [/WEB-INF/spring-hibernate-usermgmt.xml]: Cannot resolve reference to bean 'msSqlSessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'msSqlSessionFactory': FactoryBean which is currently in creation returned null from getObject
    Caused by: 
    org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'msSqlSessionFactory': FactoryBean which is currently in creation returned null from getObject
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectFromFactoryBean(AbstractBeanFactory.java:1223)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1177)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:161)
    	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:245)
    	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:124)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1019)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:809)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:425)
    	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:250)
    	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:141)
    
    <snip>...<snap>
    In my opinion i have no circular references in the second application context configuration, but if I should be wrong with that suggestion please tell me ;-)

    I can't get it out what the problem is, do i had to create a BeanInitializer to do a workaround, or does anyone see where the problem is?

    Thanks for your replies.
    Mike

  2. #2

    Default

    Please post code for ur hibernateAuditInterceptor bean

  3. #3
    Join Date
    Jul 2007
    Location
    Berne, Switzerland
    Posts
    7

    Default

    Here is the source of the HibernateAuditInterceptor

    Code:
    package com.usp.portal.portlets.usermgmt.models.audit;
    
    
    import java.io.Serializable;
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    import org.apache.log4j.Logger;
    import org.hibernate.CallbackException;
    import org.hibernate.EmptyInterceptor;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.type.Type;
    
    import com.usp.portal.portlets.usermgmt.models.AbstractPersistentObject;
    import com.usp.portal.portlets.usermgmt.models.Auditable;
    
    
    /**
     * The HibernateInterceptor is used to create the necessary entries
     * for changes on Entities in the Audit Log Table of the database.
     * <p>
     * A AuditLoggerInterceptor is instanciated per HibernateSession.
     * Every object is passed trough this interceptor individually.
     * </p>
     */
    public class HibernateAuditInterceptor extends EmptyInterceptor {
    
      /**
       * The logger to be used for this class.
       */
      private static final Logger log = Logger.getLogger(HibernateAuditInterceptor.class);
    
      /**
       * A Set containing references to the inserted Entities. Will be used
       * to create the Log Entries after flush.
       */
      private Set<Auditable> insertedEntities = new HashSet<Auditable>();
    
      /**
       * A Set containing references to the updated Entities. Will be used
       * to create the Log Entries after flush.
       */
      private Set<Auditable> updatedEntities = new HashSet<Auditable>();
    
      /**
       * A Set containing references to the deleted Entities. Will be used
       * to create the Log Entries after flush.
       */
      private Set<Auditable> deletedEntities = new HashSet<Auditable>();
    
      /**
       * The session factory to use when doing auditlogging.
       */
      private SessionFactory sessionFactory = null;
    
      
      /**
       * This method takes care about auditing for updated records.
       *
       * @see org.hibernate.Interceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
       */
      public boolean onFlushDirty(Object entity, Serializable id, Object[] state,
          Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException {
    
        if (entity instanceof Auditable) {
          updatedEntities.add((Auditable)entity);
        }
        return false;
      }
    
    
      /**
       * This method takes care about auditing for inserted records.
       *
       * @see org.hibernate.Interceptor#onSave(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
       */
      public boolean onSave(Object entity, Serializable id, Object[] state,
          String[] propertyNames, Type[] types) throws CallbackException {
    
        boolean changed = false;
    
        if (entity instanceof Auditable) {
          insertedEntities.add((Auditable)entity);
        }
        Date now = new Date();
    
        if (entity instanceof AbstractPersistentObject) {
          String userPid = getUserName();
    
          for (int x=0; x< propertyNames.length; x++) {
            if ("createDate".equals(propertyNames[x])
            		&& state[x] == null) {
              state[x] = now;
              changed = true;
            } else if ("createUser".equals(propertyNames[x])
            		&& state[x] == null) {
              state[x] = userPid;
              changed = true;
            } else if ("modifyDate".equals(propertyNames[x])) {
                state[x] = now;
                changed = true;
            } else if ("modifyUser".equals(propertyNames[x])) {
                state[x] = userPid;
                changed = true;
            }
          }
        }
        return changed;
      }
    
      /**
       * This method takes care about auditing for deleted records.
       *
       * @see org.hibernate.Interceptor#onDelete(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
       */
      public void onDelete(Object entity, Serializable id, Object[] state,
          String[] propertyNames, Type[] types) throws CallbackException {
    
        if (entity instanceof Auditable) {
          deletedEntities.add((Auditable)entity);
        }
      }
    
      /**
       * Creates all the Auditlog entries for the inserted, updated and
       * deleted entities and stores them on the database.
       *
       * @see org.hibernate.Interceptor#postFlush(java.util.Iterator)
       */
      public void postFlush(Iterator arg0) throws CallbackException {
        Session tempSession = null;
    
        try {
    
        	if (sessionFactory != null) {
        		tempSession = sessionFactory.openSession();
        	}
    
          String userName = getUserName();
    
          // create the log entries for the new records
          Iterator it = insertedEntities.iterator();
          while (it.hasNext()) {
            Auditable auditable = (Auditable)it.next();
            AuditLogHelper.insert(auditable, userName, tempSession);
          }
          insertedEntities.clear();
    
          // create the log entries for the updated records
          it = updatedEntities.iterator();
          while (it.hasNext()) {
            Auditable auditable = (Auditable)it.next();
            AuditLogHelper.update(auditable, userName, tempSession);
          }
          updatedEntities.clear();
    
          // create the log entries for the new records
          it = deletedEntities.iterator();
          while (it.hasNext()) {
            Auditable auditable = (Auditable)it.next();
            AuditLogHelper.delete(auditable, userName, tempSession);
          }
          deletedEntities.clear();
    
          if (tempSession != null) {
          	tempSession.flush();
          }
        } catch(Exception ex) {
          log.error("Error while postFlusing", ex);
        } finally {
          if (tempSession != null) {
            tempSession.close();
          }
        }
      }
    
      /**
       * @return Returns the userPID.
       */
      public String getUserName() {
        String retVal = null;
    
        // get the user from the Operating system:
        String osUser = System.getProperty("user.name");
        if (osUser != null && osUser.length() > 0) {
          retVal= osUser;
        }
    
    
        return retVal;
      }
    
      public SessionFactory getSessionFactory() {
    	return sessionFactory;
      }
    
      public void setSessionFactory(SessionFactory factory) {
    	this.sessionFactory = factory;
      }
    }

  4. #4
    Join Date
    Jul 2007
    Location
    Berne, Switzerland
    Posts
    7

    Thumbs up finally solved

    I solved my problem with the depends-on flag. With that option, and with a fallback on the Spring version 2.0.2 my Interceptor now initializes properly.


    Here my current bean configuration:
    Code:
    <beans default-autowire="autodetect">
    	<bean id="msSqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    
    		<property name="driverClassName" value="com.microsoft.jdbc.sqlserver.SQLServerDriver" />
    		<property name="url" value="jdbc:microsoft:sqlserver://SERVERXX:1433;DatabaseName=Customerportal" />
    		<property name="username" value="portalservice" />
    		<property name="password" value="password" />
    	</bean>
    
    	<bean id="hInterceptor" class="com.usp.portal.portlets.usermgmt.models.audit.HibernateAuditInterceptor" depends-on="sqlSessionFactory">
    		<property name="sessionFactory" ref="sqlSessionFactory" />
    	</bean>
    
    	<bean id="sqlSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" depends-on="msSqlDataSource" autowire="no">
    		<property name="dataSource" ref="msSqlDataSource" />
    		<property name="configLocation">
    			<value>classpath:hibernatemapping-usermgmt.cfg.xml</value>
    		</property>
    
    
    		<property name="configurationClass">
    			<value>org.hibernate.cfg.Configuration</value>
    		</property>
    
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    			</props>
    		</property>
    
    		<property name="eventListeners">
    			<map>
    				<entry key="pre-update">
    					<bean class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/>
    				</entry>
    				<entry key="pre-insert">
    					<bean class="org.hibernate.validator.event.ValidatePreInsertEventListener"/>
    				</entry>
    			</map>
    		</property>
    	</bean>
    	
    	
    	<bean id="myHibernate" class="com.usp.portal.portlets.usermgmt.dao.Hibernate" scope="singleton" depends-on="sqlSessionFactory">
    		<property name="sessionFactory" ref="sqlSessionFactory" />
    	</bean>
    	
    </beans>

  5. #5
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,624

    Default

    Just a thought...

    You are keeping state in your Singleton interceptor, isn't that going to be a problem?! What if 5 threads are going to update/add stuff with Hibernate... There is just going to be 1 instance of yuor interceptor... 5 threads are then modifying the insertedEntities, updatedEntities, deletedEntities.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

Posting Permissions

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