1 Reply Latest reply on Mar 24, 2010 3:53 AM by Stuart Douglas

    Transactional observers with @Transactional

    Ashley Westwell Newbie

      Hey All



      I am having an issue where the transactional observer fires with a EntityManager persiste but it does not take in to account the commit. In the following example I have wrapped the persist method with @Transactional as show in the example at URL My Link


      Based on the @Transactional Interceptor it performs a begin, proceed and commit


      @Transactional
      @Interceptor
      public class EntityTransactionInterceptor  implements Serializable {
          private @Inject @Any EntityManager em;
          @AroundInvoke
          public Object aroundInvoke(InvocationContext ic) throws Exception {
              boolean act = !em.getTransaction().isActive();
              if(act) {
                  em.getTransaction().begin();
              }
              try {
                  Object result = ic.proceed();
                  if(act) {
                      em.getTransaction().commit();
                  }
                  return result;
              }
              catch (Exception e) {
                  if (act) {
                      em.getTransaction().rollback();
                  }
                  throw e;
              }
          }
      }



      My issue is the following the persistEntityEvent is set to observe during the TransactionPhase.AFTER_SUCCESS. If this means that the event for TransactionPhase.AFTER_SUCCESS does not wait for the commit what happens if the commit fails. Which is exactly what I am seeing. If I try to commit unique values twice it still calls the persistEntityEvent before the commit is executed. This means that the event fires before the final commit which could fail.




      @Singleton
      public class ProductManager {
      
         @PersistenceContext EntityManager em;
         @Inject @Any Event<Product> productEvent;
         Set<Product> elements = new HashSet<Product>(0);
      
         @Transactional
         public void delete(Product product) {
            em.delete(product);
            productEvent.select(new AnnotationLiteral<Deleted>(){}).fire(product);
         }
      
         @Transactional
         public void persist(Product product) {
            em.persist(product);
            productEvent.select(new AnnotationLiteral<Created>(){}).fire(product);
         }
      
         private void persistEntityEvent(@Observes(during=TransactionPhase.AFTER_SUCCESS) @Created Product product) {
            elements.add(product);
         }
           
         private void deleteEntityEvent(@Observes(during=TransactionPhase.AFTER_SUCCESS) @Deleted Product product) {
            elements.remove(product);
         }
      }





      What I want to do is only call the event if the commit executes successfully. Anyone have any ideas on what I am doing wrong?