Spring PropertyPlaceholderConfigurer loading properties from both file and database - spring

I'm wondering if its possible to load properties from both file and database, and use the properties in file when loading properties in database. So what I want to achieve is to save app properties in the database, and save the database info in the properties file. Below is my configuration, but it didn't work, the value in jdbc.properties cannot be loaded before reading database properties. Can anyone help me on this? Thanks!
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:jdbc.properties</value> <!--loading properties from file first-->
</list>
</property>
<property name="properties" ref="dataBaseProperties"/> <!--loading properties from database using the properties from file-->
</bean>
<bean id="dataBaseProperties" class="common.spring.DatabaseProperties" >
<constructor-arg type="javax.sql.DataSource" ref="confDataSource"/>
<constructor-arg value="select key_s,value_s from app_conf where status>0"/>
</bean>
<bean id="confDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/> <!--from properties file - jdbc.properties-->
<property name="url" value="${jdbc.url}"/> <!--from properties file - jdbc.properties-->
<property name="username" value="${jdbc.username}"/> <!--from properties file - jdbc.properties-->
<property name="password" value="${jdbc.password}"/> <!--from properties file - jdbc.properties-->
</bean>

> <beans:bean id="appProperties"
> class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
> <beans:property name="location"
> value="classpath:META-INF/application.properties" /> </beans:bean>
You should mention the location from where it fetches the *.properties file

Related

Spring Batch::How to generate file on sftp server using Spring Batch?

I am using Spring Batch 2. version.I have generated the csv file and able to save in csv format on local.
Now I want to generate the same file but it will be stored on SFTP server.
I had gone through some tutorial which generates file on sftp server but they are using spring integration with Spring Batch.
Is it possible to generate the file on SFTP server using Spring Batch only?
Below is itemReader bean defined::
<bean id="itemReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="dataSource" ref="dataSource" />
<property name="sql"
value="select u.ID, u.USER_LOGIN, u.PASSWORD, u.AGE from USERS u" />
</property>
<property name="rowMapper">
<bean class="com.example.UserRowMapper" />
</property>
</bean>
ItemWriter Bean::
<bean id="flatFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:csv/user.csv" />
<property name="appendAllowed" value="true" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value="," />
<property name="fieldExtractor">
<bean
class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="name,age,id,password"/>
</bean>
</property>
</bean>
You have to customize your writer class

Build Maven project without include Spring bean profile

I use Spring bean profile to separate each datasource environments:
<bean id="fooJDBCTemplate" class="com.rakuya.r_erp.task.dao.FooJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<beans profile="dev">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
</beans>
<beans profile="qa">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
</beans>
<beans profile="prod">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
</beans>
And i use following command to build jar file and specify profile
mvn clean package -Dspring.profiles.active=prod
But i got the error about no definition of dataSource when executing the jar file.
It seems like Maven does not use the Spring profile to build jar.
How can I configure the Maven or Spring peofile to use the dataSource ?
Thx
You need to pass the profile -D switch when you run your app.
Since your bears are all the same type (DriverManagerDataSource) and the only thing that differs between environments are some of the properties, I think it would be best to get rid of the spring profiles and use properties to set these values. PropertyPlaceholderConfigurer should be able to handle this scenario where you set a vm param specifying what environment you want. Something like -Denv=dev.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:${env}.properties</value>
</list>
</property>
</bean>
Then you would only need one datasource bean like the following:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
And a property file for each environment named dev.properties, qa.properties, and prod.properties with values in each for db.driver, db.url, etc.
When spring starts up it will select the appropriate properties file based on the value passed in with -Denv and load the corresponding property values into your datasource bean.

Error upon integrating JNDI with Spring

This was my first attempt at Spring with JNDI but getting the below mentioned exception when trying to create the ApplicationContext like:
ApplicationContext context = new ClassPathXmlApplicationContext("master-job.xml");
The Spring configuration file is as follows:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="/jdbc/Eqpstatus"/>
<property name="resourceRef" value="true" />
</bean>
<bean id="masterDao" class="com.dao.MasterDao">
<property name="dataSource" ref="dataSource"/>
</bean>
On Server i have the required resource entry for the JNDI name.
<Resource auth="Container" driverClassName="oracle.jdbc.OracleDriver"
maxActive="10" maxIdle="2" maxWait="10000" name="jdbc/Eqpstatus"
password="xxxx" type="javax.sql.DataSource"
url="jdbc:oracle:thin:#(DESCRIPTION=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=xxxx) (PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=xxxx) (PORT=1521))(CONNECT_DATA=(SERVICE_NAME=xyz)))"
username="xxx"/>
The error i see is:
javax.naming.NameNotFoundException: Name jdbc is not bound in this Context
Would highly appreciate any inputs on this as am new to Spring-JNDI integration.
First, I think you should use the dedicated tag instead of declaring a "JndiObjectFactoryBean" bean :
<!-- JNDI DataSource for J2EE environments -->
<jee:jndi-lookup id="dataSource" jndi-name="java:jdbc/rppsDS-PUB-PROTO" default-ref="localDataSource" />
<!-- local dataSource for JUnit integration tests -->
<bean id="localDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="100"/>
<property name="maxWait" value="1000"/>
<property name="poolPreparedStatements" value="true"/>
<property name="defaultAutoCommit" value="true"/>
</bean>
Then, you need a jndi.properties file (which could be directly in application server dir such as JBoss) with a content similar to :
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost:1099
If you are using Tomcat and everything is fine with your Tomcat configuration; this should be enough:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/dataSource" />
Where jdbc/dataSource is the name defined in your Tomcat config.
EDIT:
My bad, forgot about the jndi.properties; there are two possibilities:
either provide a jndi.properties on your classpath or
set the values in a in the <jee:jndi-environment/> element of <jee:jndi-lookup /> (see reference)
The java.naming.factory.initial property needs to be set for sure, to something like org.apache.naming.java.javaURLContextFactory, possibly some other values as well, like:
java.naming.factory.url.pkgs=org.apache.naming
java.naming.factory.url.pkgs.prefixes=org.apache.naming
java.naming.provider.url=org.apache.naming
Also see reference.

Setting properties in Spring

Is there a way to change the properties of a file? I'm trying to run selenium tests in parallel, with Spring and Jetty, so I'm trying to configure the url of the database, the port of the jettyserver and the port of the selenium server. So that I'm able to initialize two or more servers where the tests can run on.
My server.properties file contains this:
jdbc.url=jdbc:hsqldb:hsql://localhost/bibliothouris_scenario
jetty.port=8081
seleniumServer.port=4444
I can read those properties with a PropertyPlaceholderConfigurer, and I need the database URL, jettyport and seleniumserver port to be flexible.
I have declared them like this:
In my applicationContext.xml:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:server.properties</value>
</property>
</bean>
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
In the serverContext.xml file:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:server.properties</value>
</property>
</bean>
<bean class="com.~companyName~.bibliothouris.jetty.JettyServer" init-method="start" destroy-method="stop">
<constructor-arg value="${jetty.port}" />
<constructor-arg ref="dataSource" />
</bean>
<bean class="org.openqa.selenium.server.SeleniumServer" init-method="start" destroy-method="stop">
<constructor-arg>
<bean class="org.openqa.selenium.server.RemoteControlConfiguration">
<property name="port" value="${seleniumServer.port}" />
<property name="singleWindow" value="true" />
<property name="timeoutInSeconds" value="10" />
</bean>
</constructor-arg>
</bean>
<bean class="com.thoughtworks.selenium.DefaultSelenium" init-method="start" destroy-method="stop" lazy-init="true">
<constructor-arg>
<bean class="com.thoughtworks.selenium.HttpCommandProcessor">
<constructor-arg value="localhost" />
<constructor-arg value="${seleniumServer.port}" />
<constructor-arg value="*firefox c:/~companyname~/firefox/firefox.exe" />
<constructor-arg value="http://localhost:${jetty.port}" />
</bean>
</constructor-arg>
</bean>
When I change the data in server.properties the selenium tests run on the right servers with the right ports, without failures.
So now I'm looking for a method to change the properties in the server.properties file.
Kind regards and thanks in advance
I solved this by having a flag in my build process (I'm using Maven) that chose which property file to include in the final war. This way you can include different artifacts (different property files) with different properties without having to mess with the low level property support of Spring.
If you do need to do this is Spring only, I would recommend going for a Java based configuration, where you can get and set the properties by in code not in XML.
Is there a way to change the
properties of a file?
No, but you could solve this in the following ways.
Split the properties into jdbc.properties (for applicationContext.xml) and test.properties (for serverContext.xml)
override server.properties via a src/test/resources resource
use system properties in addition to server.properties (use PropertyPlaceholderConfigurer.setSystemPropertiesMode for this)
Thanks for the help guys, without your info, I couldn't find my own solution. Here it is:
try {
Properties props = new Properties();
FileInputStream fileInputStream = new FileInputStream(
"C:\\~CompanyName~\\workspace\\bibliothouris\\infrastructure\\src\\main\\resources\\server.properties");
props.load(fileInputStream);
fileInputStream.close();
props.setProperty("seleniumServer.port", "4445");
FileOutputStream fileOutputStream = new FileOutputStream(
"C:\\~CompanyName~\\workspace\\bibliothouris\\infrastructure\\src\\main\\resources\\server.properties");
props.store(fileOutputStream, "");
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
I've wrote this piece of code in a testclass, now I have to create a method of it, which takes a few arguments (the URL, jettyport and seleniumport). And I have to change the path to a relative one.
Thanks for the help!

Loading .properties file in a jar from my web-app

I have created a JAR that I need to use in my WEB-APP. Both are created with spring framework. I would like to load a .properties file outside the JAR file, in the main context of the web-application. And I want to do it with the facilities that Spring offers us.
I've tried to do something like this in my spring.xml file inside the JAR:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>/WEB-INF/classes/my.properties</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="myJob" />
<property name="cronExpression" value="${my.cronExpression}"/>
</bean>
</property>
</bean>
Trying to load my.cronExpression from my.properties file. But without any success.
I always get this error:
Could not resolve placeholder 'my.cronExpression'.
I've tried to change the location with many variants, using classpath:/WEB-INF/classes/my.properties etc...
But I'm not able to load the configuration file.
Thanks for your help.
Use classpath:my.properties - /WEB-INF/classes is root of your classpath.
Try declaring it as follows:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>/WEB-INF/classes/my.properties</value>
</property>
<property name="ignoreUnresolvablePlaceholders">
<value>true</value>
</property>
</bean>
I have gone through your code and want you to try this code snippet
It works well for me :)
<bean id="placeholderProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:/WEB-INF/classes/my.properties" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="order" value="1" />
</bean>

Resources