Change hibernate.connection.url from within Spring - spring

I am using Hibernate in combination with Spring. As database I am currently using HSQL, which stores its data in a file (like SQLite). The path to the HSQL file is currently hard-coded in the persistence.xml. How can I access and change this value at runtime, so a user can load and save from/to an arbitrary HSQL file?
persistence.xml:
<persistence 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"
version="1.0">
<persistence-unit name="something-unit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
<property name="hibernate.connection.url" value="jdbc:hsqldb:file:~/something-db/somethingdb" />
<property name="hibernate.connection.username" value="sa" />
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>
Spring applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:data="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
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-2.5.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- Database Setup -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="something-unit" />
</bean>
<data:repositories base-package="com.something.playlist"/>
<!-- Transaction Setup -->
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
</beans>
Thanks for any hint!

You can specify a JNDI datasource and pass it to Hibernate. Or you can define your own plugin strategy for obtaining JDBC connections by implementing the interface org.hibernate.connection.ConnectionProvider
For more hints see: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/session-configuration.html
Edit 2/16: There is an example on StackOverflow on creating a custom ConnectionProvider: How can I set Datasource when I'm creating Hibernate SessionFactory?
If you are going to change the data source on the fly, rather than at the startup, you will have to restart the Hibernate session factory. To do it correctly, you will have to make sure that no transactions are running in it at the time of the restart. Following question/answers would help you with that: Hibernate Sessionfactory restart | Spring

A commonly used strategy is to define all runtime configurations in one or several *.properties files and use spring's PropertyPlaceholderConfigurer to load the values and substitute the placeholder in applicationContext.xml, read more here: Best ways to deal with properties values in XML file in Spring, Maven and Eclipses.
app.properties:
# Dadabase connection settings:
hibernate.connection.driver_class=org.hsqldb.jdbcDriver
hibernate.connection.url=jdbc:hsqldb:file:~/something-db/somethingdb
hibernate.connection.username=sa
hibernate.connection.password=changeit
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hbm2ddl.auto=update
... ...
applicationContext-dataStore.xml:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- Default location inside war file -->
<value>classpath:app.properties</value>
<!-- Environment specific location, a fixed path on deployment server -->
<value>file:///opt/my-app/conf/app.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
... ...
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${hibernate.connection.driver_class}" />
<property name="url" value="${hibernate.connection.url}" />
<property name="username" value="${hibernate.connection.username}" />
<property name="password" value="${hibernate.connection.password}" />
</bean>
One problem here is the PropertyPlaceholderConfigurer doesn't parse persistence.xml, the solution is to move all hibernate configuration into Spring's applicationContext.xml, as it is not necessary to set them in persistence.xml. read more here: loading .properties in spring-context.xml and persistence.xml.
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="1.0">
<persistence-unit name="JPAService" transaction-type="RESOURCE_LOCAL"/>
</persistence>
applicationContext-datSource.xml:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${hibernate.connection.driver_class}"/>
<property name="url" value="${hibernate.connection.url}"/>
<property name="username" value="${hibernate.connection.username}"/>
<property name="password" value="${hibernate.connection.password}"/>
</bean>
... ...
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml"/>
<property name="persistenceUnitName" value="JPAService"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${hibernate.dialect}"/>
<property name="showSql" value="true" />
<property name="generateDdl" value="true"/>
</bean>
</property>
<property name="jpaProperties">
<!-- set extra properties here, e.g. for Hibernate: -->
<props>
<prop key="hibernate.hbm2ddl.auto">${hbm2ddl.auto}</prop>
</props>
</property>
</bean>
Note that the web application need to be restarted every time you alter the configuration in /opt/my-app/conf/app.properties, in order to make changes take effect.
Hope this helps.

If you wish to use hibernate via the JPA Abstraction you can we-write your code or service to use an javax.persistence.EntityManagerFactory. Autowire one of these and call createEntityManager(Map map); You can provide a datasource in the map. You could wrap the entity manager with your own implementation that pulls the parameter off a thread-local for creating the datasource.
EDIT: Mis-read the context and saw you are using an EntityManagerFactory. In which case just read the last part where you wrap the Factory with a delegate that creates the correct datasource from a threadlocal.

Related

How to read application.properties file , while starting Ignite from spring config file

I was trying to start a Apache Ignite from spring config xml file. The spring xml has keys that it reads from application.properties file.
I am using the following command to start Apache Ignite
apache-ignite-fabric-2.6.0-bin\bin\ignite.bat D:\workspace\<application-name>\src\main\resources\ignite.xml
I tried setting up a CLASSPATH environment variable where i have kept all the related spring and ignite jars and have also kept the application.properties file. Still its somehow now able to read the apploication.properties file.
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'ignite.cfg' defined in URL [file:/D:/workspace/<application-name>/src/main/resources/ignite.xml]: No configuration setting found for key 'zookeeper'; nested exception is com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'zookeeper'
at org.springframework.beans.factory.config.PlaceholderConfigurerSupport.doProcessProperties(PlaceholderConfigurerSupport.java:223)
at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.processProperties(PropertyPlaceholderConfigurer.java:222)
at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:86)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:283)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:163)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)
at org.apache.ignite.internal.util.spring.IgniteSpringHelperImpl.applicationContext(IgniteSpringHelperImpl.java:381)
I have tried setting the classpath as well as tried keeping the file/jar in lib directory of IGNITE_HOME directory.
ignite.xml
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<!--<property name="gridLogger">
<bean class="org.apache.ignite.logger.slf4j.Slf4jLogger"/>
</property>-->
<!-- Enabling Apache Ignite native persistence. -->
<property name="peerClassLoadingEnabled" value="false"/>
<property name="dataStorageConfiguration">
<bean class="org.apache.ignite.configuration.DataStorageConfiguration">
<property name="walMode" value="NONE"/>
<property name="walArchivePath" value="D:\work\TIWorkspace\ignite\wal\archive"/>
<property name="defaultDataRegionConfiguration">
<bean class="org.apache.ignite.configuration.DataRegionConfiguration">
<property name="persistenceEnabled" value="true"/>
<!-- Increasing the buffer size to 1 GB. -->
<property name="checkpointPageBufferSize"
value="#{1024L * 1024 * 1024}"/>
</bean>
</property>
</bean>
</property>
<property name="binaryConfiguration">
<bean class="org.apache.ignite.configuration.BinaryConfiguration">
<property name="compactFooter" value="false"/>
<property name="idMapper">
<bean class="org.apache.ignite.binary.BinaryBasicIdMapper">
<property name="lowerCase" value="true"/>
</bean>
</property>
<property name="nameMapper">
<bean class="org.apache.ignite.binary.BinaryBasicNameMapper">
<property name="simpleName" value="true"/>
</bean>
</property>
</bean>
</property>
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.zk.ZookeeperDiscoverySpi">
<property name="zkConnectionString" value="localhost:2181"/>
<!--<property name="zkConnectionString" value="${zookeeper.server}"/>-->
<property name="zkRootPath" value="/dbobjects"/>
</bean>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:application.properties</value>
</property>
</bean>
Any leads could be helpful.
Thanks in advance.
The most straightforward way to achieve that is to use file-based resource URL. This one worked for me:
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:${IGNITE_HOME}/libs/application.properties</value>
</list>
</property>
</bean>

moving from oracle sql to couchBase db just by changing connection

I have a spring mvc application that works on oracle server, I am currently using the spring JPA to store and retrieve data. can i move from oracle sql to couchbase server just by changing the data source, If so how do I configure my datasource to work with couchbase
The bean definition is as follows
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx/ http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:component-scan base-package="org.test.project"></context:component-scan>
<context:property-placeholder location="classpath:application.properties" ></context:property-placeholder>
<jpa:repositories base-package="org.test.project"
entity-manager-factory-ref="entityManagerFactoryBean"></jpa:repositories>
<bean id="dbClassImpl" class="org.test.project.DbClassImpl" />
<!--EntityManagerFactory -->
<bean id="entityManagerFactoryBean"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.test.project" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="someurl" />
<property name="username" value="username" />
<property name="password" value="password" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryBean" />
</bean>
<tx:annotation-driven proxy-target-class="true" />
Here is the official documentation about it https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#configuration-xml
However, you will need to change a few extra things to make it work:
1 - One of the main advantages of Document Databases is to avoid unnecessary joins. If you simply transition from relational to Document without changing your model, you won't get the most of it. (https://blog.couchbase.com/json-data-modeling-rdbms-users/)
2 - Couchbase don't support LocaDateTime/ZonnedDateTime yet, you will need to write a converter.
3 - Your repositories should have a few extra annotations
(https://blog.couchbase.com/couchbase-spring-boot-spring-data/)
4 - If you are using JPQL, you will need to slightly modify it to use the N1QL syntax (https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#couchbase.repository.n1ql)

Spring-Hibernate Error: Error loading class [org.springframework.orm.hibernate3.LocalSessionFactoryBean]

I am trying a sample application which uses Spring-Hibernate integration. However I am getting this error when I load config.xml
Exception in thread "main" org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.orm.hibernate3.LocalSessionFactoryBean] for bean with name 'mySessionFactory' defined in class path resource [SpringDAO/config.xml]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: org/springframework/dao/support/PersistenceExceptionTranslator
Here's my config.xml code
<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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean id="JdbcDAO" class="SpringDAO.JdbcDAO"/>
<bean id="HibernateDAO" class="SpringDAO.Hibernate"/>
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/test"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="mappingResources">
<list>
<value>SpringDAO/HibernateDAO/SocketStreamedData.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>hibernate.dialect=org.hibernate.dialect.HSQLDialect</value>
</property>
</bean>
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="socketStreamedDataDAO">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
</beans>
Maybe there's something wrong with mappingResources property class is incorrect or something. However, what I have specified there is full classpath for that hibernate xml config. So what could be the problem? Please help me.
Source of a java.lang.NoClassDefFoundError is most of time a problem in classpath. Here you have to check that Spring TX and Hibernate are present in the classpath.
Please add spring tx jar in your class path.I faced the same issue and solved by adding the spring-tx jar.

Spring with JPA not persisting objects

I have read many tutorials to config spring with JPA. I am using a local MySQL database and i have this context:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- DataSource Setup -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="vitornobrega" />
<property name="password" value="" />
</bean>
<!-- Entity Manager Factory -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.vitornobrega.myapp.entities" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
</beans>
I have a test on JUnit to test my DAO and works nice but when i try to persist an entity with this config, i never the in hibernate log the insert command but in test case i see it. If i try to make a entitymanager.flush i get an exception because any transaction is running.
What i should change to can make persist on my local database with this entities?
thanks
If i try to make a entitymanager.flush i get an exception because any transaction is running.
If I'm reading that right, the problem is you're trying to save something without starting a transaction. Transactions are required when changing persistent state.
In order to be able to persist in database it is mandatory to be within a transaction. So the better you can solve it is to annotate #Transactional ... e.g. on the method
This also make me crazy for couple of hours some time ago.
are you using annotations in your classes? if so please make sure you
<context:component-scan base-package="com.vitornobrega.myapp"> because arpart from the jpa configurations i can see where you are injecting your dependencies.

Load webserver context.xml using Spring

Fairly new to Spring, so I'm having some trouble with this. I'm trying to use LDAP security with Spring. I can use a properties file I created inside the webapp itself. But what I would like to do is load and read the context.xml file of the server (it has all the values I need for this and other applications).
This is what I have:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="searchContextAttributes" value="true"/>
<property name="contextOverride" value="true"/>
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>/WEB-INF/properties/dataUploadProperties.properties</value>
<value>/WEB-INF/properties/globalProperties.properties</value>
<value>context.xml</value>
</list>
</property>
</bean>
I'm able to load and read the 2 properties files, but the context.xml is not found. Does it need to be the absolute path on the server?
Thanks
Chris
So the first thing I would recommend is to use Spring Security. It has an already build in LDAP support.
but the context.xml is not found
Normally this (reading the context.xml directly) is not the way you should go.
Instead, define some properties and or JNDI resources in the context.xml and then use them in the spring configuration.
For example:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<!-- access via jndi -->
<jee:jndi-lookup id="jndiEmailSession"
jndi-name="java:comp/env/email/session/myEmailSession" />
<!-- direct access for properties required the SERVLET contect property
place older configurer, then it works like properties from normal
property files -->
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"> <property name="locations" value="classpath*:META-INF/spring/*.properties" /> </bean>
<bean class=Demo>
<property name="someString" value="${simpleValue}" />
</bean>
</beans>
context.xml:
<Resource name="email/session/myEmailSession"
type="javax.mail.Session"
auth="Container"
password="secret"
mail.debug="false"
mail.transport.protocol="smtp"
mail.smtp.auth="true"
mail.smtp.user="test#example.com"
mail.smtp.host="mail.example.com"
mail.smtp.from="test#example.com"/>
<Parameter name="simpleValue" value="any" override="false" />

Resources