Spring MVC multiple data sources JTA atomikos in same transaction - spring

I have a Spring MVC project with Hibernate (Spring 4.2.2 - Hibernate 4.3.6). I wanted to connect two datasources (two different postgresql databases) to it, so I used atomikos as implementation for JTA. I have my configuration all by annotations, so the Configuration file is this:
#Configuration
#PropertySource(value = { "classpath:hibernate.properties" })
public class HibernateConfig {
#Autowired
private Environment environment;
// First DB connection
#Primary
#Bean(name = "sessionFactory")
#DependsOn("setMyAtomikosSystemProps")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "org.spring.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean(name = "statsSessionFactory")
#DependsOn("setMyAtomikosSystemProps")
public LocalSessionFactoryBean statsSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(statsDataSource());
sessionFactory.setPackagesToScan(new String[] { "org.spring.stats.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Primary
#Bean(name = "dataSource")
public DataSource dataSource() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
ds.setUniqueResourceName("first");
ds.setXaDataSourceClassName("org.postgresql.xa.PGXADataSource");
ds.setXaProperties(dataSourceProperties("first"));
ds.setMinPoolSize(5);
ds.setMaxPoolSize(75);
ds.setMaxIdleTime(60 * 15);
return ds;
}
#Bean(name = "statsDataSource")
public DataSource statsDataSource() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
ds.setUniqueResourceName("second");
ds.setXaDataSourceClassName("org.postgresql.xa.PGXADataSource");
ds.setXaProperties(dataSourceProperties("second"));
ds.setMinPoolSize(5);
ds.setMaxPoolSize(75);
ds.setMaxIdleTime(60 * 15);
return ds;
}
private Properties dataSourceProperties(String database) {
Properties p = new Properties();
p.setProperty("user", environment.getRequiredProperty("hibernate.connection.username"));
p.setProperty("password", environment.getRequiredProperty("hibernate.connection.password"));
p.setProperty("serverName", environment.getRequiredProperty("hibernate.connection.url"))
p.setProperty("portNumber", environment.getRequiredProperty("hibernate.connection.port"))
p.setProperty("databaseName", database);
return p;
}
#Bean(name = "userTransactionService")
#DependsOn("setMyAtomikosSystemProps")
public UserTransactionService userTransactionService() {
UserTransactionServiceImp uts = new UserTransactionServiceImp();
Properties prop = new Properties();
prop.setProperty("com.atomikos.icatch.service", "com.atomikos.icatch.standalone.UserTransactionServiceFactory");
uts.init(prop);
return uts;
}
#Bean
#DependsOn("userTransactionService")
public UserTransactionManager AtomikosTransactionManager() {
UserTransactionManager utm = new UserTransactionManager();
utm.setForceShutdown(true);
utm.setStartupTransactionService(false);
return utm;
}
#Bean
#DependsOn("userTransactionService")
public UserTransaction AtomikosUserTransaction() {
UserTransactionImp ut = new UserTransactionImp();
try {
ut.setTransactionTimeout(300);
} catch (SystemException e) {
e.printStackTrace();
}
return ut;
}
#Bean
#DependsOn("userTransactionService")
public PlatformTransactionManager JtaTransactionManager() {
JtaTransactionManager jtaTM = new JtaTransactionManager();
jtaTM.setTransactionManager(AtomikosTransactionManager());
jtaTM.setUserTransaction(AtomikosUserTransaction());
jtaTM.setAllowCustomIsolationLevels(true);
return jtaTM;
}
// SharedProperties
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
// JTA
properties.put("hibernate.current_session_context_class", "jta");
properties.put("hibernate.transaction.factory_class", "org.hibernate.transaction.JTATransactionFactory");
properties.put("hibernate.transaction.jta.platform", "com.atomikos.icatch.jta.hibernate4.AtomikosPlatform");
return properties;
}
#Bean
public MethodInvokingFactoryBean setMyAtomikosSystemProps() {
MethodInvokingFactoryBean mifb = new MethodInvokingFactoryBean();
Properties p = new Properties();
p.setProperty("com.atomikos.icatch.hide_init_file_path", "true");
p.setProperty("com.atomikos.icatch.no_file", "true");
mifb.setArguments(new Object[] { p });
mifb.setTargetObject(java.lang.System.getProperties());
mifb.setTargetMethod("putAll");
return mifb;
}
}
This configuration works if the transaction involves only one datasource, but if I create a Service that wants get data from both, I receive this error:
GRAVE: Servlet.service() for servlet [dispatcher] in context with path [/api] threw exception [Request processing failed; nested exception is org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Prepare: NO vote] with root cause
com.atomikos.icatch.RollbackException: Prepare: NO vote
at com.atomikos.icatch.imp.ActiveStateHandler.prepare(ActiveStateHandler.java:202)
at com.atomikos.icatch.imp.CoordinatorImp.prepare(CoordinatorImp.java:523)
at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:687)
at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:282)
at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:172)
at com.atomikos.icatch.jta.TransactionManagerImp.commit(TransactionManagerImp.java:414)
at com.atomikos.icatch.jta.UserTransactionImp.commit(UserTransactionImp.java:86)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1021)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy91.findById(Unknown Source)
But this is NOT a timeout problem because the response come in few seconds.
I receive also a very long list of errors from postgres. I'm "filtering" the errors:
WARN XAResourceTransaction - XA resource 'second': rollback for XID '3139322E3136382E322E322E746D313438373639323737373736333030303032:3139322E3136382E322E322E746D32' raised -4: the supplied XID is invalid for this XA resource
org.postgresql.xa.PGXAException: Errore durante il «rollback» di una transazione preparata
(this one is in italian, it says "error during the "rollback" of a prepared transaction)
Caused by: org.postgresql.util.PSQLException: ERROR: prepared transactions are disabled
Suggerimento: Set max_prepared_transactions to a nonzero value.
Caused by: org.postgresql.util.PSQLException: ERROR: prepared transactions are disabled
Suggerimento: Set max_prepared_transactions to a nonzero value.
ERROR XAResourceTransaction - XA resource 'first': prepare for XID '3139322E3136382E322E322E746D313438373639323737373736333030303032:3139322E3136382E322E322E746D33' raised -3: the XA resource detected an internal error
org.postgresql.xa.PGXAException: Error in preparing transaction
So it seems it needs prepared transaction, but because only for transaction that include both of them? And it is mandatory enable them? Can I avoid this?

You have to edit your postgresql.conf file, find max_prepared_transactions and uncomment It (remove the # at the beginning of the line) and set a reasonable value.
See : https://www.postgresql.org/docs/9.4/static/runtime-config-resource.html

Related

Access denied to resource: type=<jms>, application=JMSModule, destinationType=queue, resource=test, action=receive

I'm try to receive a weblogic server jms in spring boot . But I have encountered this problem after launch application successfully.
[]org.springframework.jms.listener.DefaultMessageListenerContainer:handleListenerSetupFailure(892): Setup of JMS message listener invoker failed for destination 'jms/test' - trying to recover. Cause: Access denied to resource: type=<jms>, application=JMSModule, destinationType=queue, resource=ns-alert-test, action=receive
And I found it can be connect successfully in thread of [main] when launching.
It looks like the username and password is missed when thread changed
[main] org.springframework.jndi.JndiObjectFactoryBean:lookup(112): Located object with JNDI name [jms/rtsConnectionFactory]
And I'm try to use wlfullclient.jar and wlclient.jar and wlthint3client.jar in my project . But the problem still exists. Can you give me some suggest of this problem . Below is my code
Config:
#Autowired
private JmsErrorHandler jmsErrorHandler;
#Autowired
private JMSPropertiesConfig jmsPropertiesConfig;
#Bean
public JndiTemplate jndiTemplate(){
JndiTemplate jndiTemplate =new JndiTemplate();
Properties properties = new Properties();
properties.setProperty("java.naming.factory.initial","weblogic.jndi.WLInitialContextFactory");
properties.setProperty("java.naming.provider.url", jmsPropertiesConfig.getUrl());
if(jmsPropertiesConfig.getUname()!=null){
properties.setProperty("username", jmsPropertiesConfig.getUname());
}
if(jmsPropertiesConfig.getUcert()!=null){
properties.setProperty("password", jmsPropertiesConfig.getUcert());
}
jndiTemplate.setEnvironment(properties);
return jndiTemplate;
}
#Bean
public JndiDestinationResolver jmsDestionationProvider() {
JndiDestinationResolver destinationResolver = new JndiDestinationResolver();
destinationResolver.setJndiTemplate(jndiTemplate());
return destinationResolver;
}
#Bean
public JndiObjectFactoryBean connectionFactory(){
JndiObjectFactoryBean cf = new JndiObjectFactoryBean();
cf.setJndiTemplate(jndiTemplate());
cf.setJndiName(jmsPropertiesConfig.getFactory());
return cf;
}
#Bean
public JmsTemplate jmsTemplate(){
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory((ConnectionFactory) connectionFactory().getObject());
template.setSessionAcknowledgeModeName("AUTO_ACKNOWLEDGE");
template.setSessionTransacted(true);
template.setDestinationResolver(jmsDestionationProvider());
return template;
}
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory((ConnectionFactory) connectionFactory().getObject());
factory.setDestinationResolver(jmsDestionationProvider());
factory.setErrorHandler(jmsErrorHandler);
factory.setSessionAcknowledgeMode(0);
return factory;
}
Receive:
#JmsListener(destination = "jms/test")
public void receiveApplicationNotification(String input) throws Exception {
log.info("Receiving message from jms.external.ExampleQueue.queue "+input);
}
Seems to be a bug in Weblogic.
Can you please try applying below patch..
Bug 22550927 - WEBLOGIC JMS CONNECTION IS NOT THREAD-SAFE

Hibernate JNDI lookup for WebLogic is throwing unable to resolve

I have configured a datasource configured on Oracle Weblogic 12.1.3 and trying to lookup this datasource in a Spring MVC application.
// Weblogic configuration
Datasource Name in weblogic : Admin Data Source
JNDI Name : bsh/AdminDS
// Spring MVC Configuration
#Bean
public DataSource getDataSourceUsingJndi() throws NamingException {
return (DataSource) new JndiTemplate().lookup("bsh/AdminDS"); // 1st way
}
#Bean
public LocalSessionFactoryBean sessionFactory() throws NamingException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSourceUsingJndi());
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put(AvailableSettings.DIALECT, hibernateDialect);
properties.put(AvailableSettings.SHOW_SQL, showSql);
properties.put(AvailableSettings.FORMAT_SQL, formatSql);
return properties;
}
I am getting the below stacktrace:
Caused by: javax.naming.NameNotFoundException: Unable to resolve 'bsh.AdminDS'. Resolved 'bsh'; remaining name 'AdminDS'
at weblogic.jndi.internal.BasicNamingNode.newNameNotFoundException(BasicNamingNode.java:1180)
at weblogic.jndi.internal.BasicNamingNode.lookupHere(BasicNamingNode.java:270)
at weblogic.jndi.internal.ServerNamingNode.lookupHere(ServerNamingNode.java:187)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:210)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:224)
at weblogic.jndi.internal.WLEventContextImpl.lookup(WLEventContextImpl.java:253)
at weblogic.jndi.internal.WLContextImpl.lookup(WLContextImpl.java:426)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at org.springframework.jndi.JndiTemplate.lambda$lookup$0(JndiTemplate.java:156)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:91)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:156)
at com.bsh.config.WebConfig.getDataSourceUsingJndi(WebConfig.java:68)
I tried different ways to lookup - 2nd way
public DataSource getDataSourceUsingJndi() {
JndiDataSourceLookup jndiLookup = new JndiDataSourceLookup();
jndiLookup.setResourceRef(true);
return jndiLookup.getDataSource("bsh/AdminDS");
}
Is there anything wrong with my configuration ?

Spring Boot Dual data configuration, unable to reconnect after connection lost

I am working on application written in spring Boot 1.5.3. I have two data source which are configured as below.
Main connection
spring.datasource.driverClassName = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://xxx.xxx.xxx.xx:5432/mydb
spring.datasource.username = xxxx
spring.datasource.password = xxxx
spring.jpa.properties.hibernate.default_schema=test
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=150
spring.datasource.tomcat.max-idle=30
spring.datasource.tomcat.min-idle=2
spring.datasource.tomcat.initial-size=3
# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.test-on-connect=true
spring.datasource.time-between-eviction-runs-millis=60000
#spring.datasource.tomcat.validation-query-timeout=1000
spring.datasource.tomcat.validation-query=SELECT 1
spring.datasource.tomcat.validation-interval=1000
spring.datasource.tomcat.remove-abandoned=true
spring.datasource.tomcat.remove-abandoned-timeout=55
spring.datasource.tomcat.test-while-idle=true
spring.datasource.tomcat.min-evictable-idle-time-millis = 55000
spring.datasource.tomcat.time-between-eviction-runs-millis = 34000
Second Connection
spring.rdatasource.driverClassName = org.postgresql.Driver
spring.rdatasource.url = jdbc:postgresql://xxx.xxx.xxx.xx:5432/mydb1
spring.rdatasource.username = xxxx
spring.rdatasource.password = xxxx
spring.jpa.properties.hibernate.default_schema=test
# Number of ms to wait before throwing an exception if no connection is available.
spring.rdatasource.tomcat.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.rdatasource.tomcat.max-active=150
spring.rdatasource.tomcat.max-idle=30
spring.rdatasource.tomcat.min-idle=2
spring.rdatasource.tomcat.initial-size=3
# Validate the connection before borrowing it from the pool.
spring.rdatasource.tomcat.test-on-borrow=true
spring.rdatasource.tomcat.test-on-connect=true
spring.rdatasource.time-between-eviction-runs-millis=60000
#spring.rdatasource.tomcat.validation-query-timeout=1000
spring.rdatasource.tomcat.validation-query=SELECT 1
spring.rdatasource.tomcat.validation-interval=1000
spring.rdatasource.tomcat.remove-abandoned=true
spring.rdatasource.tomcat.remove-abandoned-timeout=55
spring.rdatasource.tomcat.test-while-idle=true
spring.rdatasource.tomcat.min-evictable-idle-time-millis = 55000
spring.rdatasource.tomcat.time-between-eviction-runs-millis = 34000
I am working in in VPN environment. When I run application, application is working fine. But the issue starts when I disconnect the VPN and reconnect the VPN.again, my application won't reconnect to data source again. Instead I always getting exception.
But working single database when leave connection handling to spring itself and I do not perform any database configuration.
Update
#Configuration
#PropertySource({ "classpath:application.properties" })
#EnableJpaRepositories(
basePackages = {"com.services.persistence"},
entityManagerFactoryRef = "entityManager",
transactionManagerRef = "transactionManager"
)
#ComponentScan("com.services.persistence")
#EnableTransactionManagement
public class DBConfig {
#Autowired private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean entityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(userDataSource());
em.setPackagesToScan(
new String[] { "com.services.persistence", "com.services.persistence.pojo" });
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
// properties.put("hibernate.hbm2ddl.auto",
// env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",
env.getProperty("spring.jpa.database-platform"));
properties.put("hibernate.current_session_context_class",
env.getProperty("spring.jpa.properties.hibernate.current_session_context_class"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource userDataSource() {
return DataSourceBuilder
.create()
.build();
}
#Primary
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
entityManager().getObject());
return transactionManager;
}
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory() {
SessionFactory sessionFactory = transactionManager().getEntityManagerFactory().unwrap(SessionFactory.class);
if (sessionFactory == null) {
throw new NullPointerException("factory is not a hibernate factory");
} else {
System.out.println(
"==================================== Transaction Enabled ========================================");
return sessionFactory;
}
}
I have also configured spring.rdatasource and it is same as above file, except it is not set as primary and other further details like pojo, transactionmanager etc.

spring batch not rolling on runtime exception in itemwriter

I am new to spring batch and I have a spring batch with spring data project with oracle database. Basically for simplicity I have 2 steps :
Step 1 : Read the first row of the csv file than insert in table_header in itemwriter
Step 2 : Read from the second row of the csv file than insert in table_detail in itemwriter.
The table_header is linked to table_detail - one to many relationship.
Basically if a runtime exception in triggered in step 2 just after saving the detail while in the same step the data does not roll back.According to spring reference it should roll back on runtime exception.
I am not sure what i am missing in order for the transaction to rollback, can someone point me to the right direction pls?
Please find below my database configuration:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "dummyEntityManager", transactionManagerRef = "dummyTransactionManager", basePackages = {
"com.dummy.persistence" })
#PropertySource("file:${test_PROPERTIES}")
public class DatabaseConfig extends HikariConfig {
#Bean(name = "dummyDatasource")
public HikariDataSource dataSource() {
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setJdbcUrl(CipherWrapper.getInstance().decrypt(jdbcUrl));
hikariDataSource.setUsername(CipherWrapper.getInstance().decrypt(username));
hikariDataSource.setPassword(CipherWrapper.getInstance().decrypt(password));
hikariDataSource.setAutoCommit(false);
hikariDataSource.setMaximumPoolSize(maximumPoolSize);
hikariDataSource.setMinimumIdle(minimumIdle);
return hikariDataSource;
}
#Bean(name = "dummyEntityManager")
public LocalContainerEntityManagerFactoryBean dummyEntityManagerFactory(EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = builder.dataSource(dataSource())
.packages("com.dummy.persistence.entity").persistenceUnit("dummyPersistenceUnit").build();
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return localContainerEntityManagerFactoryBean;
}
#Bean(name = "dummyTransactionManager")
public PlatformTransactionManager dummyTransactionManager(
#Qualifier("dummyEntityManager") EntityManagerFactory dummyEntityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(dummyEntityManagerFactory);
jpaTransactionManager.setRollbackOnCommitFailure(true);
return jpaTransactionManager;
}
#Bean
public BatchConfigurer batchConfigurer(#Qualifier("dummyEntityManager") EntityManagerFactory dummyEntityManagerFactory) {
return new DefaultBatchConfigurer() {
#Override
public PlatformTransactionManager getTransactionManager() {
return dummyTransactionManager(dummyTransactionManager);
}
};
}
}
Please find below both step config:
#Bean("step1")
public Step headerSaveStep() {
StepBuilder stepBuilder = stepBuilderFactory.get(Flow.STEP1.toString());
SimpleStepBuilder<HeaderDetailsDto,HeaderDetailsAdditionaDto> simpleStepBuilder = stepBuilder
.<HeaderDetailsDto, HeaderDetailsAdditionaDto>chunk(1);
simpleStepBuilder.reader(csvItemReader.csvFileVatPayerDetailsItemReader(null));
simpleStepBuilder.processor(EnrichmentProcessor());
simpleStepBuilder.writer(headerWriter());
simpleStepBuilder.allowStartIfComplete(true);
return simpleStepBuilder.build();
}
#Bean("step2")
public Step detailSaveStep() {
StepBuilder stepBuilder = stepBuilderFactory.get(Flow.STEP2.toString());
SimpleStepBuilder<DetailsDto, DetailsDto> simpleStepBuilder = stepBuilder
.<DetailsDto, DetailsDto>chunk(20000);
simpleStepBuilder.reader(csvItemReader.csvFileBuyerDetailsFileItemReader(null));
simpleStepBuilder.writer(detailsWriter());
simpleStepBuilder.allowStartIfComplete(true);
return simpleStepBuilder.build();
}
Your transaction manager is not being used by Spring Batch. You need to define a BatchConfigurer bean referring to it (See example here). Hope this helps.

Spring Boot + Camel JPA with multiple Datasources

I need to create a Camel route that polls a DB, transforms the retrieved data and then inserts the new entities into another DB. I need help with the configuration.
These are the jpa endpoints:
from("jpa://" + Entity1.class.getName()
+ "?"
+ "persistenceUnit=entity1PU&"
+ "consumer.namedQuery=query1&"
+ "consumeDelete=false"
)
//various operations...
.to("direct:route2");
from("direct:route2")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
//processing...
}
})
.to("jpa://" + Entity2.class.getName()
+ "?"
+ "persistenceUnit=entity2PU&"
+ "entityType=java.util.ArrayList&"
+ "usePersist=true&"
+ "flushOnSend=true");
I'd like to configure the persistence units by code and annotations, instead of using persistence.xml; these are the relative classes. This is the first:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.foo.entity1.repo",
entityManagerFactoryRef = "entity1EntityManagerFactory",
transactionManagerRef = "entity1TransactionManager"
)
public class Entity1PersistenceConfig {
#Autowired
#Qualifier("datasource1")
private DataSource dataSource;
#Primary
public DataSource dataSource() {
return this.dataSource;
}
#Primary
#Bean(name="entity1EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.foo.entity1.domain");
factory.setDataSource(this.dataSource());
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPersistenceUnitName("entity1PU");
Properties hibernateProps = setJpaHibernateCommonProperties();
hibernateProps.setProperty("hibernate.dialect", environment.getProperty("spring.jpa.properties.hibernate.oracle.dialect"));
factory.setJpaProperties(hibernateProps);
return factory;
}
#Primary
#Bean(name="entity1TransactionManager")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
}
and the second one:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.foo.entity2.repo",
entityManagerFactoryRef = "entity2EntityManagerFactory",
transactionManagerRef = "entity2TransactionManager"
)
public class Entity2PersistenceConfig {
#Autowired
#Qualifier("datasource2")
private DataSource dataSource;
public DataSource dataSource() {
return this.dataSource;
}
#Bean(name="entity2EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.foo.entity2.domain");
factory.setDataSource(this.dataSource());
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPersistenceUnitName("entity2PU");
Properties hibernateProps = setJpaHibernateCommonProperties();
hibernateProps.setProperty("hibernate.dialect", environment.getProperty("spring.jpa.properties.hibernate.mysql.dialect"));
factory.setJpaProperties(hibernateProps);
return factory;
}
#Bean(name="entity2TransactionManager")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
}
Entities and repositories are in the correct packages; also, the configuration of the databases is correctly done in a specific class, and are correctly injected.
When I try to run the project, I get the following:
2018-05-30 11:38:36.481 INFO 1056 --- [main] o.h.j.b.internal.PersistenceXmlParser: HHH000318: Could not find any META-INF/persistence.xml file in the classpath
and
javax.persistence.PersistenceException: No Persistence provider for EntityManager named entity1PU
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:61) ~[hibernate-jpa-2.1-api-1.0.0.Final.jar:1.0.0.Final]
at org.springframework.orm.jpa.LocalEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalEntityManagerFactoryBean.java:96) ~[spring-orm-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:384) ~[spring-orm-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:371) ~[spring-orm-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.apache.camel.component.jpa.JpaEndpoint.createEntityManagerFactory(JpaEndpoint.java:552) ~[camel-jpa-2.21.1.jar:2.21.1]
at org.apache.camel.component.jpa.JpaEndpoint.getEntityManagerFactory(JpaEndpoint.java:250) ~[camel-jpa-2.21.1.jar:2.21.1]
at org.apache.camel.component.jpa.JpaEndpoint.validate(JpaEndpoint.java:545) ~[camel-jpa-2.21.1.jar:2.21.1]
at org.apache.camel.component.jpa.JpaEndpoint.createConsumer(JpaEndpoint.java:165) ~[camel-jpa-2.21.1.jar:2.21.1]
at org.apache.camel.impl.EventDrivenConsumerRoute.addServices(EventDrivenConsumerRoute.java:69) ~[camel-core-2.21.1.jar:2.21.1]
at org.apache.camel.impl.DefaultRoute.onStartingServices(DefaultRoute.java:103) ~[camel-core-2.21.1.jar:2.21.1]
at org.apache.camel.impl.RouteService.doWarmUp(RouteService.java:172) ~[camel-core-2.21.1.jar:2.21.1]
at org.apache.camel.impl.RouteService.warmUp(RouteService.java:145) ~[camel-core-2.21.1.jar:2.21.1]
Why is it looking for a persistence.xml file instead of using annotations? I'm using Spring Boot 1.5.13.RELEASE with Camel 2.21.1.
Basically to make it work I had to abandon using annotations and create an equivalent persistence.xml file, because Apache Camel was looking for configuration only in it.
As soon as I could upgrade to Spring Boot 2 (because Apache Camel got updated and started to support it), I managed to make configuration by annotations work and dropped the persistence.xml file.

Resources