Trouble with overriding properties in Spring-batch - spring

We are using Spring 4.3.9 with Spring Batch 3. We are using maven to copy resources with filtering to merge profile-based properties into the configs at build time. I want to allow my DevOps engineers to override property file settings (db passwords) at deployment time to the environment specific property, so I've setup things as shown below, but the overrides don't work:
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="location" value="classpath:bluecost-OVERRIDE.properties" />
</bean>
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${datasource.database.driverClassName}" />
<property name="jdbcUrl" value="${datasource.database.url}" />
<property name="user" value="${datasource.database.username}" />
<property name="password" value="${datasource.database.password}" />
<property name="maxPoolSize" value="${datasource.maxPoolSize}" />
<property name="minPoolSize" value="${datasource.minPoolSize}" />
</bean>
The property file that maven merges with all default values looks like this:
datasource.database.driverClassName=com.ibm.db2.jcc.DB2Driver
datasource.database.url=jdbc:db2://localhost:50000/bluecost
datasource.database.username=not-real-id
datasource.database.password=not-real-pwd
datasource.maxPoolSize=50
datasource.minPoolSize=10
And finally, my bluecost-OVERRIDE.properties file has the correct values for just the username and password, configured like this:
# Overriding values for the datasource property values
datasource.database.username=db2inst
datasource.database.password=db2inst1
The override file is surely in the classpath (it wouldn't start without finding it anyway). It's throwing errors at runtime because of the invalid (default) userid/pwd.
Why doesn't it override the userid/pwd like I want it to?

Related

How do I replace content or keyword of an xml (like applicationContext.xml) with Gradle build?

My application has applicationContext.xml with entityManagerFactory bean defined as :
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="org.xyz" />
**<property name="dataSource" ref="poolDVLDataSource" />**
<!--<property name="dataSource" ref="poolPRDDataSource" /> -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform"
value="org.hibernate.dialect.Oracle10gDialect" />
<property name="database" value="ORACLE" />
<property name="showSql" value="false" />
</bean>
</property>
</bean>
and data source references as
<bean id="poolPRDDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
....
</bean>
and
<bean id="poolDVLDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
....
</bean>
I'm using gradle for build. Depending on the deploying environment, is there a way to replace the dataSource ref to either "poolDVLDataSource" or "poolPRDDataSource" dynamically?
ReplaceRegExp ant task should fix your issue. https://ant.apache.org/manual/Tasks/replaceregexp.html
Sample gradle code below:
ant.replaceregexp(match:'existingName', replace:'newName', byline:true) {
fileset(dir: 'WebContent/WEB-INF', includes: 'applicationContext.xml')
}
I wouldn't be solving this with gradle, you should solve this in spring
You can use spring's <import /> with a ${parameter} so that the actual file is decided at runtime. For instance you could split your service configuration into two files. The "internal" file could contain all the services implemented by your application and the "external" config file could contain external config including database connections, JMS connections, mail servers etc, etc.
Eg: applicationContext.xml
<context:property-placeholder/>
<import resource="classpath:internal-services.xml" />
<import resource="classpath:${environment}/external-services.xml" />
For production, you can pass environment=prod as a system property and load the prod/external-services.xml which contains the "real" services. For tests you could pass environment=mock and load mock/external-services.xml which contains mocks of all of your external services.

How do I automatically reload my properties in my Spring XML appilcation context?

I’m using Spring 3.2.11.RELEASE. I currently have the following set up in my application context file for the purposes of loading a cron trigger based off a schedule defined in a properties file (the property = cron.schedule) …
<bean id="localPropertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:application.properties</value>
</property>
</bean>
…
<bean id="updateResourcesJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myService" />
<property name="targetMethod" value="myMethod" />
<property name="concurrent" value="true" />
</bean>
<bean id="updateResourcesCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="myJob" />
<property name="cronExpression" value="${cron.schedule}" />
</bean>
My question is, I would like to create an XML configuration in my context file that allows me to edit my properties file and have everything automatically reloaded without having to restart my server or re-deploy my application. I have read several places about Apache Commons Configuration, but I can’t figure out how to take the above and rewrite an XML config that would utilize the configuration.
Thanks for any help, - Dave

Change property value of a existing bean in spring at run time

I have a web application deployed on Tomcat server. I have the following bean hiveDataSource created in my application-context.xml:
<!-- Hive Data Source for Connection Pooling -->
<bean id="hiveDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="url" value="jdbc:hive2://localhost:10000/demo48" />
<property name="driverClassName" value="org.apache.hive.jdbc.HiveDriver" />
<property name="username" value="hive" />
<property name="password" value="" />
<property name="removeAbandoned" value="true" />
<property name="initialSize" value="5" />
<property name="maxActive" value="20" />
</bean>
I want to change the value of property URL, username and password at run time for bean hiveDataSource. Is there any way to change these property values at runtime?
The documentation says that these fields have protected access, so you wont be able to change their values.
Even if you do, by using reflection or in some other way, it's not likely that data source would just pick up these new values. It would probably have to be restarted or reinitialized in some way.

Changing blob size on HSQLDB with spring datasource

I am configuring HSQLDB through Spring and C3P0, this creates the database for me if it doesn't exist.
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="org.hsqldb.jdbcDriver" />
<property name="jdbcUrl" value="jdbc:hsqldb:file:mydb/mydb" />
<property name="user" value="sa" />
<property name="password" value="" />
</bean>
However, I would like to initialize the BLOB size to 8kb instead of the 32kb default value, is it possible to set the parameter in Spring somehow? I know I can edit later the script file to set SET FILES LOB SCALE 32 to 8, but I would like it set on Spring/C3P0 if possible.
Yes. For new databases, several settings can be included on the URL or as properties.
To change the BLOB block size, add this line:
<property name="hsqldb.lob_file_scale" value="8" />
The properties are covered in the Guide:
http://www.hsqldb.org/doc/2.0/guide/dbproperties-chapt.html#dpc_db_file_mem

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!

Resources