11 Replies Latest reply on Apr 20, 2010 8:59 PM by Adam Warski

    JSF lifecycle transactions feature

    Dan Allen Master

      I'd like to put our heads together (Adam, Lincoln and Dan) to get the code in Transaction for normal beans added to the Faces module. That will make you an official contributor to the Faces module, Adam. Are you ready? :)


      One change that I would like to make first is for this phase listener to be put under the managed phase listener infrastructure already present in the Faces module. That will turn the phase listener into a bean and it to receive injections. Most notably, we want to inject the JTA UserTransaction.


      @Inject UserTransaction utx;



      This is infinitely more portable than looking up in JNDI. And CDI affords us this injection through the following paragraph:



      A Java EE or embeddable EJB container must provide the following built-in beans, all of which have qualifier @Default:

      • a bean with bean type javax.transaction.UserTransaction, allowing injection of a reference to the JTA UserTransaction


      This may make you uneasy at first because it ties us to JTA, leaving servlet containers and SE out in the code. No worries, we are working on a transaction API-agnostic UserTransaction implementation in the persistence module. We'll change the injection point when it's ready. But that wrapper will extend from the UserTransaction API, so no need to change the method calls on the instance ;)


      I also want to give this feature an official name, JSF lifecycle transactions. In Seam 2, they were called Seam managed transactions and in Seam in Action, I called them global transactions. I think the term JSF lifecycle transactions is much more applicable and clear. Plus, we can match this in other frameworks (e.g., Wicket lifecycle transactions).

        • 1. Re: JSF lifecycle transactions feature
          Nikolay Elenkov Master

          Dan Allen wrote on Apr 15, 2010 01:40:


          I also want to give this feature an official name, JSF lifecycle transactions. In Seam 2, they were called Seam managed transactions and in Seam in Action, I called them global transactions. I think the term JSF lifecycle transactions is much more applicable and clear. Plus, we can match this in other frameworks (e.g., Wicket lifecycle transactions).


          Nice to have the option, but could you remind me again, why are lifecycle transactions a good idea? From my experience with Seam, those are do more harm than good. Just a few:



          • unintuitive: people expect the transaction to start and finish with their @Transactional methods. But that is not the case.

          • bad for performance: even if you use them not every page needs them (two per page in Seam 2!)

          • source of bugs: especially with ajax postbacks, some attached entity may end up persisted when you meant to ignore the changes. Just a small mistake in your xhtml is enough to trigger this. (we now about manual flush, but still)

          • not easy to use: if you want to do something after the transaction commits (send email, etc.) you have to resort to transactionSuccessful (undocumented!) event and the like



          I am not saying don't do it, I'm just saying that it's hugely overrated (as is the SMPC). I guess some people will still use it, so for the brand new JSF lifecycle transactions we need at least:



          • more control: disable/enable by view (what happened to pages.xml for Seam 3?)

          • some API to control those programmatically (if you use/write a Java-based navigation handler)

          • events that let you hook up easily in the transaction lifecyle




          • 2. Re: JSF lifecycle transactions feature
            Nicklas Karlsson Master

            Well, classically it has been the solution for the dreaded LazyLoadingException (and s:convertEntity but Lincoln mentioned it would be built into JSF 2 nowadays).


            But you are correct in that now is the time for everything that goes into Seam 3 to justify its existence so we just don't move it over because it's always been there

            • 3. Re: JSF lifecycle transactions feature
              Stuart Douglas Master

              I really want to be able to enable/disable them based on path e.g. disable them for /app/complexpages/ and enable them for /app/simplepages/


              Even better would be the ability to only enable the transaction in the render response phase, so you can have control of your transactions when executing your business code and not have to worry about LIE's when rendering the page.

              • 4. Re: JSF lifecycle transactions feature
                Adam Warski Master

                Hello,



                Nikolay Elenkov wrote on Apr 15, 2010 03:34:


                Nice to have the option, but could you remind me again, why are lifecycle transactions a good idea? From my experience with Seam, those are do more harm than good. Just a few:


                Several reasons :)


                First of all, suppose transactions are started and commited through an interceptor, which is bound with @Transactional. Most architectures have a service layer, which accesses the database (their method are transactional), and a view layer which only calls the services (their methods aren't transactional).


                Now, imagine a method in the view layer does the following:


                service1.method1()
                service2.method2()
                



                Because the transactions are started in an interceptor, there are actually 2 transactions here! And if the second method fails, the results of the first are already commited. In most situations, that's not what you would expect.


                One could argue of course that this should be encapsulated in one service method call, but I guess it's fairly common that's not the case.


                Secondly, I really don't want to put the annotation on all my service classes.




                • unintuitive: people expect the transaction to start and finish with their @Transactional methods. But that is not the case.





                That is, if you need @Transactional at all :). Also, @Transactional can be a mechanism to override the default, which in case of having JSF lifecycle txs is @Transactional(REQUIRED) for all methods.




                • bad for performance: even if you use them not every page needs them (two per page in Seam 2!)





                I don't think you should ever access database outside of a transaction. See Open Session in View article on Hibernate wiki.


                Also, if there's no transaction, you loose any isolation. You always get READ_COMMITED, even if the connection's isolation level is REPEATABLE_READ.




                • source of bugs: especially with ajax postbacks, some attached entity may end up persisted when you meant to ignore the changes. Just a small mistake in your xhtml is enough to trigger this. (we now about manual flush, but still)





                Well that's a general architecture of JPA and Hibernate. Whether it's good or bad is debatable, but it just works this way :).


                One thing to consider is making (if possible) the render-view-phase tx read-only. I think Hibernate 3.5 has this feature, but I'm not 100% sure how to use it.




                • not easy to use: if you want to do something after the transaction commits (send email, etc.) you have to resort to transactionSuccessful (undocumented!) event and the like





                Aren't transaction listeners in Weld documentation (here)? Besides, sending an e-mail is a perfect job for a MDB or some other asynchronous mechanism.



                I am not saying don't do it, I'm just saying that it's hugely overrated (as is the SMPC). I guess some people will still use it, so for the brand new JSF lifecycle transactions we need at least:


                • more control: disable/enable by view (what happened to pages.xml for Seam 3?)

                • some API to control those programmatically (if you use/write a Java-based navigation handler)

                • events that let you hook up easily in the transaction lifecyle





                Generally, I would vote for JSF lifecycle transactions enabled by default, but with an option to disable them, with 1 tx in a non-faces request and 2 txs in a postback.


                Adam

                • 5. Re: JSF lifecycle transactions feature
                  Adam Warski Master

                  Dan Allen wrote on Apr 15, 2010 01:40:


                  One change that I would like to make first is for this phase listener to be put under the managed phase listener infrastructure already present in the Faces module. That will turn the phase listener into a bean and it to receive injections.



                  One problem here is ordering. Right now I have two phase listeners: transaction and security (does a redirect if a page requires login). As the security listener is using the DB, it must come after the tx listener.


                  So I guess I'm not saying don't use the managed phase listener infrastructure, but change it to allow ordering :)



                  Most notably, we want to inject the JTA UserTransaction.

                  @Inject UserTransaction utx;





                  Sure, much better :)


                  Adam

                  • 6. Re: JSF lifecycle transactions feature
                    Nikolay Elenkov Master

                    Adam Warski wrote on Apr 15, 2010 12:24:



                    Nikolay Elenkov wrote on Apr 15, 2010 03:34:


                    Nice to have the option, but could you remind me again, why are lifecycle transactions a good idea? From my experience with Seam, those are do more harm than good. Just a few:


                    Several reasons :)
                    ...

                    service1.method1()
                    service2.method2()
                    



                    Because the transactions are started in an interceptor, there are actually 2 transactions here! And if the second method fails, the results of the first are already commited. In most situations, that's not what you would expect.



                    Well, if I wanted to have two separate transactions, I need to remember to use REQUIRES_NEW (doesn't work in Tomcat et al. in Seam 2). And relying on some global transaction management (which may or may not be enabled) to bundle up things for you is simply broken by design, IMHO.
                    I need to control this stuff.





                    • unintuitive: people expect the transaction to start and finish with their @Transactional methods. But that is not the case.





                    That is, if you need @Transactional at all :)...


                    Of course I do, see above.





                    • bad for performance: even if you use them not every page needs them (two per page in Seam 2!)





                    I don't think you should ever access database outside of a transaction. See Open Session in View article on Hibernate wiki.

                    Also, if there's no transaction, you loose any isolation. You always get READ_COMMITED, even if the connection's isolation level is REPEATABLE_READ.



                    OpenSessioninView is broken, I know. What I am saying is that you shouldn't depend on the view layer to load stuff from the database.
                    You put a bunch of lazy associations, you don't bother to fetch them and when stuff gets rendered they automagically get loaded. Because of this, you think you need JSF/global transaction. But since you are too lazy to load your stuff, you are generally too lazy to start/manage one. Hence, JSF lifecycle transactions :) I see where this comes from, but nevertheless I think it is a bad idea. A LIE is a sign that your application is broken, SMPC/Open Session in View/lifecycle transactions just serves to hide this from you.





                    • source of bugs: especially with ajax postbacks, some attached entity may end up persisted when you meant to ignore the changes. Just a small mistake in your xhtml is enough to trigger this. (we now about manual flush, but still)





                    Well that's a general architecture of JPA and Hibernate. Whether it's good or bad is debatable, but it just works this way :).



                    What I am saying is that POST = new transaction is a bad idea. If you want to ignore changes, you don't start/commit a transaction, easy to understand. With global transactions, you have to remember to clear/reload/detach/ whatever your entity to avoid commiting stuff you didn't want committed. Too much thinking involved -> bug.





                    • not easy to use: if you want to do something after the transaction commits (send email, etc.) you have to resort to transactionSuccessful (undocumented!) event and the like





                    Aren't transaction listeners in Weld documentation (here)? Besides, sending an e-mail is a perfect job for a MDB or some other asynchronous mechanism.



                    Undocumented in Seam 2, I meant. Whether you use JMS or @Asynchronous to do stuff is not really relevant, having to deal with a transaction that commits at some (mostly) unknown later time is not intuitive.  But since the event is standard in CDI, at least it is documented, I agree :)



                    Generally, I would vote for JSF lifecycle transactions enabled by default, but with an option to disable them, with 1 tx in a non-faces request and 2 txs in a postback.



                    Should be obvious by now where I stand, but I say: disabled by default with warnings in the docs ('this is what this feature does; don't call us if your application is slow' :).


                    PS. This has been said before, but formatting sucks big time. Try to write something a bit longer and you get tons of 'wrong position for X' errors. Since there will be changes to the forum, pretty please change it something more humane.

                    • 7. Re: JSF lifecycle transactions feature
                      Adam Warski Master

                      I guess you are just using a different architecture and you have different needs.


                      For almost all of my methods I need a transaction, and I don't want to worry about two calls from the view to the service start two transactions, or to worry to load every needed association in the service layer, so I want to have the JSF lifecycle transactions feature.
                      It would think that that's what most users expect.


                      You need to have control and load associations manually etc, so you don't want to have it. Perfectly fine of course :).


                      I think both of the approaches can be good :). So it's only a matter of if lifecycle transactions are on by default or off.


                      Adam

                      • 8. Re: JSF lifecycle transactions feature
                        Arbi Sookazian Master

                        Dan Allen wrote on Apr 15, 2010 01:40:


                        I also want to give this feature an official name, JSF lifecycle transactions. In Seam 2, they were called Seam managed transactions and in Seam in Action, I called them global transactions. I think the term JSF lifecycle transactions is much more applicable and clear. Plus, we can match this in other frameworks (e.g., Wicket lifecycle transactions).


                        Please be very careful here and think this out very long.  IMHO understanding transaction support and how to prevent LIEs with Hibernate flushMode MANUAL and SMPC becomes extremely convoluted and unnecessarily complicated and therefore intimidating and cumbersome.  This topic in Seam 2.x is still complicated and intimidating for me even after years of Seam/EE5 development.


                        Please strive to make this as simplified for the Seam developer as possible.  For Seam 2 devs migrating to Seam 3, digesting these terms (application tx's, global tx's, distributed tx's, JSF lifecycle tx's, Seam managed tx's) is a total disaster and presents a higher learning curve and barrier to entry to the application stack/frmwk.  And I'm not even talking about using @Transactional vs. the EJB3 tx support annotations, which is another level of choice/learning/complication. 


                        Get my drift??


                        It's good to give Seam devs the option of using JavaBean (managed bean?) vs. session bean components, but lets make it as consistent as possible.  Actually this is one of the reasons Spring seems simpler, you don't have to think about using a JavaBean or EJB.


                        How does .NET platform handle tx's?  Much simpler most likely but then again there is no JSF lifecycle in .NET apps.


                        BTW, this was a very interesting thread!

                        • 9. Re: JSF lifecycle transactions feature
                          Adam Warski Master

                          Arbi Sookazian wrote on Apr 19, 2010 19:00:


                          Please strive to make this as simplified for the Seam developer as possible.  For Seam 2 devs migrating to Seam 3, digesting these terms (application tx's, global tx's, distributed tx's, JSF lifecycle tx's, Seam managed tx's) is a total disaster and presents a higher learning curve and barrier to entry to the application stack/frmwk.  And I'm not even talking about using @Transactional vs. the EJB3 tx support annotations, which is another level of choice/learning/complication. 



                          In fact, what's described above is (as far as I know) the way Seam2 works. So no big changes here.


                          Also, I suppose it should be possible to write a portable extension which adds the transactional interceptor for all methods annotated with @TransactionAttribute. That way we support both ways (EE and SE). But I would have to try to be certain here :)


                          Adam

                          • 10. Re: JSF lifecycle transactions feature
                            Arbi Sookazian Master

                            Adam Warski wrote on Apr 20, 2010 11:35:


                            Also, I suppose it should be possible to write a portable extension which adds the transactional interceptor for all methods annotated with @TransactionAttribute. That way we support both ways (EE and SE). But I would have to try to be certain here :)

                            Adam


                            I would like to understand more details on this idea.  Also, isn't (over)using interceptors a possible/probable performance problem?  But then again Spring is using AOP advice/pointcut/etc. left-and-right which is very similar to interceptors...


                            That's why the Seam ref doc suggests using @BypassInterceptors as a performance optimization...

                            • 11. Re: JSF lifecycle transactions feature
                              Adam Warski Master

                              Well, in case you are not using JSF managed transactions, but transactions managed by interceptors, you need the interceptor ;) Either bound with @Transactional and @TransacionAttribute.


                              In Seam2, I think the main culprit (but that's only a feeling, maybe I am wrong) was the BijectionInterceptor. Because of the different injection model in Seam3, it's gone, so in theory the problems should be gone also.


                              Moreover, I think that in general the interceptors, decorators etc in Seam3/Weld are bound only where necessary, as opposed to the more global approach in Seam2.


                              Adam