Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting EntityManager with a producer in tomcat

I am running a project using Hibernate and Weld CDI on tomcat 7. I have write a ServletContextListener to create the EntityManagerFactory and EntityManager during application startup.

public class PersistenceListener implements ServletContextListener {

     private static EntityManagerFactory entityManagerFactory;

     public void contextInitialized(ServletContextEvent sce){
     ServletContext context = sce.getServletContext();
     entityManagerFactory = Persistence.createEntityManagerFactory("hibernate-test");
     }

     public void contextDestroyed(ServletContextEvent sce) {
     entityManagerFactory.close();
     }


     public static EntityManager createEntityManager() {
            if (entityManagerFactory == null) {
                throw new IllegalStateException("Context is not initialized yet.");
            }

            return entityManagerFactory.createEntityManager();
        }

}

I can use my entityManager in my test class (it is an arquillian test class) simply by creating it through the following code

EntityManager em = PersistenceListener.createEntityManager();
               em.getTransaction().begin();
                   em.createQuery("delete from Game").executeUpdate();
                   em.getTransaction().commit();

here is the complete code for my test class

    @RunWith(Arquillian.class)
    public class HibernateTestSample {

           @Deployment
           public static WebArchive createTestArchive()
           {
               MavenDependencyResolver resolver = DependencyResolvers.use(
                        MavenDependencyResolver.class).loadMetadataFromPom("pom.xml");

               WebArchive webArchive=  ShrinkWrap
                    .create(WebArchive.class, "ROOT.war")
                    .addClasses(CdiTestBean.class,HibernateListener.class,PersistenceListener.class)
                    .addAsLibraries(
                                resolver.artifact("org.jboss.weld.servlet:weld-servlet")
//                              .artifact("org.hibernate.javax.persistence:hibernate-jpa-2.0-api")
                                .artifact("org.apache.tomcat:tomcat-dbcp")
                                .artifact("org.hibernate:hibernate-entitymanager")
                                .artifact("org.hibernate:hibernate-validator")
                                .artifact("org.hibernate:hibernate-core")   
                                .artifact("com.h2database:h2")
                                .artifact("mysql:mysql-connector-java")
                                .resolveAs(GenericArchive.class))

                    .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
                    .addAsWebInfResource("test-persistence.xml", "classes/META-INF/persistence.xml")
                    .addAsWebInfResource("hibernate.cfg.xml", "classes/hibernate.cfg.xml") 
//                  .addAsWebInfResource("context.xml", "classes/META-INF/context.xml")
                    .addAsManifestResource("context.xml", "context.xml")
                    .setWebXML("hibernate-web.xml");
              System.out.println(webArchive.toString(true));

              return webArchive;
           }


           @Test
           public void myTest()
                   throws Exception {                                                      

               EntityManager em = PersistenceListener.createEntityManager();
               em.getTransaction().begin();
                       em.createQuery("delete from Game").executeUpdate();
                   em.getTransaction().commit();
                  ...............
                      .......
                      ...


           }
    }

but I want to inject my entityManager to my class. I read in an other post that I cannot use @PersistenceContext in my class, therefor I decided to use a producer to inject my entity manager. but it doesn't work for my, please tell me what am i doing wrong here (I am quite new in CDI )

here is my new ServletContextListener

public class PersistenceListener implements ServletContextListener {

     private static EntityManagerFactory entityManagerFactory;

     @Produces
     private EntityManager entityManager;

     public void contextInitialized(ServletContextEvent sce){
     ServletContext context = sce.getServletContext();
     entityManagerFactory = Persistence.createEntityManagerFactory("hibernate-test");
     createEntityManager();
     }

     public void contextDestroyed(ServletContextEvent sce) {
     entityManagerFactory.close();
     }


     public void createEntityManager() {
            if (entityManagerFactory == null) {
                throw new IllegalStateException("Context is not initialized yet.");
            }

            this.entityManager =  entityManagerFactory.createEntityManager();
        }

and I am injecting in my testclass

@Inject
private EntityManager em;

It is null

like image 834
Yashar Avatar asked Oct 05 '22 00:10

Yashar


2 Answers

The instance created through the Servlet specification by implementing ServletContextListener is not the same instance as CDI will create later on to resolve your @Produces field.

Further I recommend this informative blog post about the EntityManager: http://struberg.wordpress.com/2012/04/25/is-there-a-way-to-fix-the-jpa-entitymanager/

It might be slighly outdated though because if I recall correctly I have seen @TransactionScoped in the works over at deltaspike.

Lastly as you may have figured by now having a singleton EntityManager is not what you want but for the sake of completeness the miss in synergy between your ContextListener and CDI can be somewhat fixed by using CdiCtrl from Deltaspike and BeanProvider from Deltspike Core.

How to attach CDI ApplicationScope to to your current thread http://struberg.wordpress.com/2012/03/17/controlling-cdi-containers-in-se-and-ee/

And then you can pickup a bean that is annotated with @ApplicationScoped and set it up. The pickup is done with MyBean myBean = BeanProvider.getContextualReference(MyBean.class, false); http://deltaspike.apache.org/deltaspike/core.html

Hopefully CDI 1.1 will make this a little more fluent

Update: The talk on the Deltaspike list is to have 0.5 be a smaller release in about a month. Hopefully the new Servlet module will solve this nicely.

https://issues.apache.org/jira/browse/DELTASPIKE-376 https://issues.apache.org/jira/browse/DELTASPIKE-377

like image 156
Karl Kildén Avatar answered Oct 13 '22 11:10

Karl Kildén


You need @Produces on your createEntityManager method, instead of the field.

like image 27
LightGuard Avatar answered Oct 13 '22 12:10

LightGuard