hakdogan
hakdogan

Reputation: 168

Relative persistence unit inject?

I have a Persistence.xml with multiple persistence-unit definition file exists.

I want to inject unit EntityManager object, according to the user who entered the system.

Is it possible?

@PersistenceContext (unitName = myUnit)

In this use, I get a warning: "attribute value must be constant"

Application Frameworks: JSF 2.1 & Spring 3.0.2

Persistence layer: JPA

Upvotes: 3

Views: 2270

Answers (5)

hakdogan
hakdogan

Reputation: 168

My solution was not the solution :)

applicationContext.xml:

<context:component-scan base-package="com.hakdogan.hakdoganjsfspring"/>
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManagerConstant"/>
<tx:annotation-driven transaction-manager="transactionManagerRelative"/>

<bean id="jpaDialect" class="com.hakdogan.hakdoganjsfspring.util.HibernateExtendedJpaDialect" />
<bean id="transactionManagerConstant" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="constant"/>
    <property name="jpaDialect" ref="jpaDialect" />
</bean>

<bean id="transactionManagerRelative" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="relative"/>
    <property name="jpaDialect" ref="jpaDialect" />
</bean>

<bean id="constant" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="persistenceUnitManager" ref="persistenceUnitManager" />
   <property name="persistenceUnitName" value="JSFSpring" />
</bean>

<bean id="relative" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
   <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
   <property name="persistenceUnitName" value="hakdogan" />
</bean>

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
   <property name="database" value="MYSQL"/>
   <property name="showSql" value="true"/>
   <property name="generateDdl" value="false"/>
   <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
</bean>

<bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
  <property name="persistenceXmlLocations">
   <list>
      <value>classpath*:META-INF/persistence.xml</value>
   </list>
  </property>
</bean>

<bean id="persistenceManager" class="com.hakdogan.hakdoganjsfspring.util.PersistenceManager"/>
<bean id="odev" class="com.hakdogan.hakdoganjsfspring.entity.Odev" scope="prototype" />

</beans>

PersistenceManager.java:

public class PersistenceManager {


@Autowired
private LocalEntityManagerFactoryBean persistence;
private PersistenceProvider provider;

 public EntityManager getBaglam(String unitName){
    if(null == provider)
        provider = persistence.getPersistenceProvider();

    if(!unitName.equals(persistence.getPersistenceUnitName()))
        persistence.setPersistenceUnitName(unitName);

    return provider.createEntityManagerFactory(unitName, null).createEntityManager();
 }
}

PersistDAO.java:

@Component("persistDAO")
@Scope("session")
public class PersistDAO {

   @PersistenceContext(unitName="JSFSpring")
   private EntityManager em;


@Autowired
private PersistenceManager persistenceManager;

private List<Odev> kayitListesi;
private List<Event> eventListesi;
private List<Musteriler> musteriListesi;    

private String myUnit = "hakdogan";


@Transactional(propagation = Propagation.REQUIRED, readOnly=true)
public List<Odev> getKayitListesi() {
    return kayitListesi = (List<Odev>) em.createNamedQuery("Odev.findAll").getResultList();
}

@Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED)
public List<Event> getEventListesi() {
    return persistenceManager.getBaglam(myUnit).createQuery("SELECT e FROM Event e").getResultList();
}

@Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED)
public List<Musteriler> getMusteriListesi() {
    return persistenceManager.getBaglam("musteri").createNamedQuery("Musteriler.findAll").getResultList();
}
}

Does not have a property such as LocalEntityManagerFactoryBean persistenceUnitManager. For this reason, I could not set the names of unit.

The cost is to create EntityManagerFactory in happening. Trying to slow the project.

I'm looking for an effective solution in the Spring.

Thanks.

Upvotes: 0

hakdogan
hakdogan

Reputation: 168

I reached a solutions. I'm new learning in Spring. There are definitely better solutions, but I still wanted to share the solution.

applicationContext.xml

<context:component-scan base-package="com.hakdogan.hakdoganjsfspring"/ 

<tx:annotation-driven transaction-manager="transactionManagerConstant"/ 

<tx:annotation-driven transaction-manager="transactionManagerRelative"/ 

<bean id="odev" class="com.hakdogan.hakdoganjsfspring.entity.Nesne"  / 

<bean id="transactionManagerConstant" 
class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="constant"/> 
    <property name="jpaDialect" ref="jpaDialect" /> 
</bean> 
<bean id="transactionManagerRelative" 
class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="relative"/> 
    <property name="jpaDialect" ref="jpaDialect" /> 
</bean> 
<bean id="jpaDialect" 
class="com.hakdogan.hakdoganjsfspring.util.HibernateExtendedJpaDialect" / 

<bean id="persistenceUnitManager" 
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitMa nager"> 
<property name="persistenceXmlLocations"> 
  <list> 
      <value>classpath*:META-INF/persistence.xml</value> 
      <value>classpath*:META-INF/hk.xml</value> 
  </list> 
</property> 
</bean> 
<bean id="constant" 
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
<property name="persistenceUnitManager" 
ref="persistenceUnitManager" /> 
<property name="persistenceUnitName" value="JSFSpring" /> 
</bean> 
<bean id="relative" 
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
<property name="persistenceUnitManager" 
ref="persistenceUnitManager" /> 
</bean> 
<bean id="persistenceManager" 
class="com.hakdogan.hakdoganjsfspring.util.PersistenceManager"/> 
</beans>

PersistenceManager.java

public class PersistenceManager { 
   private LocalContainerEntityManagerFactoryBean persistence; 
   public LocalContainerEntityManagerFactoryBean getPersistence() { 
    return persistence; 
   } 

   @Autowired 
   @Qualifier("relative") 
   public void setPersistence(LocalContainerEntityManagerFactoryBean 
persistence) { 
    this.persistence = persistence; 
   } 
}

PersistDAO.java

@Component("persistDAO") 
@Scope("session") 
public class PersistDAO { 
   @PersistenceContext(unitName="JSFSpring") 
   private EntityManager em; 

   @Autowired 
   private PersistenceManager persistenceManager; 

   @Autowired 
   private Nesne nesne; 

   private List<Odev> kayitListesi; 
   private List<Event> eventListesi; 
   private String myUnit = "hakdogan"; 

   public Nesne getNesne() { 
     return nesne; 
   } 

   public void setNesne(Nesne nesne) { 
     this.nesne = nesne; 
   } 

   @Transactional(isolation = Isolation.SERIALIZABLE, propagation = 
    Propagation.REQUIRED) 
   public String kaydet(){ 
      em.persist(nesne); 
      return "/liste.xhtml"; 
   } 

   @Transactional(propagation = Propagation.REQUIRED, readOnly=true) 
   public List<Odev> getKayitListesi() { 
      return kayitListesi = (List<Odev>) 
      em.createNamedQuery("Odev.findAll").getResultList(); 
   } 

   @Transactional(readOnly=true) 
   public List<Event> getEventListesi() { 
      persistenceManager.getPersistence().setPersistenceUnitName(myUnit); 
      EntityManager emt =        persistenceManager.getPersistence().getNativeEntityManagerFactory().createEntityManager(); 
    return eventListesi = (List<Event>) 
    emt.createNamedQuery("Event.findAll").getResultList(); 
   } 
} 

Upvotes: 0

Tom Anderson
Tom Anderson

Reputation: 47193

Can you use CDI? You could write a little class which gets injected with all the different contexts, then supplies them to your classes through a producer method which does some logic. Bit like this:

public class PersistenceContext {
    @PersistenceContext(unitName="myUnit") private EntityManager myEm;
    @PersistenceContext(unitName="yourUnit") private EntityManager yourEm;

    @Produces
    public EntityManager getEntityManager(InjectionPoint ip) {
        if (USER IS ME) {
            return myEm;
        }
        else if (USER IS YOU) {
            return yourEm;
        }
        else {
            NOW PANIC AND FREAK OUT
        }
    }
}

Then you can just write classes like this:

public class FeedReamer {
    @Inject private EntityManager em;
}

And everything will magically happen right (possibly?).

If you don't want to hardcode the names of the persistence units in the class, then instead of relying on injection, you may be able to get the entity manager factories explicitly:

    @Produces
    public EntityManager getEntityManager(InjectionPoint ip) {
        String persistenceUnitName = somehowDeterminePersistenceUnitName();
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
        return emf.createEntityManager();
    }

However, although this method will work in a J2SE application, Persistence.createEntityManagerFactory is not guaranteed to work in J2EE. Footnote 42 in the spec (the EJB 3.0 persistence spec, at least) says:

Use of these Java SE bootstrapping APIs may be supported in Java EE containers; however, support for such use is not required.

In addition, i believe that creating a new EntityManagerFactory can be quite slow; you might find you needed to cache the results of the lookups. I believe it should be safe to hold on to an EntityManagerFactory for a long time, and to access it from multiple threads (but i'm not certain).

Upvotes: 2

As it has been mentioned in another post, annotation attributes must be constant.

Another approach could be getting an EntityManager instance programmatically:

Persistence.getEntityManagerFactory().getEntityManager(persistenceUnitName);

You could implement the logic necessary to assign the persistence unit name depending on your own criteria. Obviously this has all the downsides associated to the fact that persistence is not managed by the container anymore.

Upvotes: 1

skaffman
skaffman

Reputation: 403501

As the error message says, Java annotation attributes must be constant values, not references to variables. This is a limitation in the Java languages, not JPA. You'll need to find a different way to do what you're trying to do.

Upvotes: 1

Related Questions