You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Antoni Myłka <an...@quantinum.com> on 2015/06/29 11:59:48 UTC

Expected an OptimistickLockException but got a SetRollbackOnlyException

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

Re: Expected an OptimistickLockException but got a SetRollbackOnlyException

Posted by Antoni Myłka <an...@quantinum.com>.
Hi,

This seems to be known:

https://issues.apache.org/jira/browse/GERONIMO-4576

AFAIU the reasoning is that "exceptions on the server side should not be thrown to the client side since such exceptions types might not be known by the client". 

That issue has been open for six years now and it's still on the "Wish list". Does this mean that I can't get my OptimisticLockException in the client code by design? Are there any workarounds?

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

----- Ursprüngliche Mail -----
Von: "Antoni Myłka" <an...@quantinum.com>
An: users@openjpa.apache.org
Gesendet: Montag, 29. Juni 2015 11:59:48
Betreff: Expected an OptimistickLockException but got a SetRollbackOnlyException

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