5 Replies Latest reply on Mar 17, 2010 2:32 AM by Ashley Westwell

    EntityTransactionInterceptor with correct EntityManager in Java SE

    Ashley Westwell Newbie

      Hey Everyone


      I wanted to get some clarification regarding the example show at http://seamframework.org/Documentation/WeldAndJPARunningInTomcat


      1. Created a class to produce my EntityManager


      public class PersistenceProducer {
         @Produces @TicketManager @PersistenceContext(unitName="LogicBoxTicketManager") EntityManager entityManager;
      }
      




      2. Create a manager class(Singleton) with a simple qualifier named TicketManager


      @Singleton
      @Named("TestManager")
      public class TestManager {
              @Inject @TicketManager EntityManager entityManager;
      
              @Transactional
              public void persist(TestBean testBean) {
                 entityManager.persist(testBean);
              }
      }
      



      3. Added source for the EntityTransactionInterceptor (which I know is being called) and the transactional qualifier


      @Transactional
      @Interceptor
      public class EntityTransactionInterceptor {
      
              private @Inject @Any EntityManager entityManager;
      
              @AroundInvoke
              public Object aroundInvoke(InvocationContext invocationContext) throws Exception {
                      boolean active = !(entityManager.getTransaction().isActive());
                      if(active) {
                              entityManager.getTransaction().begin();
                      }
                      try {
                              Object result = invocationContext.proceed();
                              if(active) {
                                      entityManager.getTransaction().commit();
                              }
                              return result;
                      }
                      catch (Exception exception) {
                              if (active) entityManager.getTransaction().rollback();
                              throw exception;
                      }
              }
      }




      My question is in regards to the EntityTransactionInterceptor. How does it know to use the instance of the EntityManager defined in the TestManager and not to create a new one? I understand the @Inject basics but how does the Interceptor know which EntityManager to inject? Especially with mine containing another qualifier @TicketManager?


      The reason I ask is the sample code runs fine but no record is added to the database. I am assuming this is because it is not getting the correct EntityManager from the TestManager class. If I remove the @Transactional from the persist method and add the following lines around the persist method it works fine.




      -> entityManager.getTransaction().begin();
      entityManager.persist(auditTypeBean);
      -> entityManager.getTransaction().commit();
      




      Thanks for the help in advanced :)

        • 1. Re: EntityTransactionInterceptor with correct EntityManager in Java SE
          Stuart Douglas Master

          Your entityManager is @Depenant scoped, so a new one is created every time you inject.


          Try this:


          
          @Produces @TicketManager @ConversationScoped @PersistenceContext(unitName="LogicBoxTicketManager") EntityManager entityManager;
          
          


          • 2. Re: EntityTransactionInterceptor with correct EntityManager in Java SE
            Ashley Westwell Newbie

            Right I can understand that. However I was hoping to have the producer generic so that it can be used in different scopes. This is why I did not define a scope. I guess is there a way to access the instance via the EntityTransactionInterceptor.


            BTW I don't think I can use the ConversationScoped because its a standalone application using Java SE. What I would like to do is link the instance defined in the TestManager to the EntityTransactionInterceptor so it can find the instance. Is it possible to get the instance of the EntityManager defined in the TestManager bean from with in the Interceptor.


            Or do you have a better suggestion?

            • 3. Re: EntityTransactionInterceptor with correct EntityManager in Java SE
              Ashley Westwell Newbie

              Just to clarify I want to leave my Interceptor generic so it is not aware of a scope and is just used to produce an instance. Maybe I am wrong but a producer should not care of the scope it should just produce the instance of EntityManager. The managed bean that it is injected into should control the life cycle of the EntityManager.


              Based on this I would like to set an annotation of some sort on the method with the same annotation on the EntityManager and have the Interceptor link the two based on the annotations matching.


              Something like that... So is it possible to access the class instance that the Interceptor is on so I can look up the EntityManager instance.


              • 4. Re: EntityTransactionInterceptor with correct EntityManager in Java SE
                Stuart Douglas Master

                If you actually want an @Dependant scoped EM then you will probably have to resort to dirty hacks to make it do what you want. The easiest way would probably be to create an interface with a getEntityManager() method and call this from your interceptor to get hold of the em.


                Stuart

                • 5. Re: EntityTransactionInterceptor with correct EntityManager in Java SE
                  Ashley Westwell Newbie

                  Hey Stuart


                  So here is what I am thinking I will do regarding this issue. I have noticed that the invocationContext.getTarget() in the Interceptor seems to return the instance of the object that the interceptor was called on. If this is correct I want to do the following and was wondering if you or someone else could suggest the API calls to use.


                  So basically I am thinking I would like to match the qualifiers on the method that invoked the Interceptor to the EntityManager in the instance that contains the qualifier. So that will help me determine which EntityManager I should perform the begin transaction and commit transaction on.


                  For Example as show below the Interceptor would look for a Field in the instance with a qualifier @TicketManager this would then match up with the property entityManager and set the begin and commit transaction


                  @Singleton
                  @Named(TestManager)
                  public class TestManager {
                          @Inject @TicketManager EntityManager entityManager;


                          @Transactional @TicketManager
                          public void persist(TestBean testBean) {
                             entityManager.persist(testBean);
                          }
                  }


                  What do you think of this idea? Also is there a util method to return all the qualifiers for a given field in Weld?


                  Ashley