[GLASSFISH-19050] Glassfish swallows RuntimeException thrown in SynchronizationListener.beforeCompletion Created: 04/Sep/12  Updated: 07/Sep/12  Resolved: 07/Sep/12

Status: Resolved
Project: glassfish
Component/s: jts
Affects Version/s: 3.1.2, 4.0_b53
Fix Version/s: 4.0_b54

Type: Bug Priority: Major
Reporter: rgirsten Assignee: marina vatkina
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Glassfish 3.1.2.2, EclipseLink 2.3.2, Oracle Database Server 10.x or 11.x


Attachments: GZip Archive demo-proxy-auth-generic.tar.gz    

 Description   

I have created an example that demonstrates how to use the EclipseLink feature for
Oracle Database Server Proxy Authentication.
This feature uses database authentication and authorization to secure an application.

On Glassfish the original RuntimeException thrown in an EclipseLink exception handler is not piggybacked with the EJBException that the web client does receive from the failed session bean method call.

[#|2012-09-04T15:08:37.237+0200|WARNING|oracle-glassfish3.1.2|javax.enterprise.system.container.ejb.com.sun.ejb.containers|_ThreadID=39;_ThreadName=Thread-2;|javax.ejb.EJBException: Transaction aborted
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5142)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4901)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2045)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1994)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:89)
at $Proxy138.incrementAndReadValue(Unknown Source)
at oracle.support.web.BackingBean.incrementAndReadValue(BackingBean.java:46)
at org.apache.jsp.WEB_002dINF.jsp.write_jsp._jspService(write_jsp.java:97)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:111)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:411)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:473)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:377)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.ApplicationDispatcher.doInvoke(ApplicationDispatcher.java:809)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:671)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:505)
at org.apache.catalina.core.ApplicationDispatcher.doDispatch(ApplicationDispatcher.java:476)
at org.apache.catalina.core.ApplicationDispatcher.dispatch(ApplicationDispatcher.java:355)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:305)
at oracle.support.web.ControllerServlet.doPost(ControllerServlet.java:83)
at oracle.support.web.ControllerServlet.doGet(ControllerServlet.java:38)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at oracle.support.web.AuthenticationFilter.doFilter(AuthenticationFilter.java:61)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.transaction.RollbackException
at com.sun.jts.jta.TransactionManagerImpl.commit(TransactionManagerImpl.java:334)
at com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate.commitDistributedTransaction(JavaEETransactionManagerJTSDelegate.java:185)
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:861)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5136)
... 54 more

The README file of the example explains how to setup the example.
The problem can be reproduced by logging in as user "proxyuser" and password "test" and then clicking on "write".
The user "proxyuser" does not have privileges to write and therefore the JDBC driver will raise an exception that indicates that the privileges are not sufficient.

On WebLogic Server the example does display the correct error message of the root cause exception on the error page.



 Comments   
Comment by marina vatkina [ 05/Sep/12 ]

Can you try the scroll through the causes? I think we fixed it in the transaction code, but the EJB container only reports the actual transaction failure (javax.transaction.RollbackException), which is fine.

Comment by rgirsten [ 05/Sep/12 ]

The web client error page walks down the exception chain and prints the root exception error message.
The client gets EJBException with RollbackException. The root cause exception is missing.
I have tried to setup a simpler example which is simply violating a primary key constraint (unique key violation) in a transaction. But in this case the client will receive the complete chain of exceptions including the root cause.
So, somewhat the behavior of Glassfish seems to be inconsistent.
But without having the complete exception chain available, the client cannot handle or report an application exception.
It is pretty normal for persistence frameworks to plug into JTS by using a SynchronizationListener with the beforeCompletion and afterCompletion method. Also it is normal that such persistence framework does call setRollbackOnly if the processing of the beforeCompletion and afterCompletion actions was throwing an exception.

Comment by marina vatkina [ 07/Sep/12 ]

Can you attach a simple test case? Are you using XA or non-XA resources?

Comment by marina vatkina [ 07/Sep/12 ]

I have even a junit test case that verifies that an exception from beforeCompletion is attached to the RollbackException...

Comment by rgirsten [ 07/Sep/12 ]

I have tried to simplify my example but I was not able to.
My example uses an XA data source for the transaction that throws the RuntimeException in the eclipselink exception handler when it detects the
SQLSyntaxErrorException: ORA-01031: insufficient privileges
My RuntimeException does not piggyback the SQLSyntaxErrorException. But this is not the problem.
The problem is that the RollbackException does not piggyback the root cause exception which is the RuntimeException.
If I remove the eclipselink exception handler by putting the persistence.xml property in comments then I have the problem that the SQLSyntaxErrorException is not piggybacked by the RollbackException.
There is very little Glassfish specific that eclipselink is doing.
The SunAS/Glassfish support classes do provide Glassfish specific methods to lookup the TransactionManager and to unwrap JDBC connections.

Comment by marina vatkina [ 07/Sep/12 ]

I can reproduce it with 2 XA resources, but it's not clear yet why junit test doesn't catch it

Comment by marina vatkina [ 07/Sep/12 ]

Interestingly enough the unit test calls tx.commit() and that path attaches the cause. TM.commit() doesn't

Comment by marina vatkina [ 07/Sep/12 ]

Transaction.commit was fixed by http://java.net/jira/browse/GLASSFISH-11970

Comment by marina vatkina [ 07/Sep/12 ]

Fixed on trunk with rev 55854.

To make the same change in 3.1.2x line 333 in src/main/java/com/sun/jts/jta/TransactionManagerImpl.java should be changed as follows:

  • throw new RollbackException();
    + RollbackException rbe = new RollbackException();
    + Throwable cause = ex.getCause();
    + if (cause != null) { + rbe.initCause(cause); + }

    + throw rbe;

Generated at Sat Mar 07 05:14:01 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.