OpenJPA
  1. OpenJPA
  2. OPENJPA-462

OptimisticException is thrown instead of OptimisticLockException

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 0.9.7
    • Fix Version/s: 1.2.0
    • Component/s: None
    • Labels:
      None
    • Environment:
      BEA WebLogic Server 10

      Description

      In my application, i wanted to catch "javax.persistence.OptimisticLockException" and take appropriate action. However I am seeing that instead "org.apache.openjpa.util.OptimisticException" is being thrown. I don't want my code to become dependent on OpenJPA and would like to see OptimisticLockException thrown.

      While discussing in the OpenJPA forums, Patrick suggested that I create a JIRA issue for this since its a bug.
      You can see the discussion in the forum under title "OptimisticException question" few days ago.

      Below is the stack trace from my application.

      <Nov 30, 2007 9:50:53 AM EST> <Error> <EJB> <BEA-010026> <Exception occurred during commit of transaction Name=[EJB com.covergence.soa.covapi.sesscfg.SessionConfigBean.getSessionConfig(com.covergence.soa.utils.SerJavaSipMessageType)],Xid=BEA1-00001267875BE126CEB7(64273527),Status=Rolled back. [Reason=<2|false|0.9.7> org.apache.openjpa.util.OptimisticException: Optimistic locking errors were detected when flushing to the data store. The following objects may have been concurrently modified in another transaction: [com.covergence.soa.covapi.userpolicy.User-com.covergence.soa.covapi.userpolicy.User-1]],numRepliesOwedMe=0,numRepliesOwedOthers=0,seconds since begin=2,seconds left=30,SCInfo[ajayProduction+AdminServer]=(state=rolledback),properties=(

      {weblogic.transaction.name=[EJB com.covergence.soa.covapi.sesscfg.SessionConfigBean.getSessionConfig(com.covergence.soa.utils.SerJavaSipMessageType)]}

      ),OwnerTransactionManager=ServerTM[ServerCoordinatorDescriptor=(CoordinatorURL=AdminServer+172.30.0.202:7001+ajayProduction+t3+admin+7001+,XAResources=

      {WLStore_ajayProduction__WLS_AdminServer}

      ,NonXAResources={})],CoordinatorURL=AdminServer+172.30.0.202:7001+ajayProduction+t3+admin+7001+): weblogic.transaction.RollbackException: Optimistic locking errors were detected when flushing to the data store. The following objects may have been concurrently modified in another transaction: [com.covergence.soa.covapi.userpolicy.User-com.covergence.soa.covapi.userpolicy.User-1]

      at weblogic.transaction.internal.TransactionImpl.throwRollbackException(TransactionImpl.java:1818)

      at weblogic.transaction.internal.ServerTransactionImpl.internalCommit(ServerTransactionImpl.java:333)

      at weblogic.transaction.internal.ServerTransactionImpl.commit(ServerTransactionImpl.java:227)

      at weblogic.ejb.container.internal.BaseRemoteObject.postInvoke1(BaseRemoteObject.java:606)

      at weblogic.ejb.container.internal.StatelessRemoteObject.postInvoke1(StatelessRemoteObject.java:57)

      at weblogic.ejb.container.internal.BaseRemoteObject.postInvokeTxRetry(BaseRemoteObject.java:426)

      at com.covergence.soa.covapi.sesscfg.SessionConfigBean_4w7egw_SessionConfigImpl.getSessionConfig(SessionConfigBean_4w7egw_SessionConfigImpl.java:76)

      at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)

      at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)

      at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:63)

      at $Proxy67.getSessionConfig(Lcom.covergence.soa.utils.SerJavaSipMessageType;)Lcom.covergence.ws.callouts.SessionConfigType;(Unknown Source)

      at com.covergence.soa.ws.server.CallOutsImpl.getSessionConfigType(CallOutsImpl.java:46)

      at com.covergence.soa.ws.server.CallOutsImplBase.getSessionPolicy(CallOutsImplBase.java:238)

      at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)

      at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)

      at weblogic.wsee.jaxws.WLSInvoker.invoke(WLSInvoker.java:50)

      at weblogic.wsee.jaxws.WLSInvoker.invoke(WLSInvoker.java:42)

      at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:247)

      at com.sun.xml.ws.server.sei.SEIInvokerPipe.process(SEIInvokerPipe.java:97)

      at weblogic.wsee.jaxws.MonitoringPipe.process(MonitoringPipe.java:98)

      at com.sun.xml.ws.protocol.soap.ServerMUPipe.process(ServerMUPipe.java:62)

      at com.sun.xml.ws.server.WSEndpointImpl$1.process(WSEndpointImpl.java:139)

      at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:153)

      at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:235)

      at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:97)

      at weblogic.wsee.jaxws.HttpServletAdapter.post(HttpServletAdapter.java:36)

      .>

      javax.ejb.EJBException: nested exception is: <2|false|0.9.7> org.apache.openjpa.util.OptimisticException: Optimistic locking errors were detected when flushing

      to the data store. The following objects may have been concurrently modified in another transaction: [com.covergence.soa.covapi.userpolicy.User-com.covergence.

      soa.covapi.userpolicy.User-1]<2|false|0.9.7> org.apache.openjpa.util.OptimisticException: Optimistic locking errors were detected when flushing to the data store. The following objects may have been concurrently modified in another transaction: [com.covergence.soa.covapi.userpolicy.User-com.covergence.soa.covapi.userpolicy.User-1]

      at org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2120)

      at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1970)

      at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:1868)

      at org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:1786)

      at weblogic.transaction.internal.ServerSCInfo.doBeforeCompletion(ServerSCInfo.java:1212)

      at weblogic.transaction.internal.ServerSCInfo.callBeforeCompletions(ServerSCInfo.java:1190)

      at weblogic.transaction.internal.ServerSCInfo.startPrePrepareAndChain(ServerSCInfo.java:118)

      at weblogic.transaction.internal.ServerTransactionImpl.localPrePrepareAndChain(ServerTransactionImpl.java:1299)

      at weblogic.transaction.internal.ServerTransactionImpl.globalPrePrepare(ServerTransactionImpl.java:2111)

      at weblogic.transaction.internal.ServerTransactionImpl.internalCommit(ServerTransactionImpl.java:260)

      at weblogic.transaction.internal.ServerTransactionImpl.commit(ServerTransactionImpl.java:227)

      at weblogic.ejb.container.internal.BaseRemoteObject.postInvoke1(BaseRemoteObject.java:606)

      at weblogic.ejb.container.internal.StatelessRemoteObject.postInvoke1(StatelessRemoteObject.java:57)

      at weblogic.ejb.container.internal.BaseRemoteObject.postInvokeTxRetry(BaseRemoteObject.java:426)

      at com.covergence.soa.covapi.sesscfg.SessionConfigBean_4w7egw_SessionConfigImpl.getSessionConfig(SessionConfigBean_4w7egw_SessionConfigImpl.java:76)

      at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)

      at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)

      at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:63)

      at $Proxy67.getSessionConfig(Lcom.covergence.soa.utils.SerJavaSipMessageType;)Lcom.covergence.ws.callouts.SessionConfigType;(Unknown Source)

      at com.covergence.soa.ws.server.CallOutsImpl.getSessionConfigType(CallOutsImpl.java:46)

      Caused by: <2|false|0.9.7> org.apache.openjpa.util.OptimisticException: An optimistic lock violation was detected when flushing object instance "com.covergence.soa.covapi.userpolicy.User-com.covergence.soa.covapi.userpolicy.User-1" to the data store. This indicates that the object was concurrently modified in anothertransaction.

      FailedObject: com.covergence.soa.covapi.userpolicy.User-com.covergence.soa.covapi.userpolicy.User-1

      at kodo.jdbc.kernel.BatchingPreparedStatementManager.checkUpdate(BatchingPreparedStatementManager.java:354)

      at kodo.jdbc.kernel.BatchingPreparedStatementManager.flushInternal(BatchingPreparedStatementManager.java:208)

      at kodo.jdbc.kernel.BatchingPreparedStatementManager.flush(BatchingPreparedStatementManager.java:188)

      at kodo.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:90)

      at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:86)

      at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:69)

      at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.flush(JDBCStoreManager.java:511)

      at org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:127)

      at org.apache.openjpa.datacache.DataCacheStoreManager.flush(DataCacheStoreManager.java:506)

      at org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:127)

      at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1970)

      at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:1868)

      at org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:1786)

      at weblogic.transaction.internal.ServerSCInfo.doBeforeCompletion(ServerSCInfo.java:1212)

      at weblogic.transaction.internal.ServerSCInfo.callBeforeCompletions(ServerSCInfo.java:1190)

      at weblogic.transaction.internal.ServerSCInfo.startPrePrepareAndChain(ServerSCInfo.java:118)

      at weblogic.transaction.internal.ServerTransactionImpl.localPrePrepareAndChain(ServerTransactionImpl.java:1299)

      at weblogic.transaction.internal.ServerTransactionImpl.globalPrePrepare(ServerTransactionImpl.java:2111)

      at weblogic.transaction.internal.ServerTransactionImpl.internalCommit(ServerTransactionImpl.java:260)

      at weblogic.transaction.internal.ServerTransactionImpl.commit(ServerTransactionImpl.java:227)

      at weblogic.ejb.container.internal.BaseRemoteObject.postInvoke1(BaseRemoteObject.java:606)

      at weblogic.ejb.container.internal.StatelessRemoteObject.postInvoke1(StatelessRemoteObject.java:57)

      at weblogic.ejb.container.internal.BaseRemoteObject.postInvokeTxRetry(BaseRemoteObject.java:426)

      javax.ejb.EJBException: nested exception is: <2|false|0.9.7> org.apache.openjpa.util.OptimisticException: Optimistic locking errors were detected when flushing to the data store. The following objects may have been concurrently modified in another transaction: [com.covergence.soa.covapi.userpolicy.User-com.covergence.soa.covapi.userpolicy.User-1]

      at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:78)

      at $Proxy67.getSessionConfig(Lcom.covergence.soa.utils.SerJavaSipMessageType;)Lcom.covergence.ws.callouts.SessionConfigType;(Unknown Source)

      at com.covergence.soa.ws.server.CallOutsImpl.getSessionConfigType(CallOutsImpl.java:46)

      at com.covergence.soa.ws.server.CallOutsImplBase.getSessionPolicy(CallOutsImplBase.java:238)

      at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)

      at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)

      at weblogic.wsee.jaxws.WLSInvoker.invoke(WLSInvoker.java:50)

      at weblogic.wsee.jaxws.WLSInvoker.invoke(WLSInvoker.java:42)

      at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:247)

      at com.sun.xml.ws.server.sei.SEIInvokerPipe.process(SEIInvokerPipe.java:97)

      at weblogic.wsee.jaxws.MonitoringPipe.process(MonitoringPipe.java:98)

      at com.sun.xml.ws.protocol.soap.ServerMUPipe.process(ServerMUPipe.java:62)

      at com.sun.xml.ws.server.WSEndpointImpl$1.process(WSEndpointImpl.java:139)

      at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:153)

      at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:235)

      at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:97)

      at weblogic.wsee.jaxws.HttpServletAdapter.post(HttpServletAdapter.java:36)

      at weblogic.wsee.jaxws.JAXWSServlet.doPost(JAXWSServlet.java:218)

      at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)

      at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)

      at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:226)

      at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:124)

      at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:283)

      at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)

      at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3370)

      at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)

      at weblogic.security.service.SecurityManager.runAs(Lweblogic.security.acl.internal.AuthenticatedSubject;Lweblogic.security.acl.internal.AuthenticatedSubject;Ljava.security.PrivilegedAction;)Ljava.lang.Object;(Unknown Source)

      at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2117)

      at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2023)

      1. jira462.patch.1.txt
        6 kB
        Pinaki Poddar
      2. PObject.java
        0.5 kB
        Pinaki Poddar
      3. TestOptimisticException.java
        2 kB
        Pinaki Poddar

        Issue Links

          Activity

          Hide
          Pinaki Poddar added a comment -

          An optimistic violation often manifests as a SQLException during implicit or explicit flush/commit operation.
          As this SQL exception bubbles up the stack of OpenJPA layers, the exception gets translated with the original exception being nested within.
          The OpenJPA facade translates an exception to javax.persistence.OptimisticLockException for the user application if the lower layer
          (i.e. spec-agnostic OpenJPA kernel) raises or translates original SQLException to a org.apache.openjpa.util.OptimisticException.
          If the context is not sufficient to translate the exception to org.apache.openjpa.util.OptimisticException, it gets translated to
          org.apache.openjpa.util.StoreException which is the generic type from all exceptions raised by the underlying datastore (which is JDBC datastore in this case).

          The attached patch addresses this issue by narrowing down the original SQLException to a specific subtype of StoreException based on the SQLState carried by the original SQLException.
          As a result, the JPA-facade layer can translate the exception to a org.apache.opejpa.persistence.OptimisticLockException which is derived from intended javax.persistence.OptimisticLockException.
          But this exception can get nested further up the exception translation chain before it reaches the user application.

          So, if an application wants to detect whether the exception is caused by optimistic consistency violation, one way to do it is

          boolean isExpectedException(Throwable t, Class expected)

          { if (t == null) return false; if (expected.isAssignableFrom(t.getClass())) return true; if (t.getCause()==t) return false; return isExpectedException(t.getCause(), expected); }

          and call it from the application code as:

          try

          { // do some JPA stuff; }

          catch (Throwable t) {
          if (isExpectedException(t, javax.persistence.OptimisticLockException.class)

          { // do some smart thing to retry/recover else // rethrow }

          Notes on the patch:
          1. The existing DBDictionary.newStoreException() method did detect referential integrity violations by analyzing java.sql.SQLException.getSQLState().
          2. This patch generalizes the same logic to other violations such as locking or duplicate key.
          3. The only context available to narrow down the cause is java.sql.SQLException.getSQLState() – which is ideally be same across JDBC drivers and different databases.
          But ideals are seldom met. So a new method
          public String[] DBDictionary.getKnownErrorCodes(int storeExceptionType)
          is introduced, that can be overwritten by database-specific DBDictionary derivations.
          4. The patch only supplies two error codes for referential integrity and locking errors.
          ===============================================================================================
          If someone can point me to an enumeration of these (supposedly database-neutral) error codes returned by
          SQLException.getSQLState() that will be of great help.
          ===============================================================================================

          Show
          Pinaki Poddar added a comment - An optimistic violation often manifests as a SQLException during implicit or explicit flush/commit operation. As this SQL exception bubbles up the stack of OpenJPA layers, the exception gets translated with the original exception being nested within. The OpenJPA facade translates an exception to javax.persistence.OptimisticLockException for the user application if the lower layer (i.e. spec-agnostic OpenJPA kernel) raises or translates original SQLException to a org.apache.openjpa.util.OptimisticException. If the context is not sufficient to translate the exception to org.apache.openjpa.util.OptimisticException, it gets translated to org.apache.openjpa.util.StoreException which is the generic type from all exceptions raised by the underlying datastore (which is JDBC datastore in this case). The attached patch addresses this issue by narrowing down the original SQLException to a specific subtype of StoreException based on the SQLState carried by the original SQLException. As a result, the JPA-facade layer can translate the exception to a org.apache.opejpa.persistence.OptimisticLockException which is derived from intended javax.persistence.OptimisticLockException. But this exception can get nested further up the exception translation chain before it reaches the user application. So, if an application wants to detect whether the exception is caused by optimistic consistency violation, one way to do it is boolean isExpectedException(Throwable t, Class expected) { if (t == null) return false; if (expected.isAssignableFrom(t.getClass())) return true; if (t.getCause()==t) return false; return isExpectedException(t.getCause(), expected); } and call it from the application code as: try { // do some JPA stuff; } catch (Throwable t) { if (isExpectedException(t, javax.persistence.OptimisticLockException.class) { // do some smart thing to retry/recover else // rethrow } Notes on the patch: 1. The existing DBDictionary.newStoreException() method did detect referential integrity violations by analyzing java.sql.SQLException.getSQLState(). 2. This patch generalizes the same logic to other violations such as locking or duplicate key. 3. The only context available to narrow down the cause is java.sql.SQLException.getSQLState() – which is ideally be same across JDBC drivers and different databases. But ideals are seldom met. So a new method public String[] DBDictionary.getKnownErrorCodes(int storeExceptionType) is introduced, that can be overwritten by database-specific DBDictionary derivations. 4. The patch only supplies two error codes for referential integrity and locking errors. =============================================================================================== If someone can point me to an enumeration of these (supposedly database-neutral) error codes returned by SQLException.getSQLState() that will be of great help. ===============================================================================================
          Hide
          Pinaki Poddar added a comment -

          This patch narrows down StoreException by SQLException.getSQLState().
          This narrowing down helps the upper layers to translate the exception to more specific errors for the user.

          See the previous comment for further details.

          Show
          Pinaki Poddar added a comment - This patch narrows down StoreException by SQLException.getSQLState(). This narrowing down helps the upper layers to translate the exception to more specific errors for the user. See the previous comment for further details.
          Hide
          Pinaki Poddar added a comment -

          a test case to verify exact type of exception being thrown for optimistic consistency violation.

          Show
          Pinaki Poddar added a comment - a test case to verify exact type of exception being thrown for optimistic consistency violation.
          Hide
          Patrick Linskey added a comment -

          Based on the description, it sounds like this patch might still allow internal Exception types to make it out of the OpenJPA tier unwrapped. It would seem that we should always be re-wrapping with a facade-specific exception, even if the particular exception type is not being properly handled. Is that covered in the patches at this time?

          Show
          Patrick Linskey added a comment - Based on the description, it sounds like this patch might still allow internal Exception types to make it out of the OpenJPA tier unwrapped. It would seem that we should always be re-wrapping with a facade-specific exception, even if the particular exception type is not being properly handled. Is that covered in the patches at this time?
          Hide
          Pinaki Poddar added a comment -

          This patch only narrows down StoreException to more specific subtypes. So that the upper layers can translate/rewrap the exception in a more targeted exception for the user facacde.
          This patch does not cover all internal exception types.
          The narrowing down is based on SQLState that the core SQLException carries with it. Hence only specific SQL errors can be narrowed within the available context/scope.
          The user-visible exception translation will continue to happen through the layers above as The invocation context can only determine the correct translation.

          Specifically, a SQL lock time out exception is now being narrowed to a internal LockException as opposed to a generic StoreException. That helps JPA facade (PersistenceExceptions) to
          translate it to OptimisticLockException rather than a more generic PersistenceException.

          SQLExceptions are being specialized further in JDBC 4.0 and SQLExceptions.narrow() that has been introduced in this patch can be a place for more improved logic.

          Show
          Pinaki Poddar added a comment - This patch only narrows down StoreException to more specific subtypes. So that the upper layers can translate/rewrap the exception in a more targeted exception for the user facacde. This patch does not cover all internal exception types. The narrowing down is based on SQLState that the core SQLException carries with it. Hence only specific SQL errors can be narrowed within the available context/scope. The user-visible exception translation will continue to happen through the layers above as The invocation context can only determine the correct translation. Specifically, a SQL lock time out exception is now being narrowed to a internal LockException as opposed to a generic StoreException. That helps JPA facade (PersistenceExceptions) to translate it to OptimisticLockException rather than a more generic PersistenceException. SQLExceptions are being specialized further in JDBC 4.0 and SQLExceptions.narrow() that has been introduced in this patch can be a place for more improved logic.

            People

            • Assignee:
              Pinaki Poddar
              Reporter:
              Ajay Aggarwal
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development