nishiz
nishiz

Reputation: 55

@Transactional not creating session - org.hibernate.HibernateException: No Session found for current thread

Hi I have written a authentication event listener module to lock user after max login attempts.

<beans:bean id="ftfStatsAuthenticationEvent" class="com.ibm.ftfstats.auth.FTFStatsAuthenticationEvent">
<beans:property name="userMgr" ref="userManager"></beans:property>
</beans:bean>

This is how the module for capturing AuthenticationFailure event has been defined

public void onApplicationEvent(ApplicationEvent event) {
    // TODO Auto-generated method stub
    if(event instanceof AuthenticationFailureBadCredentialsEvent){
        onAuthenticationFailureBadCredentialsEvent((AuthenticationFailureBadCredentialsEvent)event);
    }else if(event instanceof AuthenticationSuccessEvent){
        onAuthenticationSuccessEvent((AuthenticationSuccessEvent)event);
    }
}

    public void onAuthenticationFailureBadCredentialsEvent(AuthenticationFailureBadCredentialsEvent event){
    Authentication authentication = event.getAuthentication();
    String userId = authentication.getName();
    System.out.println("bad credential for user : " + userId);
    getUserMgr().encounterFailedlogin(userId);
    User user = getUserMgr().getUserById(userId);
} 

The getUserMgr() returns a User Manager class where the encounterFailedlogin(userId) methos is defined as

public User encounterFailedlogin(String userId) {
    // TODO Auto-generated method stub
    User user = getUserDAO().getUserById(userId);
    return encounterFailedlogin(user);

}

@Transactional
public User encounterFailedlogin(User user) {
    // TODO Auto-generated method stub
    int failedAttempts = user.getFailedAttempts() + 1;
    user.setFailedAttempts(failedAttempts);
    System.out.println("updating user");
    updateUser(user);
    return getUserDAO().getUserById(user.getUserID());
    //return true;
}
 @Transactional
public boolean updateUser(User user){
    getUserDAO().updateUser(user);
    return true;
}

The User DAO is defined as:

public void addUser(User user){
    getSessionFactory().getCurrentSession().save(user);
}

My application context file is defined as

<!-- UserDB Session Factory Declaration -->
<bean id="UserSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="UserDataSource" />
    <property name="annotatedClasses">
        <list>
            <value>com.ibm.ftfstats.data.user.model.User</value>                
            <value>com.ibm.ftfstats.data.user.model.Environment</value>
            <value>com.ibm.ftfstats.data.user.model.Role</value>
            <value>com.ibm.ftfstats.data.user.model.Question</value>
            <value>com.ibm.ftfstats.data.user.model.SearchCriteria</value>
            <value>com.ibm.ftfstats.data.user.model.UserRequest</value>
            <value>com.ibm.ftfstats.data.user.model.RequestType</value>
            <value>com.ibm.ftfstats.data.user.model.RequestComment</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>   

        </props>
    </property>
</bean>

<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name = "sessionFactory" ref = "UserSessionFactory" />
</bean>

<tx:annotation-driven/>

<!-- DAOs List goes here -->
<bean id="UserDAO" class="com.ibm.ftfstats.data.dao.UserDAO">
    <property name="sessionFactory" ref="UserSessionFactory"></property>
    <property name="msg" ref="msgBundle"></property>
</bean>
<bean id="userManager" class="com.ibm.ftfstats.service.impl.UserManagerImp">
    <property name="userDAO" ref="UserDAO" />       
</bean>

This is the error that I a get when I enter a wrong credential in the login form

SEVERE: Servlet.service() for servlet default threw exception
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978)
at com.ibm.ftfstats.data.dao.UserDAO.updateUser(UserDAO.java:35)
at com.ibm.ftfstats.data.dao.UserDAO$$FastClassByCGLIB$$37731f27.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:627)
at com.ibm.ftfstats.data.dao.UserDAO$$EnhancerByCGLIB$$388b21db.updateUser(<generated>)
at com.ibm.ftfstats.service.impl.UserManagerImp.updateUser(UserManagerImp.java:97)
at com.ibm.ftfstats.service.impl.UserManagerImp.encounterFailedlogin(UserManagerImp.java:84)
at com.ibm.ftfstats.service.impl.UserManagerImp.encounterFailedlogin(UserManagerImp.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
at $Proxy17.encounterFailedlogin(Unknown Source)
at  com.ibm.ftfstats.auth.FTFStatsAuthenticationEvent.onAuthenticationFailureBadCredentialsEvent(FTFStatsAuthenticationEvent.java:42)
at com.ibm.ftfstats.auth.FTFStatsAuthenticationEvent.onApplicationEvent(FTFStatsAuthenticationEvent.java:29)

Can anyone please suggest where am I going wrong.

Upvotes: 0

Views: 1849

Answers (3)

a better oliver
a better oliver

Reputation: 26828

public User encounterFailedlogin(String userId) needs to be annotated with @Transactional. As far as I can see this is the method that is called from outside the class.

return encounterFailedlogin(user); is an internal call and as such is not proxied. So in this case public User encounterFailedlogin(User user) has no idea of being transactional.

Upvotes: 0

maggu
maggu

Reputation: 1199

Are you sure you have defined UserDataSource in the application context? I don't see one.

Upvotes: 0

Normally a spring proxy does not work, when a method is called within a class but only from an other class. You can use aspectj to get around that problem or redesign your classses.

Understnd aop proxies

Upvotes: 1

Related Questions