@Transactional ignored on some services while it works on others
Hi!
edit from orig post:
I have found out that when I add Spring Security, it fails to honor my @Transactional.
However, when I take it out and plugin a different security implementation (eg. JAAS/Container-Managed Authentication), my app works as expected.
I have numerous Facade beans in the same applicationContext.xml file. At runtime, some get JTA boundaries while other's @Transactional annotated methods are ignored.
All Facades have interfaces.
All Facade's @Transactional methods are public, accessed via the interface from callers.
Spring Framework 3.1.0 RELEASE
Spring Security 3.1.0 RELEASE
Here's an example of my logging. AlarmFacade gets JtaTransactionManager.begin/commit.
However, calls at the bottom (e.g., Method = getRoads, Method = getUserGroupId) both which call a RoadFacade and a SecurityFacade respectively, never get JtaTransactionManager boundaries despite the same @Transactional setup. There *should* be JtaTransactionManager begin/commit in between the "Entering Flow" and "Leaving Flow" logging, but nothing shows up.
Code:
2012-07-20 14:27:29,378 DEBUG [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) processAction: Enter Flow = 'alarm-get-unack-alarms-action', Request Principal = FOO
2012-07-20 14:27:29,378 DEBUG [cdot.ctms.layer.delegate.controllers.AlarmController] (WorkerThread#1[127.0.0.1:62171]) getUnacknowledgedAlarms: Enter
2012-07-20 14:27:29,378 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (WorkerThread#1[127.0.0.1:62171]) Returning cached instance of singleton bean 'transactionManager'
2012-07-20 14:27:29,378 DEBUG [org.springframework.transaction.jta.JtaTransactionManager] (WorkerThread#1[127.0.0.1:62171]) Creating new transaction with name [cdot.ctms.layer.services.alarm.facade.AlarmFacade.getUnacknowledgedAlarms]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '',-java.lang.Exception
2012-07-20 14:27:29,378 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (WorkerThread#1[127.0.0.1:62171]) Initializing transaction synchronization
2012-07-20 14:27:29,378 TRACE [org.springframework.transaction.interceptor.TransactionInterceptor] (WorkerThread#1[127.0.0.1:62171]) Getting transaction for [cdot.ctms.layer.services.alarm.facade.AlarmFacade.getUnacknowledgedAlarms]
2012-07-20 14:27:29,378 DEBUG [cdot.util.ApplicationProperties] (WorkerThread#1[127.0.0.1:62171]) Resource file(s) missing key-value pair: alarm.exp.hours=12
2012-07-20 14:27:29,378 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (WorkerThread#1[127.0.0.1:62171]) Bound value [org.springframework.orm.hibernate3.SessionHolder@3eecc8ce] for key [org.hibernate.impl.SessionFactoryImpl@c0fc23d] to thread [WorkerThread#1[127.0.0.1:62171]]
2012-07-20 14:27:29,553 TRACE [org.springframework.transaction.interceptor.TransactionInterceptor] (WorkerThread#1[127.0.0.1:62171]) Completing transaction for [cdot.ctms.layer.services.alarm.facade.AlarmFacade.getUnacknowledgedAlarms]
2012-07-20 14:27:29,553 TRACE [org.springframework.transaction.jta.JtaTransactionManager] (WorkerThread#1[127.0.0.1:62171]) Triggering beforeCommit synchronization
2012-07-20 14:27:29,553 TRACE [org.springframework.transaction.jta.JtaTransactionManager] (WorkerThread#1[127.0.0.1:62171]) Triggering beforeCompletion synchronization
2012-07-20 14:27:29,553 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (WorkerThread#1[127.0.0.1:62171]) Removed value [org.springframework.orm.hibernate3.SessionHolder@3eecc8ce] for key [org.hibernate.impl.SessionFactoryImpl@c0fc23d] from thread [WorkerThread#1[127.0.0.1:62171]]
2012-07-20 14:27:29,553 DEBUG [org.springframework.transaction.jta.JtaTransactionManager] (WorkerThread#1[127.0.0.1:62171]) Initiating transaction commit
2012-07-20 14:27:29,668 TRACE [org.springframework.transaction.jta.JtaTransactionManager] (WorkerThread#1[127.0.0.1:62171]) Triggering afterCommit synchronization
2012-07-20 14:27:29,668 TRACE [org.springframework.transaction.jta.JtaTransactionManager] (WorkerThread#1[127.0.0.1:62171]) Triggering afterCompletion synchronization
2012-07-20 14:27:29,668 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (WorkerThread#1[127.0.0.1:62171]) Clearing transaction synchronization
2012-07-20 14:27:29,668 DEBUG [cdot.ctms.layer.delegate.controllers.AlarmController] (WorkerThread#1[127.0.0.1:62171]) getUnacknowledgedAlarms: Exit
2012-07-20 14:27:29,673 INFO [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) StopWatch [action = alarm-get-unack-alarms-action, Controller = 'cdot.ctms.layer.delegate.controllers.AlarmController@4772d68', Method = 'getUnacknowledgedAlarms', Time (ms) = 295, Status = 'success' ]
2012-07-20 14:27:29,673 DEBUG [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) processAction: Leaving Flow = 'alarm-get-unack-alarms-action', Request Principal = FOO
2012-07-20 14:28:15,035 DEBUG [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) processAction: Enter Flow = 'get-manufacturers-action', Request Principal = FOO
2012-07-20 14:28:15,170 INFO [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) StopWatch [action = get-manufacturers-action, Controller = 'cdot.ctms.layer.delegate.controllers.CommonController@5bbb66c8', Method = 'getManufacturers', Time (ms) = 135, Status = 'success' ]
2012-07-20 14:28:15,170 DEBUG [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) processAction: Leaving Flow = 'get-manufacturers-action', Request Principal = FOO
2012-07-20 14:28:18,091 DEBUG [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) processAction: Enter Flow = 'security-service-get-user-group-id-action', Request Principal = FOO
2012-07-20 14:28:18,211 INFO [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) StopWatch [action = security-service-get-user-group-id-action, Controller = 'cdot.ctms.layer.delegate.controllers.UserManagementController@34d3d993', Method = 'getUserGroupId', Time (ms) = 120, Status = 'success' ]
2012-07-20 14:28:18,211 DEBUG [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) processAction: Leaving Flow = 'security-service-get-user-group-id-action', Request Principal = FOO
2012-07-20 14:28:18,271 DEBUG [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) processAction: Enter Flow = 'get-roads-action', Request Principal = FOO
2012-07-20 14:28:19,788 INFO [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) StopWatch [action = get-roads-action, Controller = 'cdot.ctms.layer.delegate.controllers.CommonController@5bbb66c8', Method = 'getRoads', Time (ms) = 1517, Status = 'success' ]
2012-07-20 14:28:19,789 DEBUG [cdot.ctms.layer.delegate.facade.AnnotationDelegateController] (WorkerThread#1[127.0.0.1:62171]) processAction: Leaving Flow = 'get-roads-action', Request Principal = FOO
When I import this file into my applicationContext.xml, I experience the problem. When I remove it and plugin a JAAS/Container-Managed Authentication solution, Spring honors my @Transactional annotations perfectly.
So, what is wrong with the way I'm importing the Spring Security beans and why does it only affect some services and not all??? Weird.
Code:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="securityService">
<security:password-encoder base64="true" hash="md5">
</security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<constructor-arg name="decisionVoters">
<list>
<bean class="org.springframework.security.access.vote.RoleVoter" />
</list>
</constructor-arg>
</bean>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="permissionEvaluator"/>
</bean>
<bean id="permissionEvaluator" class="cdot.ctms.layer.services.security.SecurityDomainPermissionEvaluator" c:domain-ref="securityDomain"/>
<bean id="ctmsAuthenticationManager" class="cdot.ctms.security.SpringSecurityAuthenticationManager"
c:authMgr-ref="authenticationManager"
/>
</beans>