Dynamic datasource lookup using JPA - persistence

I want to bind variable dataSourceString(possible value:HR,FINANCE : i am getting dataSourceString value dynamically by jsp) to DataSource. When dataSourceString value is HR then connect to TESTDS and when dataSourceString value is FINANCE then connect to TESTDS1.Means based on dataSourceString value i want to connect to datasource.
Enviornment : EJB3,weblogic10.3.3,JPA
Note:One more thing i dont want to write if-else loop in sessionbean like when dataSourceString is HR then connect to this EnityManage else to different EntityManager.currently there are 10-15 possible value of dataSourceString. I want to write code like if in future if a new dataSourceString is added then only i have to change persistence.xml.
After research i came to the following code,But getting some error.
Error:-
No persistence unit named 'em' is available in scope test.jar. Available persistence units: [HR, FINANCE]
at weblogic.ejb.container.deployer.EJBModule.prepare(EJBModule.java:467)
at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:199)
at weblogic.application.internal.flow.DeploymentCallbackFlow$1.next(DeploymentCallbackFlow.java:507)
at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:41)
at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:149)
Truncated. see log file for complete stacktrace
Caused By: java.lang.IllegalArgumentException: No persistence unit named 'em' is available in scope test.jar. Available persistence units: [HR, FINANCE]
at weblogic.deployment.ModulePersistenceUnitRegistry.getPersistenceUnit(ModulePersistenceUnitRegistry.java:132)
at weblogic.deployment.BasePersistenceContextProxyImpl.<init>(BasePersistenceContextProxyImpl.java:38)
at weblogic.deployment.TransactionalEntityManagerProxyImpl.<init>(TransactionalEntityManagerProxyImpl.java:35)
at weblogic.deployment.BaseEnvironmentBuilder.createPersistenceContextProxy(BaseEnvironmentBuilder.java:974)
at weblogic.deployment.BaseEnvironmentBuilder.addPersistenceContextRefs(BaseEnvironmentBuilder.java:855)
Truncated. see log file for complete stacktrace
Error is obvious that there is no persistence unit for em is available in persistence.xml
But how can i achieve lookup of datasource using jpa dynamically.
Following is my code
Session Bean
package entity.library;
import java.util.Collection;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import java.io.Serializable;
import javax.ejb.*;
#Remote(TestInterface.class)
#Stateless(mappedName="ejb3/TestBeans")
public class TestSessionBean implements Serializable, TestInterface
{
protected TestJPA test;
protected Collection <TestJPA> list;
#PersistenceContext
private EntityManager em;
#PersistenceUnit
private EntityManagerFactory emf;
public Collection <TestJPA> getAllList(String dataSourceString) {
emf = Persistence.createEntityManagerFactory(dataSourceString);
em = emf.createEntityManager();
list=em.createQuery("SELECT test FROM TestJPA test").getResultList();
return list;
}
}
persistence.xml
<persistence version="1.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_1_0.xsd">
<persistence-unit name="HR" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>TESTDS</jta-data-source>
<non-jta-data-source>TESTDS</non-jta-data-source>
<properties>
<property name="eclipselink.target-server" value="WebLogic_10"/>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
<persistence-unit name="FINANCE" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>TESTDS1</jta-data-source>
<non-jta-data-source>TESTDS1</non-jta-data-source>
<properties>
<property name="eclipselink.target-server" value="WebLogic_10"/>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
</persistence>

If there is a single persistence unit defined in persistence.xml, then it default unit for application & the same is is injected by annotation.
You can lookup manually the specific persistence context at runtime.
javax.persistence.EntityManager entityManager =
(javax.persistence.EntityManager)initCtx.lookup(
"java:comp/env/" + persistenceContext);

Even better...
Instead of:
#PersistenceContext(name="myPU")
private EntityManager em;
specify:
#PeristenceContext(unitName="myPU")
private EntityManager em;

Related

No active transaction in EJB #Schedule method

I have an EJB with a #Schedule marked method, that persists an entity to a database. Within this method, when I'm calling EntityManager.flush() after persist(), I'm getting javax.persistence.TransactionRequiredException: No transaction is currently active
AFAIK all EJB methods are transactional, but I'm getting this error even if I additionally mark the method with #TransactionAttribute(REQUIRED).
When I manage a transaction manually by EntityTransaction.begin() and commit(), everything works OK.
I'm using Wildfly 10.0 Final on JDK 8u74, EclipseLink 2.6.0.
Here is my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
<persistence-unit name="mainPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:/datasources/ExampleDS</jta-data-source>
<class>com.example.MyEntity</class>
</persistence-unit>
</persistence>
MyEJB.java:
package com.example;
import javax.ejb.*;
import javax.ejb.Timer;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Startup
#DependsOn("AppUtils")
#Singleton
public class MyEJB {
#PersistenceContext(unitName = "mainPU")
private EntityManager em;
#Schedule(hour = "*", minute = "*", second = "*/20", info = "", persistent = false)
private void doStuff(Timer timer) {
MyEntity entity = new MyEntity("Test" + Math.random(), "Test value");
em.merge(entity);
em.flush();
}
}
When you use JTA it commit and flush the changes into the database and close the current transaction. So, when you do em.flush(), the transaction is already closed.

No [EntityType] was found for the key class [] in the Metamodel - please verify that the [Entity] class was referenced in persistence.xml

java.lang.IllegalArgumentException: No [EntityType] was found for the key class [] in the Metamodel - please verify that the [Entity] class was referenced in persistence.xml using a specific <class> </class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.entityEmbeddableManagedTypeNotFound(MetamodelImpl.java:173)
Entity class:
#Entity
#Table(name="temp_param")
public class ParamConfiguration implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "param_group")
private String paramGroup;
public String getParamGroup() {
return paramGroup;
}
public void setParamGroup(String paramGroup) {
this.paramGroup = paramGroup;
}
DAO code:
CriteriaQuery<ParamConfiguration> cq = entityManager
.getCriteriaBuilder()
.createQuery(ParamConfiguration.class);
final Root<ParamConfiguration> ac = cq.from(ParamConfiguration.class);
cq.select(ac);
TypedQuery<ParamConfiguration> tq=entityManager.createQuery(cq);
List<ParamConfiguration> AClist=tq.getResultList();
persistance xml:
<persistence-unit name="serCoupons_Cdm" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>java:/comp/env/jdbc/CDM</non-jta-data-source>
<class>net.odcorp.sas.mrm.beans.AffinityConfiguration</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
Can anyone help me on this.... Is the #entity class must have all the columns in the DB table.
FYI im using Teradata as DB, Spring, JPA, JSF.
Your ParamConfiguration entity is not listed in the persistence.xml file and you set the option exclude-unlisted-classes to true
add this to your persistence.xml file :
<class>net.odcorp.sas.mrm.beans.ParamConfiguration</class>
be sure that the package is ok.
Try this in your persistence.xml file,
<persistence-unit name="serCoupons_Cdm" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>jdbc/CDM</non-jta-data-source>
<exclude-unlisted-classes>false<exclude-unlisted-classes/>
exclude-unlisted-classes has true as it's default value. or if its set to true, then you need to specify the tag manually to list the entity class,
<class>com.package.Class</class>
I had the same issue, but in my case I was missing the
#Table annotation. Also in my code don't use #Column annotation, I use #GeneratedValue(strategy= GenerationType.IDENTITY) right below #Id. It works for me without using
<exclude-unlisted-classes>true</exclude-unlisted-classes>
I can provide my source code since I've just been using to learn about JPA.

My entities are not persisting showing javax.persistence.TransactionRequiredException

I have recently migrated to JPA 2.0 (EclipseLink 2.4.2 Juno) in TomEE 1.7 in Eclipse IDE, As i am storing the values they are getting stored and retrieved fine, but they are not persisting into the database when is use entitymanager.flush()it is showing javax.persistence.TransactionRequiredException Here is my code
Create.java (register method)
public static int register(String first, String last, String email,
String date, String phone, String address, String pin, Login login) {
try {
System.out.println("registering persisting the entity");
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("FirstEE");
EntityManager manager = emf.createEntityManager();
manager.getTransaction().begin();
//
// Query query = manager
// .createQuery("select l from Truck l");
Login log = login;
System.out.println(log.getUsername() + "username"
+ log.getPassword() + "password");
User reg = new User();
reg.setLogin(log);
reg.setDate(date);
reg.setEmail(email);
reg.setFirst(first);
reg.setLast(last);
reg.setPhone(phone);
reg.setAddress(address);
reg.setPin(pin);
manager.persist(reg);
manager.getTransaction().commit();
manager.flush();
manager.close();
emf.close();
// FacesContext.getCurrentInstance().addMessage("reg:result",
// new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error Message",
// "Registered Successfully"));
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage(
"Registered Successfully");
facesContext.addMessage(null, facesMessage);
System.out.println("after message global");
return 1;
} catch (Exception e) {
System.out.println("hai this is exception caught:" + e);
System.out.println("hai" + e.getMessage());
FacesContext.getCurrentInstance().addMessage(
"reg:result",
new FacesMessage("Something went wrong",
"\tSomething went wrong\t"));
// FacesContext facesContext = FacesContext.getCurrentInstance();
// FacesMessage facesMessage = new
// FacesMessage("Something went wrong");
// facesContext.addMessage(null, facesMessage);
}
return 0;
}
persistence.xml
<?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="FirstEE" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>FirstEE</non-jta-data-source>
<!-- <exclude-unlisted-classes>false</exclude-unlisted-classes> -->
<class>com.jason.Entity.User</class>
<class>com.jason.ManagedBean.Login</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/yash" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="root" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="eclipselink.logging.level" value="FINEST" />
<property name="eclipselink.ddl-generation" value="create-tables" />
</properties>
</persistence-unit>
</persistence>
I cant figure out the problem data is getting retreived and stored but it is not updating and not getting persisted in database
The commit()method is committing your transaction immediately. Therefore, the changes are writting into the database & your previously open transaction also ends in this moment. When you call flush() afterwards, there is no open transaction so the flush() operation - complains as you experience it - with a javax.persistence.TransactionRequiredException. See also javax.persistence
Interface EntityManager#flush()
void flush()
Synchronize the persistence context to the underlying database.
Throws:
TransactionRequiredException - if there is no transaction
You should call the commit() method after you synced the state of your EntityManager, like so
manager.getTransaction.begin();
// ...
// do something with your entities in between
// ...
manager.persist(reg);
manager.flush(); // in your case: could also be skipped
// finally - if nothing fails - we are safe to commit
manager.getTransaction().commit();
Another hint:
You should avoid to mix your UI-side code (JSF...) with Backend code. This is generally considered 'spaghetti' anti-pattern here.
Moreover, do not open and close EntityManagerFactory every time (!) you call this UI-bound method (register(...)), as this is a performance killer - at least it produces unnecessary processing every time somebody tries to register here. At least, you should create an instance of EntityManagerFactory (or: EntityManager) as a field (via a DBService class) and reuse this to communicate with the application backend.
The error indicates you cant call flush outside of a transaction. Your code clearly shows you are calling flush right after calling manager.getTransaction().commit(). There is no need to call flush after commit, since the entityManager synchronizes to the database on commit or flush. You only use flush if you have a long running transaction and you want to synchronize at particular stages.
For the rest, turn on EclipseLink logging https://wiki.eclipse.org/EclipseLink/Examples/JPA/Logging and it will show you want it is doing on the commit/flush calls.

Spring Data MongoDB: Unit tests with repositories

How is it supposed to build some tests with the repository approach in Spring Data MongoDB? I would like to set the test database for my tests since I don't want to use the production database for this purpose. It should be probably possible but I have no idea. This is my application context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xsi:schemaLocation=
"http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/data/neo4j
http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd">
<!-- Default bean name is 'mongo' -->
<mongo:mongo host="${mongo.host}" port="${mongo.port}">
<mongo:options connections-per-host="8"
threads-allowed-to-block-for-connection-multiplier="4"
connect-timeout="${mongo.connect-timeout}"
max-wait-time="${mongo.max-wait-time}"
auto-connect-retry="true"
socket-keep-alive="true"
socket-timeout="${mongo.socket-timeout}"
slave-ok="true"
write-number="1"
write-timeout="0"
write-fsync="true"/>
</mongo:mongo>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo" />
<constructor-arg name="databaseName" value="${mongo.db}" />
</bean>
<context:component-scan base-package="domain.company.group.project.data.repositories"/>
<!-- MongoDB repositories -->
<mongo:repositories base-package="domain.company.group.project.data.repositories.mongodb"/>
<!-- some other stuff -->
</beans>
And let's say I have a simple repository as follows:
public interface LocationRepository extends MongoRepository<Location, String>, LocationRepositoryCustom {
}
where LocationRepositoryImpl is the class implementing all my custom methods for a certain Location (domain object) class. My test class looks like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"/test-context.xml"})
public class LocationRepositoryTest {
#Autowired
private LocationRepository locationRepository;
/* Some tests... */
}
I have tried to embed a MongoDB instance within my running tests (as explained here) but it does not work: the connection to the test database is established but the mongo template seems not able to be overwritten as all save methods keep inserting data to the "production" database.
I am using Spring 3.2.0 and Spring Data Mongo 1.1.0.RELEASE. I am using Junit for testing.
Any suggestions?
Thank you in advance.
Jaranda,
I faced the same problem last week and coincidentally I heard about Fongo, "an in-memory java implementation of mongo."
So I decide to use it to test my custom repositories and worked perfectly to me. Below is an example of how to configure Spring to use Fongo in JUnit tests. Note that I'm not using xml configuration.
Hope that will be useful!
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class LocationRepositoryTest {
private static final String PLAYER_ID = ObjectId.get().toString();
#Autowired private LocationRepositoryCustom playerRepository;
#Autowired private MongoTemplate mongoTemplate;
/* Some tests... */
#Configuration
static class LocationRepositoryTestConfiguration {
#Bean
public Mongo mongo() {
// Configure a Fongo instance
return new Fongo("mongo-test").getMongo();
}
#Bean
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongo(), "collection-name");
}
#Bean
public LocationRepositoryCustom playerRepository() {
// This is necessary if MongoTemplate is an argument of custom implementation constructor
return new LocationRepositoryCustomImpl(mongoTemplate());
}
}
}

Lookup multiple datasource in ejb3.0

I am looking up multiple datasource, depending an value of x In EJB 3.0.
To do this I have written following code.
Session Bean
package entity.library;
import java.util.Collection;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.io.Serializable;
import javax.ejb.*;
#Remote(TestInterface.class)
#Stateless(mappedName="ejb3/TestBeans")
public class TestSessionBean implements Serializable, TestInterface {
/**
*
*/
private static final long serialVersionUID = 1L;
#PersistenceContext(unitName="EntityBeanDS1")
EntityManager emds1;
#PersistenceContext(unitName="EntityBeanDS2")
EntityManager emds2;
protected TestJPA test;
protected Collection <TestJPA> list;
public Collection <TestJPA> getAllList(int x) {
System.out.println("TestInterface.java:getAllPmns x "+x);
if(x==1)
{
System.out.println("going to lookup datasource1");
list=emds1.createQuery("SELECT test FROM TestJPA test").getResultList();
}
else if(x==2)
{
System.out.println("going to lookup datasource2");
list=emds2.createQuery("SELECT test FROM TestJPA test").getResultList();
}
return list;
}
}
Persitence.xml
<persistence version="1.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_1_0.xsd">
<persistence-unit name="EntityBeanDS1" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>TESTDS</jta-data-source>
<non-jta-data-source>TESTDS</non-jta-data-source>
<properties>
<property name="eclipselink.target-server" value="WebLogic_10"/>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
<persistence-unit name="EntityBeanDS2" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>TESTDS1</jta-data-source>
<non-jta-data-source>TESTDS1</non-jta-data-source>
<properties>
<property name="eclipselink.target-server" value="WebLogic_10"/>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
</persistence>
Above code is working successfully.but i think this is not a good tech for following reasons.
1. There are 10-15 multiple session beans, in each bean i have to write if-else for lookup of datasource.
2. In future if new data source is added or any newvalue of x is added, then i have to modify all 10-15 files.
Can one give me code , for connecting to multiple data source such that i change a single file for any change in value of x.
How that single file will look like so that i can retrieve 'EntityManager' object. or there is any other method (like modification in persistence.xml) to do this?
You could inject both entity managers into another session bean (QueryBean) and inject QueryBean into your session beans instead of the entity managers themselves. Then delegate the query creation to QueryBean. This bean then decides which entity manager to use depending on the value of x.
When adding another entity manager or a new value of x you just have to adjust QueryBean.