13 Replies Latest reply on Jul 12, 2006 7:20 PM by jnorris10

    Help w/ TransactionAttributeType.REQUIRES_NEW

    dabramov

      I have some test code that exercises REQUIRES_NEW, but looking at the TransactionManager logs, I don't see a new tx being created when that method executes. I'm using JBoss 4.0.4 GA and the EJB3 RC7 FD download.

      The players are two SLSBs TxTestBean. I'm calling the toplevel() method from a simple jsp that just looks up the bean and makes the call.

      Here's the code for TxTestBean:

      @Stateless
      public class TxTestBean implements TxTestLocal {
      
       public static Logger log = Logger.getLogger( "TxTest" );
      
       /* (non-Javadoc)
       * @see com.sonus.test.TxTestLocal#toplevel()
       */
       public void toplevel() {
       log.info ("beginning toplevel test w/ ejb3");
       part1();
       part3();
       log.info ("leaving toplevel test w/ ejb3");
       }
      
       /* (non-Javadoc)
       * @see com.sonus.test.TxTestLocal#part1()
       */
       public void part1() {
       try {
       log.info( "part 1: about to call list nodes");
      
       Context context = ContextFactory.getLocalInitialContext();
       NodeAccess nodeAccess = (NodeAccess) context.lookup( "NodeAccessBean/local" );
       List nodes = nodeAccess.listNodes();
       log.info( "part 1: list nodes done" );
       part2();
       } catch( Exception e ) {
       log.error ( "exception in part1: " + e);
       }
       }
      
      
       /* (non-Javadoc)
       * @see com.sonus.test.TxTestLocal#part2()
       */
       public void part2() {
       try {
       log.info( "part 2: about to call list nodes");
       Context context = ContextFactory.getLocalInitialContext();
       NodeAccess nodeAccess = (NodeAccess) context.lookup( "NodeAccessBean/local" );
       List nodes = nodeAccess.listNodes();
       log.info( "part 2: list nodes done" );
       } catch( Exception e ) {
       log.error ( "exception in part2: " + e);
       }
       }
      
       /* (non-Javadoc)
       * @see com.sonus.test.TxTestLocal#part3()
       */
       @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
       public void part3() {
       try {
       log.info( "part 3: about to call list nodes");
       Context context = ContextFactory.getLocalInitialContext();
       NodeAccess nodeAccess = (NodeAccess) context.lookup( "NodeAccessBean/local" );
       List nodes = nodeAccess.listNodes();
       log.info( "part 3: list nodes done" );
       } catch( Exception e ) {
       log.error ( "exception in part3 :" + e);
       }
       }
      
      }



      So I'd expect to see a log message indicating a new tx starting right before my log message "part 3: about to call list nodes" (which happens at time 2006-06-05 14:34:08,522).

      Here's the log - I see only a single tx started and committed. I'm not sure how to proceed.

      2006-06-05 14:34:08,459 TRACE [org.jboss.tm.TransactionImpl] Created new instance for tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20]
      2006-06-05 14:34:08,459 TRACE [org.jboss.tm.TxManager] began tx: TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20]
      2006-06-05 14:34:08,459 INFO [TxTest] beginning toplevel test w/ ejb3
      2006-06-05 14:34:08,459 INFO [TxTest] part 1: about to call list nodes
      2006-06-05 14:34:08,459 DEBUG [com.sonus.common.dao.node.NodeAccessBean] NodeDAO: listNodes(true)
      2006-06-05 14:34:08,459 TRACE [org.jboss.tm.TransactionImpl] registerSynchronization(): Entered, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20] status=STATUS_ACTIVE
      2006-06-05 14:34:08,459 TRACE [org.jboss.tm.TransactionImpl] registerSynchronization(): Entered, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20] status=STATUS_ACTIVE
      2006-06-05 14:34:08,475 TRACE [org.jboss.tm.TransactionImpl] registerSynchronization(): Entered, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20] status=STATUS_ACTIVE
      2006-06-05 14:34:08,475 TRACE [org.jboss.tm.TransactionImpl] enlistResource(): Entered, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20] status=STATUS_ACTIVE xaRes=org.jboss.resource.connectionmanager.TxConnectionManager$LocalXAResource@720f6c
      2006-06-05 14:34:08,475 TRACE [org.jboss.tm.TransactionImpl] startResource(XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=1, localId=20]) entered: org.jboss.resource.connectionmanager.TxConnectionManager$LocalXAResource@720f6c flags=0
      2006-06-05 14:34:08,475 TRACE [org.jboss.tm.TransactionImpl] startResource(XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=1, localId=20]) leaving: org.jboss.resource.connectionmanager.TxConnectionManager$LocalXAResource@720f6c flags=0
      2006-06-05 14:34:08,490 TRACE [org.jboss.tm.TxManager] tx timeout is now: 300s
      2006-06-05 14:34:08,490 INFO [TxTest] part 1: list nodes done
      2006-06-05 14:34:08,490 INFO [TxTest] part 2: about to call list nodes
      2006-06-05 14:34:08,490 DEBUG [com.sonus.common.dao.node.NodeAccessBean] NodeDAO: listNodes(true)
      2006-06-05 14:34:08,522 TRACE [org.jboss.tm.TxManager] tx timeout is now: 300s
      2006-06-05 14:34:08,522 INFO [TxTest] part 2: list nodes done
      2006-06-05 14:34:08,522 INFO [TxTest] part 3: about to call list nodes
      2006-06-05 14:34:08,522 DEBUG [com.sonus.common.dao.node.NodeAccessBean] NodeDAO: listNodes(true)
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TxManager] tx timeout is now: 300s
      2006-06-05 14:34:08,553 INFO [TxTest] part 3: list nodes done
      2006-06-05 14:34:08,553 INFO [TxTest] leaving toplevel test w/ ejb3
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] Committing, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20], status=STATUS_ACTIVE
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] calling sync 2, org.jboss.resource.connectionmanager.TransactionSynchronizer@fbb5f5 tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20]
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] Before completion done, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20], status=STATUS_ACTIVE
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] endresources(org.jboss.resource.connectionmanager.TxConnectionManager$LocalXAResource@720f6c): state=1
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] endResource(XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=1, localId=20]) entered: org.jboss.resource.connectionmanager.TxConnectionManager$LocalXAResource@720f6c flag=67108864
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] endResource(XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=1, localId=20]) leaving: org.jboss.resource.connectionmanager.TxConnectionManager$LocalXAResource@720f6c flag=67108864
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] One phase commit TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20]: One resource.
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] Committing resource org.jboss.resource.connectionmanager.TxConnectionManager$LocalXAResource@720f6c state=3
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TransactionImpl] Committed OK, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20]
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TxManager] commited tx: TransactionImpl:XidImpl[FormatId=257, GlobalId=dabramovich/20, BranchQual=, localId=20]
      2006-06-05 14:34:08,553 TRACE [org.jboss.tm.TxManager] tx timeout is now: 300s
      



        • 1. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
          dabramov

          I ran my test in the debugger. When the TxTestBean is deployed I see the TxInterceptorFactory create a new instance of a TxInterceptor.RequiresNew for the part3() method. However when the test is executed, a breakpoint set on TxInterceptor.RequiresNew.invoke() never gets hit.

          • 2. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
            dbudworth

            we found that the TransactionAttribute annotation gets ignored when calling other methods in from a session bean.

            ie:

            public void doSomething() { // this is the method called from the client
             doSomethingInNewTx();
            }
            
            @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
            public void doSomethingInNewTx(){
             ...
            }
            
            


            But calling doSomethingInNewTx() from the client would actually create the tx. (guess you have to be going through the proxy to get the annotation to do it's thing)

            We ended up turning on full blown LoadTimeWeaving AOP and using @Tx for this situation.


            • 3. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
              sateh

               

              "dbudworth" wrote:
              We ended up turning on full blown LoadTimeWeaving AOP and using @Tx for this situation.


              Uhhh. Does that mean that transaction management in EJB3 is completely broken?

              S.


              • 4. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                sateh

                 

                "dbudworth" wrote:
                We ended up turning on full blown LoadTimeWeaving AOP and using @Tx for this situation.


                David, did you simply let your @Tx annotation do an 'em.joinTransaction()' as if the persistence context was application managed?

                S.


                • 5. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                  bill.burke

                   

                  "dbudworth" wrote:
                  we found that the TransactionAttribute annotation gets ignored when calling other methods in from a session bean.

                  ie:
                  public void doSomething() { // this is the method called from the client
                   doSomethingInNewTx();
                  }
                  
                  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
                  public void doSomethingInNewTx(){
                   ...
                  }
                  
                  


                  But calling doSomethingInNewTx() from the client would actually create the tx. (guess you have to be going through the proxy to get the annotation to do it's thing)

                  We ended up turning on full blown LoadTimeWeaving AOP and using @Tx for this situation.


                  This is the expected behavior and what is required by the specification. If you make a this pointer method call, it is a regular Java invocation. You can get an "EJB this pointer" through SessionContext method getBusinessObject (or whatever the name is, i forget).

                  Bill

                  • 6. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                    sateh

                     

                    "bill.burke@jboss.com" wrote:
                    "dbudworth" wrote:
                    This is the expected behavior and what is required by the specification. If you make a this pointer method call, it is a regular Java invocation. You can get an "EJB this pointer" through SessionContext method getBusinessObject (or whatever the name is, i forget).


                    This sounds rather silly/complicated. Maybe it is time for another JBoss-specific extension to the spec to make this (a whole lot) easier?

                    S.


                    • 7. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                      sateh

                      Sorry for the badly quoted message :-)

                      S.

                      • 8. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                        bill.burke

                        Like dbudworth said, you can use the AOP stuff if you need to.

                        • 9. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                          dbudworth

                          I didn't even realize you could get the proxy object from the context, might have been a better solution.

                          The @Tx stuff works, and I've been using the JBoss AOP stuff for a few years in production, so I don't really worry about that (aside from the 1/3 increase in deploy time, but that's no biggie)

                          As for adding a jboss specific hack, doing that would kind of suck, think about all the places you do things like:

                          Logger log = Logger.getLogger(getClass());
                          


                          You'd end up with a funky subclass in your log files, since the only way to make self references adhear to the annotations would be to generate a subclass or use LoadTimeWeaving. (I believe)

                          • 10. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                            dabramov

                            Thanks for the discussion - it's been very helpful coming up to speed on this...

                            In the case of a same EJB call, is there any difference between doing

                            A)
                            @EJB SameEJB same;

                            vs:

                            B)
                            @Resource SessionContext ctx;
                            ...
                            SameEJB same = ctx.getBusinessObject();

                            I'm guessing in B) you get a local if you're working w/ a local intf, vice versa. How does @EJB deal w/ local deal w/ that?

                            -Dan



                            • 11. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                              dbudworth

                              Not having looked at the actual implementation for injection, I'd guess that

                              @EJB
                              private SameEJB same;
                              


                              I would expect that it doesn't give you a self referencing proxy.

                              It probably at best give an error that it's not legal
                              At worst give you infinite recursion as it would be creating new instances to inject and new instances for those injected beans to have more injections, etc.


                              • 12. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                                dabramov

                                I tried calling SessionContext.getBusinessObject() and also SessionContext.getInvokedBusinessInterface() from a SLSB method. However, I get an IllegalStateException - "Not Implemented".

                                (aside: any reason to not to call getInvokedBusinessInterface() vs getBusinessObject()? It seems simpler to not have to pass in the interface)

                                @Stateless
                                public class FooBean implements FooLocal {
                                
                                 @Resource SessionContext ctx;
                                 public static Logger log = Logger.getLogger( "FooBean" );
                                
                                public void doSomething() {
                                 log.info( "doSomething: enter");
                                
                                 //Foo thisFoo = (Foo)ctx.getBusinessObject( FooLocal.class );
                                 Foo thisFoo = (Foo)ctx.getInvokedBusinessInterface();
                                
                                 log.info( "got business interface: " + thisFoo );
                                 }
                                }

                                I see the enter log message, but nothing after.

                                I guess there are two choices - either I'm not using this correctly or it's really not implemented. Bill - should this work w/ RC7? If not, would we expect this for a GA release of EJB3?

                                As to using the JBoss AOP @Tx mixed w/ EJB3 syntax, I don't think I can sell that to our group. It seems messy to adopt EJB3 only to sprinkle in a proprietary syntax to get the desired to our group.

                                Thanks,
                                -Dan

                                • 13. Re: Help w/ TransactionAttributeType.REQUIRES_NEW
                                  jnorris10

                                   

                                  "dabramov" wrote:
                                  I tried calling SessionContext.getBusinessObject() and also SessionContext.getInvokedBusinessInterface() from a SLSB method. However, I get an IllegalStateException - "Not Implemented".


                                  Yeah, I have that problem too. However, I see that it's now implemented in source control: http://fisheye.jboss.com/viewrep/JBoss/jboss-ejb3/src/main/org/jboss/ejb3/BaseSessionContext.java