Announcement Announcement Module
Collapse
No announcement yet.
HibernateAuditInterceptor Bean will not initialize Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    Please post code for ur hibernateAuditInterceptor bean

    Comment


    • #3
      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;
        }
      }

      Comment


      • #4
        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>

        Comment


        • #5
          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.

          Comment

          Working...
          X