9 Replies Latest reply on Jan 5, 2010 10:24 AM by gonzalad

    BypassInterceptors and RollbackInterceptor

    gonzalad Apprentice

      Hello,


      I've noticed after annotating all my seam components with @BypassInterceptors [1], I gain 20% of execution time.


      The problem is that whenever my seam component (javabean) generates an unchecked exception), the transaction isn't rollbacked anymore (this was the purpose of RollbackInterceptor).


      So I have following options :



      1. make sure to call in my actions Transaction.instance().setRollbackOnly() whenever an unchecked exception is thrown (ugly !!)

      2. replace RollbackInterceptor with another generic piece of code.




      I've tried to replace RollbackInterceptor with a custom filter but failed (SeamPhaseListener has already committed the transaction).
      Does anyone has a better idea ?


      Anyway, I'm asking myself, how can BypassInterceptors be usefull if it disables transaction handling ?


      Thanks very much for your help !



      [1] @BypassInterceptors described here :
      performance.html.

        • 1. Re: BypassInterceptors and RollbackInterceptor
          gonzalad Apprentice

          I think we're screwed here :


          I've tried implementing rollback with @BypassInterceptors in :



          1. Servlet Filter : doesn't work since Seam has already committed the tx - see SeamPhaseListener.handleTransactionsAfterPhase().

          2. JSF PhaseListener : We don't have access to the generated exception. For instance, if we look at JSF 1.2 Sun RI exception handling in com.sun.faces.lifecycle.Phase.doPhase - we won't have access to ex local var :




                  try {
                      if (!shouldSkip(context)) {
                          execute(context);
                      }
                  } catch (Exception e) {
                       if (LOGGER.isLoggable(Level.SEVERE)) {
                          LOGGER.log(Level.SEVERE,
                               "jsf.lifecycle.phase.exception",
                               new Object[]{
                                    this.getId().toString(),
                                    ((context.getViewRoot() != null) ? context.getViewRoot().getViewId() : ""),
                                    event});
                      }
          
                      ex = e;
                  } finally {
                      handleAfterPhase(context, listeners, event);



          So, we have the following options :



          • use @BypassInterceptors, and handle tx rollback in your Seam component code



          public void myMethod() {
            try {
              ...
            } catch (SomeException err) {
              Transaction.instance().setRollbackOnly();
              throw err;
            }
          }




          • or don't use @BypassInterceptors.




          I hope I'm missing sthing, but for the moment, @BypassInterceptors cannot be used while this pb remains.



          • 2. Re: BypassInterceptors and RollbackInterceptor
            Nikolay Elenkov Master

            Well, you disabled all of Seam interceptors, so you loose some of Seam's features. That is not really a problem, that's the way it works.


            You can:



            1. Use EJB's, they handle rollback for you

            2. if you need POJO transaction support, use Spring

            3. write your own interceptor and apply only that



            HTH

            • 3. Re: BypassInterceptors and RollbackInterceptor
              gonzalad Apprentice

              Thanks,


              I've made some more tests to know a bit about the Cpu cost of Seam interceptors.


              A simple JSE calling a method on a Seam conversation Scoped components (my main class extends SeamTest).


              The test calls the seam component method in a loop (100000 iterations), and I do 4 times this test.


              Computer used : Pentium 4 CPU 3GHz
              JVM : IBM JVM 1.5.0 SR6b


              No tx management (transaction-management-enabled=false in components.xml - I was having trouble making it work with txManagement enabled).




              Test 1 - Interceptors activated - normal case
              Cost : 0.08 ms / call
              
              Test 2 - Action annotated with @BypassInterceptors
              Cost : 0,00056 ms / call
              Gain vs Test 1 : 143
              
              Test 3 - Just declaring RollbackInterceptor in components.xml
              Cost : 0,01027 ms / call
              Gain vs Test 1 : 8
              
              Test 4 - Interceptors activated, and I added a @In attribute in my seam component
              Cost : 0.14 ms / call
              Cost vs Test 1 : *2
              
              Test 5 - like 4 but with 2 @In
              Cost : 0.17 ms / call
              So ~42000 par @In
              
              Test 6 - same as 1 but with Sun JRE 1.6.0_14-b08
              Cost : 0.068 ms / call




              • 4. Re: BypassInterceptors and RollbackInterceptor
                gonzalad Apprentice

                And finally, I've made some more tests on a seam demo app.


                Those tests are unit test (1 user connected) so, they're not really accurate, but I don't have more time to do some load tests.


                Time is measured with a custom filter.


                I measure each page 8 times and discards the 2 worst results.




                a. Interceptors activated - normal case
                    495 ms
                b. RollbackInterceptor declared in components.xml
                    406 ms
                    Gain : 22%
                c. BypassInterceptor on all my actions.
                    398 ms
                    Gain : 24%
                d. RollbackInterceptor declared in components.xml+ BypassInterceptor on all my actions
                    367 ms
                    Gain : 35%



                • 5. Re: BypassInterceptors and RollbackInterceptor
                  gonzalad Apprentice

                  Since we're using Spring with Seam, we'll :



                  1. activate transaction demarcation on our spring services (Spring AoP)

                  2. in components.xml : declare only RollbackInterceptor.

                  3. annotate all our seam components with BypassInterceptor.



                  Sample components.xml fragment :



                       <core:init debug="@debug@">
                            <core:interceptors>
                                  <value>org.jboss.seam.transaction.RollbackInterceptor</value>
                            </core:interceptors>
                       </core:init>



                  Sample spring configuration :



                      <aop:config>
                            <aop:pointcut id="businessServicePointcut" expression="execution(* *..service.*Manager.*(..))" />
                            <aop:advisor id="txAdvisor" advice-ref="txAdvice" pointcut-ref="businessServicePointcut"/>      
                      </aop:config>
                  
                      <tx:advice id="txAdvice">
                          <tx:attributes>
                               <tx:method name="*" read-only="true"  propagation="REQUIRED"/>
                          </tx:attributes>
                      </tx:advice>
                  



                  Sample Seam component :



                  @Name("rechercherChargeClienteleAction")
                  @Scope(ScopeType.CONVERSATION)
                  @BypassInterceptors
                  @SuppressWarnings("serial")
                  public class RechercherChargeClienteleAction extends NumberedPagedListAction<ChargeClientele> {
                       private String nom;
                       private String user;
                  
                       @Override
                       protected PageData<ChargeClientele> loadPage(int aFirstResult, int aResultCount) {
                            ListeResultat<ChargeClientele> lListe =
                                      getChargeClienteleManager().findByNameAndUser(getNom(), getUser(), aFirstResult, aResultCount);
                            return getPageData(lListe.getListe(), lListe.getNbTotalEnregistrements());
                       }
                  
                       public String getNom() {
                            return nom;
                       }
                  
                       public void setUser(String aUser) {
                            user = aUser;
                       }
                  
                       public String getUser() {
                            return user;
                       }
                  
                       public void setNom(String aNom) {
                            nom = aNom;
                       }
                  
                       public int getPageSize() {
                            return evaluateValueExpression("#{pageSettings.pageSize}", Integer.class);
                       }
                  
                       private IChargeClienteleManager getChargeClienteleManager() {
                            return evaluateValueExpression("#{chargeClienteleManager}", IChargeClienteleManager.class);
                       }
                  }




                  • 6. Re: BypassInterceptors and RollbackInterceptor
                    Nikolay Elenkov Master

                    Gonzalez Adrian wrote on Dec 29, 2009 17:02:


                    Since we're using Spring with Seam, we'll :


                    1. activate transaction demarcation on our spring services (Spring AoP)

                    2. in components.xml : declare only RollbackInterceptor.

                    3. annotate all our seam components with BypassInterceptor.





                    Do you really need the RollbackInterceptor? Doesn't Spring AOP handle rollback for you? AFAIK, the AOP proxy Spring creates should rollback the transaction if any RuntimeException is thrown. I have never used Spring with Seam, but I don't see why it shouldn't work.


                    • 7. Re: BypassInterceptors and RollbackInterceptor
                      gonzalad Apprentice

                      Do you really need the RollbackInterceptor? Doesn't Spring AOP handle rollback for you?

                      Yes Spring Aop handles rollback for my services (and so, I don't need RollbackInterceptor for my actions since they call a service).


                      In fact since I annotate all my seam components with @BypassInterceptors, no interceptor is applied on my components (seam doesn't even create a dynamic proxy !).


                      RollbackInterceptor is only used for seam native components (ie. theme, entityManager, ...) in order to optimize the call for those kind of components.


                      I think I could remove the RollbackInterceptor interceptor for seam native components, but I didn't tested it enough and fear any possible side effects.






                      • 8. Re: BypassInterceptors and RollbackInterceptor
                        Nikolay Elenkov Master

                        Gonzalez Adrian wrote on Dec 30, 2009 12:13:


                        In fact since I annotate all my seam components with @BypassInterceptors, no interceptor is applied on my components (seam doesn't even create a dynamic proxy !).

                        RollbackInterceptor is only used for seam native components (ie. theme, entityManager, ...) in order to optimize the call for those kind of components.



                        If that is the case, you are probably better off leaving the Seam interceptor chain as is. It will not be applied to your action classes anyway. You are aware that transactions are not the only thing handled with interceptors, right? Things like conversation management with @Begin/@End, ascynchronous methods, SFSB removal, events and security are also implemented with interceptors. If you are using neither of those, you are probably OK, but just a heads up.

                        • 9. Re: BypassInterceptors and RollbackInterceptor
                          gonzalad Apprentice

                          Thanks very much for you input Nikolay.





                          If that is the case, you are probably better off leaving the Seam interceptor chain as is. It will not be applied to your action classes anyway.

                          I've removed the Seam inteceptor chain in the components.xml (only leaving RollbackInterceptor), and it works for my demo application (196 xhtml page - so a relatively big demo app).


                          I would like to test it in a real application (checking performance benefits on adding / removing seam interceptor chain for seam native components), but I'm going out of time - pity.


                          Anyway, if one day I have problems I'll remember to add the interceptors back in components.xml ;)





                          You are aware that transactions are not the only thing handled with interceptors, right?

                          Yes, checked last week every interceptor to make sure I didn't used them (and more importantly that Seam doesn't rely on them).
                          To do it, I've just looked at the isInterceptorEnabled() method of each interceptor.


                          Here are my quick notes, if it can help someone, but you should better look at Seam interceptors code directly :



                          • org.jboss.seam.core.SynchronizationInterceptor : added on Session and Page components or components using @Synchronize.

                          • org.jboss.seam.async.AsynchronousInterceptor : added on components using @Asynchronous.

                          • org.jboss.seam.ejb.RemoveInterceptor : added on statefull ejb components.

                          • org.jboss.seam.persistence.HibernateSessionProxyInterceptor : added on statefull or stateless ejb components.

                          • org.jboss.seam.persistence.EntityManagerProxyInterceptor : added on statefull or stateless ejb components.

                          • org.jboss.seam.core.MethodContextInterceptor : usefull if you need access to Contexts.getMethodContext().

                          • org.jboss.seam.core.EventInterceptor : added on components using @RaiseEvent.

                          • org.jboss.seam.core.ConversationalInterceptor : added on components using @Conversational.

                          • org.jboss.seam.bpm.BusinessProcessInterceptor : added if jBPM jars are on your CLASSPATH. Usefulle if you use @StartTask, @EndTask, @Transition, @ResumeProcess annotations.

                          • org.jboss.seam.core.ConversationInterceptor : added if you use @Begin, @End, @StartTask, @BeginTask, @EndTask annotations.

                          • org.jboss.seam.core.BijectionInterceptor : added if you use @In, Out, @DataModelSelection, @RequestParameter, @DataModel annotations.

                          • org.jboss.seam.transaction.RollbackInterceptor : always activated marks current transaction to rollback when your seam components generated an unchecked exception (or exception annotated with @ApplicationException) : usefull for Seam javabean components.

                          • org.jboss.seam.transaction.TransactionInterceptor : added if the component is a javabean and if you use @Transactional.

                          • org.jboss.seam.webservice.WSSecurityInterceptor : if seam component annotated with @WebService and @Restrict.

                          • org.jboss.seam.security.SecurityInterceptor  : if seam component annotated with @Restrict (and without @WebService).



                          All in all, Seam interception management is efficient so that if seam detected at startup that an interceptor isn't needed for a component, it doesn't register it for this interceptor list, and the interceptor is never executed.