Hi all i ave an application with two different databases.
The first db is for our business app, the second belong to a framework we are using.
I have a manager in witch i need to access both dbs to perform some operations.
I configured my app with two entityManagerFactory, one for each datasource, and two transaction managers, one for each entityManagerFactory...
Here my configuration
my 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="ENPIM_BD_PU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>jdbc/businessDataSource</non-jta-data-source>
<class>it.aicof.projects.enpim.persistence.entities.AccountingRecords</class>
.....
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.show_sql" value="false"/>
</properties>
</persistence-unit>
<persistence-unit name="ENPIM_SERV_PU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>it.aicof.projects.enpim.persistence.entities.Authusers</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.show_sql" value="false"/>
</properties>
</persistence-unit>
</persistence>
my app-context.xml
<context:annotation-config/>
<context:component-scan base-package="it.aicof.projects.*"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="dataSourceBusiness" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${profile.database.driverClassName}" />
<property name="jdbcUrl" value="jdbc:postgresql://${profile.database.hostname}:${profile.database.port}/${profile.database.business}" />
<property name="user" value="${profile.database.username}" />
<property name="password" value="${profile.database.password}" />
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
<property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>
<bean id="dataSourceServ" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${profile.database.driverClassName}" />
<property name="jdbcUrl" value="jdbc:postgresql://${profile.database.hostname}:${profile.database.port}/${profile.database.serv}" />
<property name="user" value="${profile.database.username}" />
<property name="password" value="${profile.database.password}" />
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
<property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>
<bean id="transactionManagerBusiness" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory">
<qualifier value="business" />
</bean>
<bean id="transactionManagerServ" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactoryServ">
<qualifier value="serv" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSourceBusiness"
p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<property name="persistenceUnitName" value="ENPIM_BD_PU"></property>
</bean>
<bean id="entityManagerFactoryServ"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSourceServ"
p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<property name="persistenceUnitName" value="ENPIM_SERV_PU"></property>
</bean>
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="POSTGRESQL" p:showSql="false"/>
Here is the code i'm using
my dao
#PersistenceContext(unitName = "ENPIM_BD_PU")
protected EntityManager em;
#PersistenceContext(unitName = "ENPIM_SERV_PU")
protected EntityManager emServ;
....
public void edit(AddressBook addressBook) throws NonexistentEntityException, Exception {
try {
addressBook = em.merge(addressBook);
} catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).error("edit", ex);
String msg = ex.getLocalizedMessage();
if (msg == null || msg.length() == 0) {
Integer id = addressBook.getId();
if (findAddressBook(id) == null) {
throw new NonexistentEntityException("The addressBook with id " + id + " no longer exists.");
}
}
throw ex;
}
}
public void createBeneficiaryLoginAccount(String username, String password) throws Exception{
try {
Query q = emServ.createNativeQuery("INSERT INTO authusers(username, passwd, registrationdate, lastaccess, lastpasswordchange, active)" +
" VALUES (?, ?, ?, ?, ?, ?)");
q.setParameter(1, username);
q.setParameter(2, password);
q.setParameter(3, new Date());
q.setParameter(4, new Date());
q.setParameter(5, new Date());
q.setParameter(6, 1);
q.executeUpdate();
}catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryAccount", ex);
throw ex;
}
}
my manager
#Override
public void createBeneficiaryAccount(AddressBook addressBook, String password) {
String username = addressBook.getUsername();
try {
AddressBook ab = this.addressBookJpaDAO.findAddressBook(addressBook.getId());
ab.setUsername(username);
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.createBeneficiaryLoginAccount(username, password);
this.createBeneficiaryUsername(ab, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("", t);
}
}
#Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class, value = "serv")
private void createBeneficiaryLoginAccount(String username, String password) throws Throwable {
try {
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.addressBookJpaDAO.createBeneficiaryLoginAccount(username, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createLoginAccount", t);
throw t;
}
}
#Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class, value = "business")
private void createBeneficiaryUsername(AddressBook addressBook, String password) throws Throwable {
try {
this.addressBookJpaDAO.edit(addressBook);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryUsername", t);
throw t;
}
}
when the method that uses the second entityManager is called i get the exception
2014-11-26 11:10:35,844 ERROR controllers.AddressBookJpaController - createBeneficiaryAccount
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
.....
and debugging the application i found that when we try to use the second entityManager we have this error
Exception occurred in target VM: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:198)
at com.sun.proxy.$Proxy145.getTransaction(Unknown Source)
at it.aicof.projects.enpim.persistence.controllers.AddressBookJpaController.createBeneficiaryLoginAccount(AddressBookJpaController.java:854)
i take a look on the web for some example but all have the same configuration as mine.
So.. why it's not working?
what's wrong?
thanks in advance
andrea
You're annotating #Transactional at a private method. That doesn't work with the Spring Aop Proxy Beans.
The quickest way is to set both methods to public
#Transactional("serv")
public void createBeneficiaryLoginAccount(String username, String password) throws Throwable {
try {
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.addressBookJpaDAO.createBeneficiaryLoginAccount(username, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createLoginAccount", t);
throw t;
}
}
#Transactional("business")
public void createBeneficiaryUsername(AddressBook addressBook, String password) throws Throwable {
try {
this.addressBookJpaDAO.edit(addressBook);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryUsername", t);
throw t;
}
}
Or you might want to use AspectJ mode for AOP, but that is another layer of headaches IMHO.
See: Does Spring #Transactional attribute work on a private method?
Related
Using Spring, Hibernate and JPA to save employee objects to Oracle 12c. Receive No error when running the SpringDataSiebel "main", but actually not save to database.
<context:component-scan base-package="employee"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#...."/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="jcgPersistence"/>
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation" value="META-INF/persistence.xml"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect" ref="jpaDialect"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<!--prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop-->
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
public class SpringDataSiebel {
public SpringDataSiebel() {
super();
}
public static void main(String[] args) {
//SpringDataSiebel s = new SpringDataSiebel();
try {
ApplicationContext context = new ClassPathXmlApplicationContext("META-INF\\spring-config-siebel.xml");
//Fetch the DAO from Spring Bean Factory
EmployeeDao employeeDao = (EmployeeDao) context.getBean("EmployeeDaoImpl");
Employee employee = new Employee("Employee 320");
int id = 330;
employee.setEmployeeId(id);
//Save an employee Object using the configured Data source
employeeDao.save(employee);
System.out.println("Employee Saved with EmployeeId " + employee.getEmployeeId());
//find an object using Primary Key
Employee emp = employeeDao.findByPrimaryKey(employee.getEmployeeId());
System.out.println("Found: " + emp);
Employee emp2 = employeeDao.findByPrimaryKey(1000);
System.out.println("Found: " + emp2);
//Close the ApplicationContext
((ConfigurableApplicationContext) context).close();
} catch (BeansException | SQLException e) {
e.printStackTrace();
}
}
}
public class EmployeeDaoImpl implements EmployeeDao {
public EmployeeDaoImpl() {
super();
}
#PersistenceContext
private EntityManager entityManager;
//#Override
#Transactional
public void save(Employee employee) {
try {
//if (!entityManager.contains(employee)) {
// persist object - add to entity manager
entityManager.persist(employee);
System.out.println("Saving the employee object...");
//}
} catch (Exception ex) {
System.out.println("Something went wrong.");
ex.printStackTrace();
}
}
}
Output:
Saving the employee object...
Employee Saved with EmployeeId 330
Found: null
Found: null
Process exited with exit code 0.
I expect it finds the object "EmployeeId 330"
i implemented spring application which is running based on schedulers in weblogic 10. server.
while i am deploying it. i am getting above exception.
here is my stack trace
java.lang.SecurityException: [Security:090398]Invalid Subject: principals=[bpm_weblogic, AdminChannelUsers, Administrators, AppTesters, CrossDomainConnectors, Deployers, Monitors, Operators, OracleSystemGroup]
at weblogic.security.service.SecurityServiceManager.seal(SecurityServiceManager.java:833)
at weblogic.security.service.IdentityUtility.authenticatedSubjectToIdentity(IdentityUtility.java:30)
at weblogic.security.service.RoleManager.getRoles(RoleManager.java:183)
at weblogic.security.service.AuthorizationManager.isAccessAllowed(AuthorizationManager.java:375)
at weblogic.jndi.internal.ServerNamingNode.checkPermission(ServerNamingNode.java:442)
at weblogic.jndi.internal.ServerNamingNode.checkLookup(ServerNamingNode.java:423)
at weblogic.jndi.internal.ServerNamingNode.lookupHere(ServerNamingNode.java:180)
at weblogic.jndi.internal.BasicNamingNode.unbind(BasicNamingNode.java:565)
at weblogic.jndi.internal.WLEventContextImpl.unbind(WLEventContextImpl.java:173)
at javax.naming.InitialContext.unbind(InitialContext.java:435)
at com.tcs.controller.BpmController.run(BpmController.java:94)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
my spring application is running in one weblogic environment and i am calling bpm which is running in another weblogic environment.
here if don't call bpm i am not getting exception and if i user dataSource instead of jndi it is working fine.
but the problme is i have to call the bpm and i can't user dataSource configuration in production.
here is my controller class
public String executeBpm(User user) {
IBPMContext context = null;
String status = null;
if (logger.isDebugEnabled()) {
logger.debug("executeBpm method starts");
}
try {
if (user.getUserId() != null && !("").equals(user.getUserId())) {
context = ITBABPMContext.getIBPMContextUsingName(user.getUserId());
}
HashMap<String, Object> elements = (HashMap<String, Object>) user.getMap();
UpdateTaskDetails updates = new UpdateTaskDetails();
if (user.getTaskId() != null && !("").equals(user.getTaskId())) {
updates.setTaskID(user.getTaskId());
}
if (user.getTaskId() != null && !("").equals(user.getTaskId())) {
updates.setTaskOutcome(user.getTaskOutcome());
}
if (user.getUserComment() != null && !("").equals(user.getUserComment())) {
updates.setUserComment(user.getUserComment());
}
if (!elements.isEmpty() && elements.size() > 0) {
updates.setElementList(elements);
}
if (logger.isDebugEnabled()) {
logger.debug("executeBpm method ends");
}
status = ITBAACMUtil.updateTaskOutcome(updates, context);
if (status.equalsIgnoreCase("success")) {
bpmProcessorService.write(user.getUserId(), user.getSeqNo());
}
} catch (ITBABPMRuntimeException e) {
e.printStackTrace();
} catch (BPMServiceClientException e) {
e.printStackTrace();
} catch (BPMException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
return status;
}
my dao class
public void write(String userId,Long seqNo){
try{
String query=messageSource.getMessage(BPMConstants.FAILED_QUERY,new Object[]{Long.toString(seqNo)},Locale.US);
jdbcTemplate.update(query);
}catch(Exception e){
logger.error("exception at updating the status to failed ..");
logger.error(e.getStackTrace());
}
}
here one thing is cross domain mapping is are already there and other applications are running just fine. so i don't think this is the issue with cross domain mapping.
here is my configuration file.
<context:component-scan base-package="com.app" />
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="MCDataSource"/>
</bean>
<bean id="txManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" />
<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
<property name="transactionManagerName" value="javax.transaction.TransactionManager"/>
</bean>
<!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#172.19.8.159:1521/OIM.itba.gov.in" />
<property name="username" value="AppDB"></property>
<property name="password" value="AppDB"></property>
<property name="initialSize" value="2" />
<property name="maxActive" value="5" />
</bean> -->
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>messages</value>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="runScheduler" class="com.app.controller.BpmController" />
<task:scheduled-tasks>
<task:scheduled ref="runScheduler" method="run" cron="0 0/5 * * * ?" />
</task:scheduled-tasks>
Hey it seems your problem is you are not switching the context correctly. Once you open up the IBPM context then you are coming back and trying to lookup on your local jndi tree but you have IBPM context credentials which do not authenticate on your local weblogic. You need to open a new context before you perform a jndi lookup operation to your datasource.
Here is some sample code:
jndiTemplate(org.springframework.jndi.JndiTemplate) { bean ->
bean.scope = "prototype"
environment = [
"java.naming.factory.initial":"weblogic.jndi.WLInitialContextFactory",
"java.naming.security.principal" : "username",
"java.naming.security.credentials": "password"
]
}
dataSource(org.springframework.jndi.JndiObjectFactoryBean){
jndiTemplate = ref(jndiTemplate)
jndiName = "name"
exposeAccessContext=true
}
Then when you want to lookup the jndi you can something like.
Inject the jndiTemplate and:
jndiTemplate.context.getProperties()
Or
InitialContext initialContext = new InitialContext(jndiTemplate.getEnvironment());
You can then close it.
Any help will be greatly appreciated.
We are working on a web application. Which uses a JAR file (a java maven project) and has been added as a maven dependency in the web application.
Combination of this JAR file and web application itself creating problem.
Both web application and JAR are using Hibernate JPA to interact with database. But both are using 2 different ways for creating/initializing entityManagerFactory.
Web Application uses Spring xml based configuration to initialize entityManagerFactory.
CODE:
persistence.xml code:
<persistence-unit name="org.jbpm.persistence.jpa.local"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>META-INF/JBPMorm-JPA2.xml</mapping-file>
<class>org.drools.persistence.info.SessionInfo</class>
<class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>
<class>org.drools.persistence.info.WorkItemInfo</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" />
<property name="hibernate.max_fetch_depth" value="3" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
Spring configuration:
<context:component-scan base-package="com.company.rd.core" />
<context:component-scan base-package="com.company.rd.services" />
<jee:jndi-lookup id="testDataSource" jndi-name="java:comp/env/jdbc/SybaseDB" />
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="testDataSource"/>
<property name="defaultTimeout" value="120"></property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="org.jbpm.persistence.jpa.local" />
<property name="dataSource" ref="testDataSource" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect" ref = "jpaDialect"></property>
<property name="defaultTimeout" value="120"></property>
</bean>
<jee:jndi-lookup id="logDataSource" jndi-name="java:comp/env/jdbc/DRMLOG" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>
And Here is the code to initializing entitymanagerFactory in JAR file.
persistence.xml
<persistence-unit name="codeAuthorization" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>java:/comp/env/jdbc/SybaseDB</non-jta-data-source>
<class>com.company.auth.entity.AuthorizationCode</class>
<class>com.company.auth.entity.UserInvalidAttempt</class>
<class>com.company.auth.entity.AuthorizationProperty</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
And a java file which is injected into Base DAO through spring.
#Service
public class AuthorizationEntityMangerService {
#PersistenceUnit(name = "codeAuthorization")
private EntityManagerFactory entityManagerFactory;
public AuthorizationEntityMangerService() {
entityManagerFactory = Persistence
.createEntityManagerFactory("org.jbpm.persistence.jpa.local");
}
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
public EntityManager getEntityManager() {
return this.entityManagerFactory.createEntityManager();
}
public void closeEntityManager(EntityManager entityManager) {
if (entityManager != null && entityManager.isOpen()) {
entityManager.close();
}
}
public EntityTransaction getTransaction(EntityManager entityManager) {
return entityManager.getTransaction();
}
public void rollBackTransaction(EntityTransaction transaction) {
if (transaction != null && transaction.isActive()) {
transaction.rollback();
}
}
public void commitTransaction(EntityTransaction transaction) {
if (transaction != null && transaction.isActive()) {
transaction.commit();
}
}
}
Calling code from Base DAO.
public Object getSingleResult(final String queryString, final String key,
final NamedQueryParameter namedQueryParameter) {
EntityTransaction transaction = null;
EntityManager entityManager = null;
try {
entityManager = this.entityMangerService.getEntityManager();
transaction = entityMangerService.getTransaction(entityManager);
transaction.begin();
final Query query = entityManager.createQuery(queryString);
setQueryParameter(query, namedQueryParameter);
final Object result = query.getSingleResult();
entityMangerService.commitTransaction(transaction);
return result;
} catch (final NoResultException e) {
entityMangerService.rollBackTransaction(transaction);
logger.error("Error" : " + e.getMessage());
return null;
} finally {
entityMangerService.closeEntityManager(entityManager);
}
}
Now Here is the problem when ever line entityManager.createQuery(queryString); execute it throws the exception.
2015-06-05 17:39:46,363 WARN DefaultExceptionHandler:94 - Unhandled exception caught by the Stripes default
exception handler.
java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: AuthorizationProperty is
not mapped [SELECT pe.value FROM AuthorizationProperty pe WHERE pe.name=:propertyName AND pe.deleted=0]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1364)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:294)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke
(ExtendedEntityManagerCreator.java:334)
at com.sun.proxy.$Proxy53.createQuery(Unknown Source)
at com.company.authentication.dao.AuthorizationBaseDAO.getSingleResult(AuthorizationBaseDAO.java:40)
at com.company.authentication.dao.PropertyDAOImlp.getPropertyValue(PropertyDAOImlp.java:22)
at com.company.authentication.services.AuthorizationPropertyService.getPropertyValueByName
(AuthorizationPropertyService.java:19)
at com.company.rd.servlet.JspAuthorizationRestFilter.hasAuthorizationCode
(JspAuthorizationRestFilter.java:105)
at com.company.rd.servlet.AbstractAuthorizationRestFilter.isRequestAuthenticated
(AbstractAuthorizationRestFilter.java:120)
at com.company.rd.servlet.JspAuthorizationRestFilter.doFilter(JspAuthorizationRestFilter.java:84)
I have debugged the code and found entityManagerFactory for persistenceUnit "codeAuthorization" is not initialized. Only "org.jbpm.persistence.jpa.local" is available (verified through eclipse debugger) inside this method.
Note: This JAR is working fine in some other application where web application and JAR using same way to initialize entityMangerFactory [through Persistence.createEntityManagerFactory("")].
Please let me know How can I get "codeAuthorization" entiryManagerFactory
You are using Spring then use Spring, currently you are doing a lot of work to work around Spring and dependency injection and managed transaction. Don't use Persistence.createEntityManagerFactory(""). Just inject the EntityManager where you need it using an EntityManager field annotated with #PersistenceContext and specify the name of the one you want.
Also don't manage the transactions, entity manager yourself, spring does that for you. For this use the right PlatformTransactionManager the JpaTransactionManager and not the DatasourceTransactionManager as that won't work in a JPA environment. (At least not to manage your JPA transactions).
Doing this will really simplify your code and your life.
So basically ditch the service that is doing those nasty things and simple do things like this in your dao.
#Repository
public class YourDao {
#PersistenceContext(name="codeAuthorization")
private EntityManager em;
#Transactional
public Object getSingleResult(final String queryString, final String key,
final NamedQueryParameter namedQueryParameter) {
final Query query = em.createQuery(queryString);
setQueryParameter(query, namedQueryParameter);
return query.getSingleResult();
}
}
In your configuration replace the DatasourceTransactionManager with the JpaTransactionManager and add <tx:annotation-driven />. Then clean your code.
Note: The JpaTransactionManager is perfectly capable of managing plain JDBC transactions if you still need those, ideally you would have a single transaction manager.
Hi I'm trying a little POC with JPA and unit test to verify that the DB schema is created. I'm working with H2 DB and I set to Hibernate create the schema from the entities, but when DbUnit tries to initialize the DB from a dataset I always get a Table ... not found in tableMap. I read that I have to add the property DB_CLOSE_DELAY=-1 to DB URL but is like after Hibernate creates the schema the DB is losted when DbUnit tries to initialize.
Any ideas? Any help is highly appreciated.
This is my config:
application-context.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceH2" />
<property name="packagesToScan" value="com.xxx.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<!-- property name="databasePlatform" value="org.hibernate.dialect.MySQLInnoDBDialect" /-->
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
<!-- property name="database" value="MYSQL" /-->
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="javax.persistence.validation.mode">CALLBACK</prop>
</props>
</property>
</bean>
<bean id="dataSourceH2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
RepositoryTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/application-context-test.xml" })
#Transactional
public class SystemEntityRepositoryH2Test {
#Inject
private SystemEntityRepository repository;
#Inject
private DataSource dataSourceH2;
private IDatabaseConnection connection;
#Before
public void setUp() throws Exception {
IDatabaseConnection dbUnitCon = null;
dbUnitCon = new DatabaseDataSourceConnection(dataSourceH2, "testdb");
dbUnitCon.getConfig().setProperty(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
IDataSet dataSet = this.getDataSet("dataset-systementity.xml");
DatabaseOperation.INSERT.execute(dbUnitCon, dataSet);
}
#After
public void tearDown() throws Exception {
//DatabaseOperation.DELETE_ALL.execute(this.getConnection(), this.getDataSet(dataSetFile));
}
#Test
public void test() throws Exception {
}
protected IDataSet getDataSet(String dataSetFile) throws Exception {
ResourceLoader resourceLoader = new ClassRelativeResourceLoader(this.getClass());
Resource resource = resourceLoader.getResource(dataSetFile);
if (resource.exists()) {
return new FlatXmlDataSetBuilder().build(resource.getInputStream());
}
return null;
}
}
dataset-systementity.xml
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<System_Entities id="2" name="NAME" phone01="+52-55-55555555" email="a#a.com"
address01="Street" address02="123" address03="1" address04="Address04"
address05="Address05" city="City" state="State" country="MX"
zipcode="12345" />
</dataset>
Error
ERROR DatabaseDataSet:286 - Table 'System_Entities' not found in tableMap=org.dbunit.dataset.OrderedTableNameMap[_tableNames=[], _tableMap={}, _caseSensitiveTableNames=false]
I can see that the tables are created by hibernate because the log shows all the sql sentences without error.
Thanks.
SOLUTION
Thanks Mark Robinson
I modified the setUp method to:
#Before
public void setUp() throws Exception {
IDatabaseConnection dbUnitCon = null;
EntityManager entityManager = entityManagerFactory.createEntityManager();
Session session = entityManager.unwrap(Session.class);
SessionImplementor si = (SessionImplementor) session;
Connection conn = si.getJdbcConnectionAccess().obtainConnection();
dbUnitCon = new DatabaseConnection(conn);
//dbUnitCon.getConfig().setProperty(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
IDataSet dataSet = this.getDataSet("dataset-systementity.xml");
DatabaseOperation.INSERT.execute(dbUnitCon, dataSet);
}
It works now, what I don't understand yet is if I use HSQLDB I don't have this problem.
The problem is that DBUnit is loading the table data before Hibernate can initialize.
As part of your #setup, you'll need to get the Hibernate session. This should cause Hibernate to create your table. You could even force it by executing a simple query like select 1
Is there a way to specify a different web.xml from the standard WEB-INF/web.xml when using an embedded tomcat instance?
I would like to put a web.xml in my src/test/resources (or some other area) and refer to that web.xml when starting the embedded tomcat.
Here is my existing code to start the tomcat instance
tomcat = new Tomcat();
String baseDir = ".";
tomcat.setPort(8080);
tomcat.setBaseDir(baseDir);
tomcat.getHost().setAppBase(baseDir);
tomcat.getHost().setAutoDeploy(true);
tomcat.enableNaming();
Context ctx = tomcat.addWebApp(tomcat.getHost(), "/sandbox-web", "src\\main\\webapp");
File configFile = new File("src\\main\\webapp\\META-INF\\context.xml");
ctx.setConfigFile(configFile.toURI().toURL());
tomcat.start();
I am starting this server from a tomcat instance and I would like to do the following when running unit tests
turn off the contextConfigLocation
specify a custom ContextLoaderListener that sets the parent ApplicationContext of the embedded tomcat.
This file might be specified like so:
File webXmlFile = new File("src\\test\\resources\\embedded-web.xml");
Edit
After much frustration I realized that no matter what I do, I cannot persuade tomcat from looking in WEB-INF for web.xml. It appears that I must ignore the web.xml altogether and set the items in the web.xml programmatically.
I ended up with this configuration:
cucumber.xml for configuring tests
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="applicationContextProvider" class="ca.statcan.icos.sandbox.ApplicationContextProvider"/>
<bean id="sandBoxDataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:testdb;shutdown=true;" />
<property name="username" value="SA" />
<property name="password" value="" />
</bean>
<!-- Support for JPA related annotation support (#PersistenceUnit and #PersistenceContext) -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!-- JTA Configuration -->
<bean id="jtaTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown"><value>true</value></property>
</bean>
<bean id="jtaUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" />
<bean id="springTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="jtaTransactionManager" />
<property name="userTransaction" ref="jtaUserTransaction" />
</bean>
<!-- JPA Entity Manager configuration -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
lazy-init="true">
<property name="persistenceUnitName" value="sandBox" />
<property name="dataSource" ref="sandBoxDataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="SQL_SERVER" />
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
</bean>
</property>
<property name="jpaPropertyMap">
<props>
<prop key="hibernate.archive.autodetection">class</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<!-- Second Level Cache : EHCache in dev
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop> -->
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<import resource="classpath:META-INF/applicationContext-core.xml" />
<import resource="classpath:META-INF/applicationContext-web.xml" />
</beans>
applicationContext-core.xml - where the services are configured
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd"
default-autowire="byName">
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath*:META-INF/fms-local.properties" />
<property name="systemPropertiesModeName">
<value>SYSTEM_PROPERTIES_MODE_OVERRIDE</value>
</property>
</bean>
<!--
Classpath scanning to load all the service classes
-->
<context:component-scan base-package="ca.statcan"
use-default-filters="false">
<context:include-filter type="regex" expression="ca\.statcan\.icos.*\.service\..*Service" />
<context:include-filter type="regex" expression="ca\.statcan\.icos.*\.builders\..*Builder" />
</context:component-scan>
<!--
Spring TransactionManager
-->
<tx:advice id="txAdvice" transaction-manager="springTransactionManager">
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" propagation="SUPPORTS" isolation="DEFAULT"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS" isolation="DEFAULT"/>
<!-- other methods use the default transaction settings -->
<tx:method name="*" read-only="false" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!--
AOP Weaving for all Service methods
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="icosServiceMethods" expression="execution(* ca.statcan.icos..*.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="icosServiceMethods" />
</aop:config>
</beans>
Custom ContextLoaderListener
public class EmbeddedContextLoaderListener extends ContextLoaderListener {
#Override
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
GenericWebApplicationContext context = new GenericWebApplicationContext(sc);
context.setParent(ApplicationContextProvider.getApplicationContext());
return context;
}
#Override
protected ApplicationContext loadParentContext(ServletContext servletContext) {
return ApplicationContextProvider.getApplicationContext();
}
}
Modified Embedded Tomcat Wrapper
public class EmbeddedTomcat {
/** Log4j logger for this class. */
#SuppressWarnings("unused")
private static final Logger LOG = LoggerFactory.getLogger(EmbeddedTomcat.class);
private Tomcat tomcat;
public void start() {
try {
tomcat = new Tomcat();
String baseDir = ".";
tomcat.setPort(8080);
tomcat.setBaseDir(baseDir);
tomcat.getHost().setAppBase(baseDir);
tomcat.getHost().setDeployOnStartup(true);
tomcat.getHost().setAutoDeploy(true);
tomcat.enableNaming();
Context context = tomcat.addContext("/sandbox-web", "src\\main\\webapp");
Tomcat.initWebappDefaults(context);
configureSimulatedWebXml(context);
LOG.info("Starting tomcat in: " + new File(tomcat.getHost().getAppBase()).getAbsolutePath());
tomcat.start();
} catch (LifecycleException e) {
throw new RuntimeException(e);
}
}
public void stop() {
try {
tomcat.stop();
tomcat.destroy();
FileUtils.deleteDirectory(new File("work"));
FileUtils.deleteDirectory(new File("tomcat.8080"));
} catch (LifecycleException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void deploy(String appName) {
tomcat.addWebapp(tomcat.getHost(), "/" + appName, "src\\main\\webapp");
}
public String getApplicationUrl(String appName) {
return String.format("http://%s:%d/%s", tomcat.getHost().getName(),
tomcat.getConnector().getLocalPort(), appName);
}
public boolean isRunning() {
return tomcat != null;
}
private void configureSimulatedWebXml(final Context context) {
// Programmatically configure the web.xml here
context.setDisplayName("Sandbox Web Application");
context.addParameter("org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG", "/WEB-INF/tiles-defs.xml,/WEB-INF/tiles-sandbox.xml");
final FilterDef struts2Filter = new FilterDef();
struts2Filter.setFilterName("struts2");
struts2Filter.setFilterClass("org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter");
struts2Filter.addInitParameter("actionPackages", "ca.statcan.icos.sandbox.web");
context.addFilterDef(struts2Filter);
final FilterMap struts2FilterMapping = new FilterMap();
struts2FilterMapping.setFilterName("struts2");
struts2FilterMapping.addURLPattern("/*");
context.addFilterMap(struts2FilterMapping);
context.addApplicationListener("org.apache.tiles.web.startup.TilesListener");
context.addApplicationListener("ca.statcan.icos.sandbox.EmbeddedContextLoaderListener");
context.addWelcomeFile("index.jsp");
}
}
Step definitions
public class StepDefs {
#Autowired
protected EmployeeEntityService employeeEntityService;
#Given("^the following divisions exist$")
public void the_following_divisions_exist(DataTable arg1) throws Throwable {
final Employee employee = new Employee(3, "Third", "John", null, "613-222-2223");
employeeEntityService.persistEmployee(employee);
}
#Given("^there are no existing surveys$")
public void there_are_no_existing_surveys() throws Throwable {
}
#When("^I register a new survey with the following information$")
public void I_register_a_new_survey_with_the_following_information(DataTable arg1) throws Throwable {
Capabilities capabilities = DesiredCapabilities.htmlUnit();
final HtmlUnitDriver driver = new HtmlUnitDriver(capabilities);
driver.get("http://localhost:8080/sandbox-web/myFirst");
}
#Then("^the surveys are created$")
public void the_surveys_are_created() throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
#Then("^a confirmation message is displayed saying: \"([^\"]*)\"$")
public void a_confirmation_message_is_displayed_saying(String arg1) throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
}
Action class
#Results({ #Result(name = "success", location = "myFirst.page", type = "tiles") })
#ParentPackage("default")
#Breadcrumb(labelKey = "ca.statcan.icos.sandbox.firstAction")
#SuppressWarnings("serial")
public class MyFirstAction extends HappyfActionSupport {
private List<Employee> employees;
#Autowired
private EmployeeEntityService employeeEntityService;
#Override
public String execute() {
employees = employeeEntityService.getAllEmployee();
if (employees.size() == 0) {
// persist data in memory
final Employee employee1 = new Employee(1, "First", "John", null, "613-222-2222");
employeeEntityService.persistEmployee(employee1);
final Employee employee2 = new Employee(2, "Second", "John", null, "613-222-2223");
employeeEntityService.persistEmployee(employee2);
employees = employeeEntityService.getAllEmployee();
}
return SUCCESS;
}
public List<Employee> getEmployees() {
return employees;
}
}
With this, the embedded tomcat starts correctly and all seems to go well until I try to navigate to a web page. In the StepDefs class, the EmployeeEntityService is injected correctly. However, in the Action class, EmployeeEntityservice is not injected (it remains null).
According to my knowledge, I am setting the parent ApplicationContext for the embedded Tomcat correctly. So why isn't the server using the parent context to get the EmployeeEntityService?
I was stuck with a similar problem and the solution for using an alternative web.xml is simpler than one would dare to think:
2 lines:
Context webContext = tomcat.addWebapp("/yourContextPath", "/web/app/docroot/");
webContext.getServletContext().setAttribute(Globals.ALT_DD_ATTR, "/path/to/custom/web.xml");
Voila! The magic happens in org.apache.catalina.startup.ContextConfig#getWebXmlSource
Disclaimer: Tested on Tomcat 7.0.42