2 Replies Latest reply on Jul 21, 2010 8:19 AM by pmuir

    Seam style Persistence management with Wicket and Weld

    paulmooney

      This is a tutorial for accomplishing Seam style Persistence management with Wicket and Weld.


      My goal is to recreate Seam style persistence and transaction management in Weld, or rather the parts of Seam persistence which interest me most:




      • Conversation scoped Persistence Context / Entity Manager

      • 2 Transactions Per request: 1 for processing the request, and 1 for rendering the response.



      My example runs on Glassfish v3.0.


      Starting with the first part, the conversation scoped entity manager. I've created a couple producers and a disposer for the entity manager which will close the it when the conversation ends




      @ConversationScoped
      public class EntityManagerProducer implements Serializable {
      
          @Inject
          Logger log;
      
          @PersistenceUnit
          EntityManagerFactory entityManagerFactory;
      
          @Produces
          @ConversationScoped
          public EntityManager createEntityManager() {
           log.debug("Creating entity manager");
           return entityManagerFactory.createEntityManager();
          }
      
          public void closeEntityManager(@Disposes EntityManager em) {
           log.debug("Closing entity manager");
           em.close();
          }
      
          @Produces
      //    @HibernateSession
          @ConversationScoped
          public Session getHibernateSession(EntityManager em) {
           log.debug("Producing Hibernate Session");
           return (Session) em.getDelegate();
          }
      }



      I've created a producer for the hibernate session as well. This is useful for setting a manual flush mode on the entity manager during long running conversations. Conversation scoped EntityManager is now done. That was easy.


      Next comes the 2 transactions per request. I start by creating a Transactional request cycle which extends the WeldRequestCycle:



      public class TransactionalRequestCycle extends WeldRequestCycle {
      
          /*@Inject
          UserTransaction tx;
      
          @Inject
          Logger log;*/
      
          public TransactionalRequestCycle(WebApplication application, WebRequest request, Response response) {
           super(application, request, response);
          }
      
          public UserTransaction getUserTransaction() {
           BeanManager bm = BeanManagerLookup.getBeanManager();
           Bean<UserTransaction> bean = (Bean<UserTransaction>) bm.getBeans(UserTransaction.class).iterator().next();
           CreationalContext<UserTransaction> ctx = bm.createCreationalContext(bean);
           UserTransaction tx = (UserTransaction) bm.getReference(bean, UserTransaction.class, ctx);
           return tx;
          }
      
          public EntityManager getEntityManager() {
           BeanManager bm = BeanManagerLookup.getBeanManager();
           Bean<EntityManager> bean = (Bean<EntityManager>) bm.getBeans(EntityManager.class).iterator().next();
           CreationalContext<EntityManager> ctx = bm.createCreationalContext(bean);
           EntityManager em = (EntityManager) bm.getReference(bean, EntityManager.class, ctx);
           return em;
          }
      
          @Override
          protected void onRequestTargetSet(IRequestTarget target) {
           super.onRequestTargetSet(target);
           try {
      
               //Open transaction here since Conversation context will exist here
               UserTransaction tx = getUserTransaction();
               if (tx.getStatus()==Status.STATUS_NO_TRANSACTION) {
                EntityManager em = getEntityManager();
                tx.begin();
                em.joinTransaction();
               }
           } catch (NotSupportedException ex) {
               throw new RuntimeException(ex);
           } catch (SystemException ex) {
               throw new RuntimeException(ex);
           }
          }
      
          @Override
          protected void onBeginRequest() {
           
           super.onBeginRequest();
           /*try {
               
               UserTransaction tx = getUserTransaction();
               EntityManager em = getEntityManager();
               tx.begin();
               em.joinTransaction();
           } catch (NotSupportedException ex) {
               throw new RuntimeException(ex);
           } catch (SystemException ex) {
               throw new RuntimeException(ex);
           }*/
          }
      
          @Override
          protected void onEndRequest() {
           super.onEndRequest();
           try {
               UserTransaction tx = getUserTransaction();
               if (tx.getStatus() == Status.STATUS_ACTIVE) {
                tx.commit();
               }
           } catch (Exception ex) {
               throw new RuntimeException(ex);
           }
          }
      
          @Override
          public Page onRuntimeException(Page page, RuntimeException e) {
           Page toReturn = super.onRuntimeException(page, e);
           try {
               UserTransaction tx = getUserTransaction();
               if (tx.getStatus() == Status.STATUS_ACTIVE) {
                tx.rollback();
               }
           } catch (SystemException ex) {
               throw new RuntimeException(ex);
           } finally {
               return toReturn;
           }
          }
      
      }



      The transaction begins at the onRequestTargetSet. This is a place which gets called before your code does, sometimes it gets called more than once so we have to make sure the transaction hasn't started yet. The transaction ends at onEndRequest(), which is called at the very end of the request, even after any rendering. Ending the transaction here is sort of a catch-all. Finally if there are any exceptions we role back.


      The Wicket application needs to extend the Weld application and override the getter for the request cycle, so that we can pass our transactional request cycle back.



      public class WicketApplication extends WeldApplication {
      
          /**
           * Constructor
           */
          public WicketApplication() {
          }
      
          /**
           * @see org.apache.wicket.Application#getHomePage()
           */
          @Override
          public Class<HomePage> getHomePage() {
           return HomePage.class;
          }
      
          @Override
          public RequestCycle newRequestCycle(Request request, Response response) {
           return new TransactionalRequestCycle(this, (WebRequest) request, (WebResponse) response);
          }
      }




      At this point the application will run, and requests will be transactional. Unfortunately both the request processing and the render response are wrapped in the same transaction. This is no good because if there is an issue rendering the response we don't want it to roll back our successful request processing. To avoid this we need to break the transaction in two. This can be accomplished by creating a transactional page class which will commit begin and commit again our transaction before and after page rendering.



      public class TransactionalPage extends WebPage {
      
          @Inject
          protected EntityManager em;
      
          @Inject
          UserTransaction tx;
      
          @Override
          protected void onBeforeRender() {
           try{ 
               if (tx.getStatus() == Status.STATUS_ACTIVE)  {
                tx.commit();
               }
      
               tx.begin();
               em.joinTransaction();
           } catch (Exception ex) {
               throw new RuntimeException(ex);
           } 
      
           super.onBeforeRender();
          }
      
      
      
          @Override
          protected void onAfterRender() {
           super.onAfterRender();
           try {
               if (tx.getStatus() == Status.STATUS_ACTIVE) {
                tx.commit();
               }
      
           } catch (Exception ex) {
              throw new RuntimeException(ex);
           } 
           
          }
      
      }



      Notice onBeforeRender() commits and then begins a transaction. This is where the transaction wrapping the request is split in two.


      Finally all your pages will extend your transactional page and you will have the Seam style two transactions per request.


      How does this work? The following is the sequence of steps during a wicket request:




      1. Request Hits the Wicket filter

      2. A Transaction begins at onRequestTargetSet()

      3. Your code for handling this particular request is executed

      4. The transaction ends and a new one begins at onBeforeRender()

      5. The page is rendered, all model objects are accessed

      6. The second transaction ends at onAfterRender()



      Issues:




      • So far this only works for normal requests. Ajax requests don't call the Page's onBeforeRender() or onAfterRender() so the transaction doesn't get split up into 2. There is still a transaction wrapping the Ajax request, which works but one transaction is not ideal.

      • It would be better to start the first transaction in onBeginRequest() however the conversation context is not available at this point. I need to find a better starting point for the transaction than onRequestTargetSet() which gets called multiple times.



      I'm open to suggestions,hints, and insight, since this is my first dive into the Wicket lifecycle and am relatively new to Weld.











        • 1. Re: Seam style Persistence management with Wicket and Weld
          paulmooney

          Okay, so obviously I'm posting as I go but this is a forum not a blog.


          To combat the issue of the single transaction per ajax request I've implemented a RequestCycleProcessor to split the transaction in two rather than using the TransactionalPage described previously. Not only does this help with the ajax requests but it means that my pages no longer have to inherit from TransactionalPage! So scrap it!


          Here's the Transactional Request Cycle Processor:




          /**
           *
           * @author paul
           */
          public class TransactionalWebRequestCycleProcessor extends WeldWebRequestCycleProcessor {
          
              @Inject
              EntityManager em;
              @Inject
              UserTransaction tx;
          
              @Override
              public void respond(RequestCycle requestCycle) {
          
          //     close/commit the request processing transaction
               try {
                   if (tx.getStatus() == Status.STATUS_ACTIVE) {
                    tx.commit();
                   }
               } catch (Exception ex) {
                   throw new RuntimeException(ex);
               }
          
          //     open the response rendering transaction
               if (!requestCycle.isRedirect() || isAjaxRequest(requestCycle)) {
                   try {
                    tx.begin();
                    em.joinTransaction();
                   } catch (Exception ex) {
                    throw new RuntimeException(ex);
                   }
               }
          
               super.respond(requestCycle);
          
          //     close/commit the response rendering transaction
               if (!requestCycle.isRedirect() || isAjaxRequest(requestCycle)) {
                   try {
                    if (tx.getStatus() == Status.STATUS_ACTIVE) {
                        tx.commit();
                    }
                   } catch (Exception ex) {
                    throw new RuntimeException(ex);
                   }
               }
              }
          
              private boolean isAjaxRequest(RequestCycle requestCycle) {
               //requestCycle.
               return requestCycle.getRequestTarget() instanceof AjaxRequestTarget;
              }
          }



          This is similar to what was going on in the Transactional page:




          1. A Request hits the Wicket filter

          2. A Transaction begins at onRequestTargetSet() in the request cycle

          3. Your code for handling this particular request is executed

          4. The transaction ends and a new one begins before the respond() method is called in the cycle processor

          5. The response is rendered, all model objects are accessed

          6. The second transaction ends after the respond() method is complete



          You'll notice I've tried to avoid starting a transaction during a redirect, however for reasons beyond me at this point an ajax request is a redirect, so I have to watch out for that.


          To setup our TransactionalWebRequestCycleProcessor we add a new field and override a few methods in our Wicket Application. The application should now look like this:




          public class WicketApplication extends WeldApplication {
          
              NonContextual<TransactionalWebRequestCycleProcessor> transactionalRequestCycleProcessor;
          
              /**
               * Constructor
               */
              public WicketApplication() {
              }
          
              /**
               * @see org.apache.wicket.Application#getHomePage()
               */
              @Override
              public Class<HomePage> getHomePage() {
               return HomePage.class;
              }
          
              @Override
              public RequestCycle newRequestCycle(Request request, Response response) {
               return new TransactionalRequestCycle(this, (WebRequest) request, (WebResponse) response);
              }
          
              @Override
              protected IRequestCycleProcessor newRequestCycleProcessor() {
               return transactionalRequestCycleProcessor.newInstance().produce().inject().get();
              }
          
              @Override
              protected void internalInit() {
          
               super.internalInit();
               this.transactionalRequestCycleProcessor = new NonContextual<TransactionalWebRequestCycleProcessor>(BeanManagerLookup.getBeanManager(), TransactionalWebRequestCycleProcessor.class);
              }
          }



          To tidy this up a bit we can separate all this junk out into an abstract class:



          public abstract class TransactionalWeldApplication extends WeldApplication {
          
              NonContextual<TransactionalWebRequestCycleProcessor> transactionalRequestCycleProcessor;
          
              @Override
              public RequestCycle newRequestCycle(Request request, Response response) {
               return new TransactionalRequestCycle(this, (WebRequest) request, (WebResponse) response);
              }
          
              @Override
              protected IRequestCycleProcessor newRequestCycleProcessor() {
               return transactionalRequestCycleProcessor.newInstance().produce().inject().get();
              }
          
              @Override
              protected void internalInit() {
          
               super.internalInit();
               this.transactionalRequestCycleProcessor = new NonContextual<TransactionalWebRequestCycleProcessor>(BeanManagerLookup.getBeanManager(), TransactionalWebRequestCycleProcessor.class);
              }
          
          }



          Now having two transactions per request is as simple as extending the TransactionalWeldApplication!


          Issues:




          • I'm not sure if the Test for Ajax request is the most reliable. I may need to come up with something better.

          • At this point I'm not sure if exceptions will cause proper rollbacks for most situations. I have some testing to do, and will post back on that.












          • 2. Re: Seam style Persistence management with Wicket and Weld
            pmuir

            Nice tutorial!