2

I have a spring batch application. The database that is used to store meta-data of spring batch job is configured like the following:

In application-context.xml:

<!-- stored job-meta in database - H2 -->
    <bean id="jobRepository"
        class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
        <property name="dataSource" ref="dataSourceMetaData" />
        <property name="transactionManager" ref="transactionManager" />
        <property name="databaseType" value="h2" />    
    </bean>

In database.xml:

<!-- configure H2 database connection -->
<bean id="dataSourceMetaData"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:~/metaDataProd" />
</bean>

Now the application can run in the same environment in multiple instance for ex: one instance for prod & one instance for test. So I have to make the value="jdbc:h2:~/metaDataProd configurable so that both instance does not access the same db.

I can easily do that if I generate the value from a config file. But I am wondering if there is any automatic way of doing this. For example: When an application instance is initiated then a datevalue is appended programmatic ally like this value="jdbc:h2:~/metaData2Jul value="jdbc:h2:~/metaData4Jul

Sumit
  • 856
  • 5
  • 18
  • 38
  • How are you kicking off the job now? – Nghia Do Dec 08 '16 at 14:10
  • The job is deployed using chef. Currently I am doing manual approach like putting `value="${url}"` & changing the url value in property file for each environment. I want to automate it. – Sumit Dec 09 '16 at 07:25
  • Could you pass a param from chef to spring batch? – Nghia Do Dec 09 '16 at 20:20
  • Yup. I find out that chef is actually setting an environment variable indicating whether the instance is prod or qa. That solved my problem too :) – Sumit Dec 19 '16 at 12:27

2 Answers2

2

You can use PropertySourcesPlaceholderConfigurer and init the value from various sources, like environment variable, external property file or alike. Then use ${propname} placeholder instead of hardcoded value.

See also related question.

If you don't need to distinguish instances but just want them to be different, there is very simple method with SpEL. Any of the following may do the work:

<property name="url" value="#{ 'jdbc:h2:~/metaData' + T(java.lang.System).nanoTime() }" />

or

<property name="url" value="#{ 'jdbc:h2:~/metaData-' + T(java.util.UUID).randomUUID() }" />

or

<property name="url" value="#{ 'jdbc:h2:~/metaData-' + (new java.text.SimpleDateFormat('ddmm_hh_mm_ss')).format(new java.util.Date()) }" />

If you don't have any control over spring.xml or application but can execute some script before launch, you can generate name in a script and replace jdbc url value in xml (depending on scripting language, there are endless solutions here on SO).

Jeroen
  • 1,168
  • 1
  • 12
  • 24
Dreamer
  • 76
  • 4
  • I know this approach & that's what I have mentioned in the question. If I do so then it will not be an automatic-approach. Rather I have to change the value in config file for different instance of application manually. Anyway thanks for your quick response :) – Sumit Dec 08 '16 at 13:54
  • My answer doesn't say anything about editing configuration file manually. You put the placeholder in configuration only once, referencing the variable and not setting instance hard-coded values. Then you can start your instances with parameter wired by various means depending on your needs. Simplest example would be passing property value to instance with your start command line by adding `-Dname=value` parameter and value can contain shell expression or variable for the datetime (note, for you this is still _single_ command to prepare, not different commands per each instance). – Dreamer Dec 08 '16 at 16:16
  • I have also thought about this approach & its a good one to automate the process. However as the application is deployed via chef, that would require code change/help of another team that we cant do. – Sumit Dec 09 '16 at 07:23
  • See my edited answer for using expression to set different instances in spring xml. However, if you don't have any control over original spring xml or java sources, and can't execute any script automatically on or before instance run, obviously you can't do anything automatic, who will run the name generating job then? If you can execute some script, I don't understand what you are asking exactly, is the question how to replace an xml value from a script? – Dreamer Dec 17 '16 at 13:15
  • Chef is deploying my application & it is setting an environment variable indicating whether the instance is prod or qa or test. I didn't knew that earlier. By using this environment variable I am creating my dbname like this: `System.setProperty("batchMetaDataDbUrl","jdbc:h2:~/U2ExtractorJob"+environment); ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);` In database.xml I am writing: `` – Sumit Dec 19 '16 at 12:19
0

You can specify a JNDI property for that and load that property at init uisng initialContext() method, some like this:

new InitialContext(environment).lookup(myServiceJndiName);

And you can specify different jndi values for different environment in this case test env or production env.

KayV
  • 12,987
  • 11
  • 98
  • 148