Hi,
I have an issue whose cause lies somewhere between OpenJPA and Aries. Posting
it here first, please redirect me if it's the wrong place.
We use Open JPA in Karaf 3.0.2 (detailed bundle versions below). We have an DAO
object, instantiated by Blueprint with a jpa:context and a tx:transaction
element. It gets the EntityManager from Aries JPA and has a mandatory
transaction on each method call.
<bean id="masterDataDao" depends-on="dataSource"
class="some.package.MasterDataDaoImpl">
<jpa:context unitname="masterDataDb" property="entityManager"/>
<tx:transaction method="create,delete,find*,get*,update" value="Mandatory"/>
</bean>
That DAO object has CRUD methods for an entity class that uses optimistic
locking. It has a long version field annotated with @Version.
Our problem appears when we get the optimistic lock error. We would expect our
MasterDataDao.update method to throw a TransactionRollbackException with an
OptimisticLockException as its cause. Instead it throws a
TransactionRollbackException with a SetRollbackOnlyException as its cause
(TransactionImpl.java:272).
The question is why?
I tried debugging the issue. I put a breakpoint at
org.apache.geronimo.transaction.manager.TransactionImpl.markRollbackCause(java.lang.Throwable)
line: 539. AFAIU the problem is that that method is called *TWICE* when a
transaction is processed. The first time it is called with the "wrong"
exception - SetRollbackOnlyException, the second time it's called with the
correct OptimisticLockException, but the correct exception isn't recorded in
the TransactionImpl object because the markRollbackCause method looks like this:
private void markRollbackCause(Throwable e) {
if (markRollbackCause == null) {
markRollbackCause = e;
}
}
So the first time the field is set to a "wrong" value and when the correct
value comes it's lost.
I took stacktraces of both invocations. AFAIU the crucial bit is the
TransactionImpl.beforeCompletion(java.util.List) method. It first calls
synch.beforeCompletion() and then markRollbackCause. The problem is that
synch.beforeCompletion gets to markRollbackCause first. Why? Is it known? Is it
a bug? Is it some misconfiguration? Is it supposed to be fixed in Karaf 3.0.3
and its openjpa feature? Why does
PersistenceExceptions$2.translate(java.lang.RuntimeException) call
EntityManager.setRollbackOnly()?
The first markRollbackCause invocation (from the RuntimeExceptionTranslator
that calls EntityManager.setRollbackOnly):
Thread [qtp1832761053-45] (Suspended (breakpoint at line 539 in
org.apache.geronimo.transaction.manager.TransactionImpl))
owns: org.apache.geronimo.transaction.manager.TransactionImpl (id=152)
owns: org.eclipse.rap.rwt.internal.util.SerializableLock (id=153)
org.apache.geronimo.transaction.manager.TransactionImpl.markRollbackCause(java.lang.Throwable)
line: 539
org.apache.geronimo.transaction.manager.TransactionImpl.setRollbackOnly(java.lang.Throwable)
line: 134
org.apache.geronimo.transaction.manager.TransactionImpl.setRollbackOnly()
line: 126
org.apache.openjpa.ee.JNDIManagedRuntime.setRollbackOnly(java.lang.Throwable)
line: 71
org.apache.openjpa.ee.AutomaticManagedRuntime.setRollbackOnly(java.lang.Throwable)
line: 274
org.apache.openjpa.kernel.BrokerImpl.setRollbackOnlyInternal(java.lang.Throwable)
line: 1674
org.apache.openjpa.kernel.BrokerImpl.setRollbackOnly(java.lang.Throwable)
line: 1654
org.apache.openjpa.kernel.DelegatingBroker.setRollbackOnly(java.lang.Throwable)
line: 981
org.apache.openjpa.persistence.EntityManagerImpl.setRollbackOnly(java.lang.Throwable)
line: 631
org.apache.openjpa.persistence.PersistenceExceptions$2.translate(java.lang.RuntimeException)
line: 76
org.apache.openjpa.kernel.BrokerImpl.translateManagedCompletionException(java.lang.RuntimeException)
line: 2093
org.apache.openjpa.kernel.BrokerImpl.beforeCompletion() line: 2027
org.apache.geronimo.transaction.manager.TransactionImpl.beforeCompletion(java.util.List)
line: 527
org.apache.geronimo.transaction.manager.TransactionImpl.beforeCompletion()
line: 511
org.apache.geronimo.transaction.manager.TransactionImpl.beforePrepare() line:
413
org.apache.geronimo.transaction.manager.TransactionImpl.commit() line: 262
org.apache.aries.transaction.internal.AriesTransactionManagerImpl(org.apache.geronimo.transaction.manager.TransactionManagerImpl).commit()
line: 252
Proxy94d42c5b_f0da_4685_aa62_e265cec6c45a.commit() line: not available
org.apache.aries.transaction.TransactionAttribute$4.finish(javax.transaction.TransactionManager,
org.apache.aries.transaction.TransactionToken) line: 94
org.apache.aries.transaction.TxInterceptorImpl.postCallWithReturn(org.osgi.service.blueprint.reflect.ComponentMetadata,
java.lang.reflect.Method, java.lang.Object, java.lang.Object) line: 85
org.apache.aries.blueprint.proxy.Collaborator.postInvoke(java.lang.Object,
java.lang.Object, java.lang.reflect.Method, java.lang.Object) line: 105
Proxy8b595ed5_edc7_4490_8e6d_48b3560da384.update(somepackage.MasterData)
line: not available
The second one (directly from TransactionImpl):
Thread [qtp1832761053-45] (Suspended (breakpoint at line 539 in
org.apache.geronimo.transaction.manager.TransactionImpl))
owns: org.apache.geronimo.transaction.manager.TransactionImpl (id=152)
owns: org.eclipse.rap.rwt.internal.util.SerializableLock (id=153)
org.apache.geronimo.transaction.manager.TransactionImpl.markRollbackCause(java.lang.Throwable)
line: 539
org.apache.geronimo.transaction.manager.TransactionImpl.beforeCompletion(java.util.List)
line: 531
org.apache.geronimo.transaction.manager.TransactionImpl.beforeCompletion()
line: 511
org.apache.geronimo.transaction.manager.TransactionImpl.beforePrepare() line:
413
org.apache.geronimo.transaction.manager.TransactionImpl.commit() line: 262
org.apache.aries.transaction.internal.AriesTransactionManagerImpl(org.apache.geronimo.transaction.manager.TransactionManagerImpl).commit()
line: 252
Proxy94d42c5b_f0da_4685_aa62_e265cec6c45a.commit() line: not available
org.apache.aries.transaction.TransactionAttribute$4.finish(javax.transaction.TransactionManager,
org.apache.aries.transaction.TransactionToken) line: 94
org.apache.aries.transaction.TxInterceptorImpl.postCallWithReturn(org.osgi.service.blueprint.reflect.ComponentMetadata,
java.lang.reflect.Method, java.lang.Object, java.lang.Object) line: 85
org.apache.aries.blueprint.proxy.Collaborator.postInvoke(java.lang.Object,
java.lang.Object, java.lang.reflect.Method, java.lang.Object) line: 105
Proxy8b595ed5_edc7_4490_8e6d_48b3560da384.update(somepackage.MasterData)
line: not available
All kinds of comments welcome.
--
Antoni Myłka
Software Engineer
Quantinum AG, Birkenweg 61, CH-3013 Bern - Fon +41 31 388 20 40
http://www.quantinum.com - Experience the Power of Data
P.S. Versions of the relevant bundles
9 | Active | 20 | 1.1.0 | Apache Aries Util
10 | Active | 20 | 1.0.1 | Apache Aries Proxy API
11 | Active | 20 | 1.0.3 | Apache Aries Proxy Service
12 | Active | 20 | 1.0.1 | Apache Aries Blueprint API
13 | Active | 20 | 1.0.5 | Apache Aries Blueprint CM
14 | Resolved | 20 | 1.0.0 | Apache Aries Blueprint Core
Compatiblity Fragment Bundle, Hosts: 15
15 | Active | 20 | 1.4.1 | Apache Aries Blueprint Core,
Fragments: 14
71 | Active | 50 | 0 |
wrap_mvn_postgresql_postgresql_9.1-901.jdbc4
76 | Active | 30 | 1.1.1 | geronimo-jta_1.1_spec
77 | Active | 30 | 1.0.1 | Annotation 1.1
96 | Active | 30 | 1.0.0 | Aries JPA Container API
97 | Active | 30 | 1.0.1 | Aries JPA Container blueprint
integration for Aries blueprint
98 | Active | 30 | 1.0.0 | Aries JPA Container
99 | Active | 30 | 1.0.1 | Aries JPA Container Managed
Contexts
100 | Active | 30 | 1.0.1 | Apache Aries Transaction
Blueprint
101 | Active | 30 | 1.1.0 | Apache Aries Transaction Manager
103 | Active | 30 | 3.0.2 | Apache Karaf :: JNDI :: Core
104 | Active | 30 | 1.0.0 | Apache Aries JNDI API
105 | Active | 30 | 1.0.0 | Apache Aries JNDI Core
106 | Active | 30 | 1.0.0 | Apache Aries JNDI RMI Handler
107 | Active | 30 | 1.0.0 | Apache Aries JNDI URL Handler
108 | Active | 30 | 1.0.0 | Apache Aries JNDI Support for
Legacy Runtimes
109 | Active | 80 | 3.0.2 | Apache Karaf :: JNDI :: Command
118 | Active | 50 | 2.3.0 | OpenJPA Aggregate Jar