Hibernate JNDI lookup for WebLogic is throwing unable to resolve - oracle

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 ?

Related

Spring MVC installation

I would like to create instalation process for the first run of my Spring MVC app. Something like wordpress has (when you first run it, you need to specify DB connection and your first admin account... etc.
I have tried it with spring but the spring won't start because when DataSource Bean is not connected, it will simply fail to start. It always fail when transaction manager bean is beeing created:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'txManager' defined in SpringWebConfig: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sessionFactory' is required|#]
Is there any way how to start the spring/hibernate app without transaction manager and then load it on-the-fly when user configures his db access details ? I know there is way to do it with application.properties but I want to create a simple install process just like in wordpress so it is most convenient for non-tech users.
EDIT 1: My current code:
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"test"}) //package scan
public class SpringWebConfig implements WebMvcConfigurer {
#Bean(name = "dataSource")
public BasicDataSource dataSource() {
if (Config.getInstance().isInstalled()) {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://" + Config.getInstance().getDburl() + "/" + Config.getInstance().getDbname());
ds.setUsername(Config.getInstance().getDbuser());
ds.setPassword(Config.getInstance().getDbpass());
this.ds = ds;
}
return ds;
}
#Bean
public HibernateTransactionManager txManager() {
if (sessionFactory() == null) {
return new HibernateTransactionManager();
}
else return new HibernateTransactionManager(sessionFactory());
}
#Bean
public SessionFactory sessionFactory() {
try {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages(dbEntity).addProperties(getHibernateProperties());
return builder.buildSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Adding #Lazy to all 3 #Beans solves the issue and hibernate is not requiered at the startup of Spring MVC (configured by class that implements WebMvcConfigurer), this allows to display install page for the user so he can define DB access details.

JNDI Datasource for Spring 4 Hibernate 4 project not working in AWS

I'm trying to connect my Spring 4 & Hibernate 4 based web application hosted in Amazon Beanstalk with the database in Amazon RDS using JNDI Datasource. I connected to my EC2 environment using SSH and placed the following in /usr/share/tomcat8/conf/context.xml file;
<Resource
auth="Container"
driverClassName="com.mysql.jdbc.Driver"
name="jdbc/TestDatabase"
password="abc123"
type="javax.sql.DataSource"
url="xyz.com:3306/test_jndi"
username="abc123"/>
And in my Hibernate configuration file I used the below;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.example.spring.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
try {
return (DataSource) new
JndiTemplate().lookup("don't know what to provide");
} catch (NamingException e) {
e.printStackTrace();
return null;
}
}
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"));
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
I'm confused on what JNDI look up to provide inside;
JndiTemplate().lookup("don't know what to provide");
I was able to successfully connect to Amazon RDS database while keeping my code locally with the above configuration in context.xml file of my local tomcat and with the following look up;
JndiTemplate().lookup("java:comp/env/jdbc/TestDatabase");
But the same look up is not working when I host my code in Amazon Beanstalk. It's giving me the following exception;
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'transactionManager' defined in class path resource [com/example/spring/config/HibernateConfiguration.class]:
Invocation of init method failed; nested exception is org.hibernate.service.UnknownUnwrapTypeException:
Cannot unwrap to requested type [javax.sql.DataSource]
Please! anyone, help me with this.

Spring Data JPA and Connection Pooling

I have a RESTful web application which stores data against Oracle and the stack is Spring-Data-Jpa and Hibernate.
We have implemented connection pooling using Oracle UCP, but it does not seem to work. There were 1000s of connections in the DB for our NFT tests.
My config is as shown below
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws IllegalStateException, SQLException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaProperties(hibProperties());
return entityManagerFactoryBean;
}
#Bean
public DataSource dataSource() throws IllegalStateException, SQLException {
PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource();
dataSource.setConnectionFactoryClassName(env.getRequiredProperty(DB_CONNECTION_FACTORY_CLASS_NAME));
dataSource.setURL(env.getRequiredProperty(DATABASE_URL));
dataSource.setUser(env.getRequiredProperty(DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
dataSource.setMinPoolSize(Integer.parseInt(env.getRequiredProperty(DATABASE_CONNECTION_MIN_POOL_SIZE)));
dataSource.setMaxPoolSize(Integer.parseInt(env.getRequiredProperty(DATABASE_CONNECTION_MAX_POOL_SIZE)));
dataSource.setInitialPoolSize(Integer.parseInt(env.getRequiredProperty(DATABASE_CONNECTION_INITIAL_POOL_SIZE)));
return dataSource;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(HIBERNATE_DIALECT, env.getRequiredProperty(HIBERNATE_DIALECT));
properties.put(HIBERNATE_SHOW_SQL, env.getRequiredProperty(HIBERNATE_SHOW_SQL));
/*properties.put(HIBERNATE_NAMING_STRATEGY, env.getRequiredProperty(HIBERNATE_NAMING_STRATEGY));*/
return properties;
}
Let me know if there is another config I should be using here, such that a new session is not created all the time.
Thanks
Kris
It would seem that a DataSource gets created for each thread and centralising the datasource in the Jetty config sorted the problem.
jetty and Oracle Connection Pooling

Spring MVC multiple data sources JTA atomikos in same transaction

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

SpringBoot configurate two jndi data sources

I use springboot to configure two datasources.
First:
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource_app")
public DataSource appDataSource(){
if(config.getJndiName()!=null){
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
dataSourceLookup.setResourceRef(true);
return dataSourceLookup.getDataSource(config.getJndiName());
}
return DataSourceBuilder.create().build();
}
Second one
#Bean
#ConfigurationProperties(prefix = "datasource_domain")
public DataSource domainDataSource(){
if(config.getJndiName()!=null){
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource(config.getJndiName());
}
return DataSourceBuilder.create().build();
}
But when i run application i get this exception:
Caused by: javax.management.InstanceAlreadyExistsException: Catalina:type=DataSource,host=localhost,context=/dir-master,class=javax.sql.DataSource,name="jdbc/dir"
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195)
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:670)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615)
... 25 more
What am i doing wrong? Thanks in advance
By default, Spring Boot will attempt to register with JMX any beans in the application context that are MBeans. That causes a problem here as Tomcat has already registered the JNDI DataSource as an MBean.
Spring Boot's own JndiDataSourceAutoConfiguration avoids the problem by telling the application context's MBeanExporter to not export the MBean:
private void excludeMBeanIfNecessary(Object candidate, String beanName) {
try {
MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class);
if (JmxUtils.isMBean(candidate.getClass())) {
mbeanExporter.addExcludedBean(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
// No exporter. Exclusion is unnecessary
}
}
You can avoid the problem by doing similar in your own configuration class.

Resources