One popular issue of every application is about handling multiple database resources (at minimum you should consider handling a production DB and a development DB). In this tutorial we will show how you can solve this elegantly with CDI and its powerful annotations.

JPA and CDI

Basically, CDI is an annotation-driven injection framework that minimizes the bulk of boilerplate code that developers have to write. It is designed to greatly increase productivity, testability, and the quality of business applications built on the Java platform.

Let's see an example taken from the KitchenSink example:

 @Inject
 private EntityManager em;

  public List<Member> findAllOrderedByName() {


        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Member> criteria = cb.createQuery(Member.class);
        Root<Member> member = criteria.from(Member.class);

        criteria.select(member).orderBy(cb.asc(member.get("name")));
        return em.createQuery(criteria).getResultList();
  }


Here we are injecting an EntityManager and use it to issue a Query. That's pretty fine, however let's see how we can improve this by adding your own custom EntityManager qualifier annotations, to return a specific EntityManager using standard CDI annotations:

The following Qualifier will be used by Producer methods to create a MySQLDatabase-bound Entity Manager:

package com.sample;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.inject.Qualifier;


@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
public @interface MySQLDatabase {
}


And here's the Producer class, which will be used to create Entity Managers which are bound to the "primary" Persistence Context

package com.sample;

import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

public class DatabaseProducer {

    @Produces
    @PersistenceContext(unitName = "primary")
    @MySQLDatabase
    private EntityManager em;


}


Here's the sample persistence.xml file which contains two persistence unit: the first one which is bound to MySQL and the second one which uses the default ExampleDS DB.

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"
   xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
        http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
   <persistence-unit name="primary">

      <jta-data-source>java:jboss/datasources/MySqlDS</jta-data-source>
       <properties>

         <property name="hibernate.hbm2ddl.auto" value="create-drop" />

      </properties>
   </persistence-unit>

      <persistence-unit name="secondary">

      <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
      <properties>
         <!-- Properties for Hibernate -->
         <property name="hibernate.hbm2ddl.auto" value="create-drop" />
         <property name="hibernate.show_sql" value="false" />
      </properties>
   </persistence-unit>
</persistence>


Now it's just a matter of adding the @MySQLDatabase database annotation to mark an EntityManager injection as bound to MySQL database:

@MySQLDatabase
@Inject
private EntityManager em;


You can create of course a corresponding qualifier for the DefaultDS and add it to the DatabaseProducer

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
public @interface DefaultDatabase {
}

 

public class DatabaseProducer {

    @Produces
    @PersistenceContext(unitName = "primary")
    @MySQLDatabase
    private EntityManager em;

    @Produces
    @PersistenceContext(unitName = "secondary")
    @DefaultDatabase
    private EntityManager em;
}


This way you can immediatly give evidence of what you are doing with your Entity Managers.


 

JPA and CDI using @Alternative producers

When using this approach we suppose that it's known at compile time the EntityManager that will be used in each method or class. If on the other hand you want to address this issue at packaging time, you can use the @Alternative annotation.

The @Alternative annotation lets you package multiple beans that match an injection point without ambiguity errors. In other words, you can apply the @Alternative annotation to two or more beans, then, based on your deployment, specify the bean you want to use in CDI's beans.xml configuration file.

For example, here we will declare two database producers, one for MySQL and one for Default database:

package com.sample;

import javax.enterprise.inject.Alternative;

import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

@Alternative
public class MySQLDatabaseProducer {

    @Produces
    @PersistenceContext(unitName = "primary")
    private EntityManager em;


}

 

package com.sample;

import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

@Alternative
public class DefaultDatabaseProducer {

    @Produces
    @PersistenceContext(unitName = "secondary")
    private EntityManager em;


}


Now, each time you inject an Entity Manager:

@Inject
private EntityManager em;


the choice of which EntityManager will be resolved by CDI's beans.xml file (placed into the WEB-INF folder of your Web application).

<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    
<alternatives>
  <class>com.sample.MySQLDatabaseProducer</class>
</alternatives>       
</beans>

Specifying the default Entity Manager properties

One more trick you can do with CDI, is defining a method and marking it as producer, This way, it will be called each time an EntityManeger object is needed. For example, here we are injecting some properties into our EntityManager once it is created. This can be useful for example if you have multiple databases with the same schemas, but using a different dialect (ex. MySQL-Oracle) and we want to choose dynamically which dialect will be used:

    @PersistenceUnit(unitName = "primary")
    private EntityManagerFactory emf;

    @Produces
    @PersistenceContext(unitName = "primary")
    public void createEntityManager() {

     Map props = new HashMap();
     props.put("hibernate.show_sql","true");
     props.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
     props.put("hibernate.show_sql","true");
     props.put("hibernate.format_sql","true");


     EntityManager emy = emf.createEntityManager(props);
    }

    
Finally, each resource Producer might have a corresponding resource Disposer which can be used to perform some clean up actions before removing the instance. For example, here's how you can dispose the EntityManager created by the createEntityManager method:

 public void dispose(@Disposes @Default EntityManager entityManager)
    {
        if(entityManager.isOpen())
        {
            entityManager.close();
        }
    }
0
0
0
s2smodern