8 Replies Latest reply on Dec 7, 2005 5:19 PM by adrian.brock

    Handling exceptions on commit

      Using CMT with an MDB. The MDB calls several methods on session beans. On commit an exception happens (because of a constraint violation in the DB, or a dirty read or similar). Those exceptions are interesting to me and I want to react on them. Is there a way I can get to them without using BMT?

        • 1. Re: Handling exceptions on commit
          genman


          There's no particular J2EE pattern for this, though if you want to commit the transaction in parts, I suggest you split the source message into multiple messages for each TX part and among multiple MDBs.

          BMT might not work that well, as you can't control the commit of the MDB message as part of the BMT.

          You also might use the "Redelivered" flag to see if the first attempt processing failed.

          • 2. Re: Handling exceptions on commit

            Well, it's not exactly committing a transaction in parts. But I might want to send a response to a message even if the commit fails. And I need the exact exception why the commit failed.

            • 3. Re: Handling exceptions on commit
              genman


              I hate to give this response, but I don't see anything that allows you to handle the failed TX path. But anything really is possible if you take a look at the source code and write your own code to do what you want.

              Address your request in the development forum.

              You need to state more precisely how the feature may work in general and how it may be configured.

              • 4. Re: Handling exceptions on commit

                It would require a plugin to the server session pool since this handles the commit
                for MDBs.
                e.g. a bit like the retry processing for other ejbs, but you obviously can't retry
                for an MDB because the failed commit nacks the message back into the jms destination.

                • 5. Re: Handling exceptions on commit

                  Well, easiest for me would be a callback method on the MDB like

                  void onCommitException(Throwable t);

                  (How to register it, is another issue). But as you say the commit is issued by the pool I am not sure if that is still possible at that point or if the instance has already been dismissed.

                  Today it is a real problem when the MDB is the one who commits a transaction. All the real interesting exceptions happen on commit (because DB constraints fire then mostly). With CMT I loose the exception. And with BMT I can not push the message back to the queue: http://jira.jboss.com/jira/browse/EJBTHREE-351
                  I am sort of helpless.

                  • 6. Re: Handling exceptions on commit

                     

                    "oglueck" wrote:
                    Well, easiest for me would be a callback method on the MDB like

                    void onCommitException(Throwable t);

                    (How to register it, is another issue). But as you say the commit is issued by the pool I am not sure if that is still possible at that point or if the instance has already been dismissed.


                    Correct, the MDB instance that originally processed the message is probably doing
                    something else by the time the commit fails.


                    Today it is a real problem when the MDB is the one who commits a transaction. All the real interesting exceptions happen on commit (because DB constraints fire then mostly). With CMT I loose the exception.


                    The code you want to change is in StdServerSession's run()
                     catch (Exception e)
                     {
                     log.error("session failed to run; setting rollback only", e);
                    
                     if (useLocalTX)
                     {
                     // Use JBossMQ One Phase Commit to commit the TX
                     localRollbackFlag = true;
                     }
                     else
                     {
                     // Mark for tollback TX via TM
                     try
                     {
                     // The transaction will be rolledback in the finally
                     if (trace)
                     log.trace("Using TM to mark TX for rollback.");
                     trans.setRollbackOnly();
                     }
                     catch (Exception x)
                     {
                     log.error("failed to set rollback only", x);
                     }
                     }
                    
                     }
                     finally
                     {
                     try
                     {
                     if (useLocalTX)
                     {
                     if (localRollbackFlag == true)
                     {
                     if (trace)
                     log.trace("Using optimized 1p commit to rollback TX.");
                    
                     XAResource res = xaSession.getXAResource();
                     res.end(localXid, XAResource.TMSUCCESS);
                     res.rollback(localXid);
                    
                     }
                     else
                     {
                     if (trace)
                     log.trace("Using optimized 1p commit to commit TX.");
                    
                     XAResource res = xaSession.getXAResource();
                     res.end(localXid, XAResource.TMSUCCESS);
                     res.commit(localXid, true);
                     }
                     }
                     else
                     {
                     // Use the TM to commit the Tx (assert the correct association)
                     Transaction currentTx = tm.getTransaction();
                     if (trans.equals(currentTx) == false)
                     throw new IllegalStateException("Wrong tx association: expected " + trans + " was " + currentTx);
                    
                     // Marked rollback
                     if (trans.getStatus() == Status.STATUS_MARKED_ROLLBACK)
                     {
                     if (trace)
                     log.trace("Rolling back JMS transaction");
                     // actually roll it back
                     tm.rollback();
                    
                     // NO XASession? then manually rollback.
                     // This is not so good but
                     // it's the best we can do if we have no XASession.
                     if (xaSession == null && serverSessionPool.isTransacted())
                     {
                     session.rollback();
                     }
                     }
                     else if (trans.getStatus() == Status.STATUS_ACTIVE)
                     {
                     // Commit tx
                     // This will happen if
                     // a) everything goes well
                     // b) app. exception was thrown
                     if (trace)
                     log.trace("Commiting the JMS transaction");
                     tm.commit();
                    
                     // NO XASession? then manually commit. This is not so good but
                     // it's the best we can do if we have no XASession.
                     if (xaSession == null && serverSessionPool.isTransacted())
                     {
                     session.commit();
                     }
                     }
                     }
                     }
                     catch (Exception e)
                     {
                     log.error("failed to commit/rollback", e);
                     }
                     }
                     if (trace)
                     log.trace("onMessage done");
                    



                    And with BMT I can not push the message back to the queue: http://jira.jboss.com/jira/browse/EJBTHREE-351
                    I am sort of helpless.


                    You also have control if you have JCA1.5 resource adapter for JMS
                    that does transaction inflow. i.e. you start and commit the transaction
                    from the "activation".

                    • 7. Re: Handling exceptions on commit

                      Adrian, I'm afraid you lost me here. I guess I am out of luck with CMT. The JCA inflow sounds interesting. I saw the documentation on that and I'm sure I can make JBoss use JCA inflow for my MDBs. But where do I go from there? Where do I control the transaction then?

                      • 8. Re: Handling exceptions on commit

                        You don't with CMT and EJB2.0,
                        unless you want to get into non-portable behaviour,
                        read the FAQ