Configuration jars

I have a what feels like a straightforward problem, but wondering the best approach.

I am using a library which requires a specific properties file (dsp-client.properties) to be in the classpath. The properties file has a single value. i.e. serverURL={address}. There are three versions of this file in a folder structure- conf/prod, conf/stg, conf/tst. Each file has different serverURL value.

What would be a better approach- create 3 source sets for each configuration or simply jar each file once and define 3 configurations?

1 Like

Have you considered including all three files in your distribution and using a system property to choose one at runtime?

Eg:

  • prod/dsp-client.properties
  • stg/dsp-client-prod.properties
  • test/dsp-client.properties

And use ${env}/dsp-client.properties at runtime

I don’t “own” the library that reads the properties file, so I don’t have the flexibility to alter how the property is read. It it hard-coded to look for “dsp-client.properties” on the classpath.

Assuming you want to publish an artifact for each environment, you could do something like

apply plugin: 'java'

['tst', 'prod', 'stg'].each {
   tasks.create("jar$it", type: Jar) {
      dependsOn jar
      from zipTree(jar) 
      from "conf/$it" 
      archiveClassifier it
   } 
   assemble.dependsOn "jar$it"
   artifacts {
      archives tasks["jar$it"] 
   } 
}

This will create an artifact for each environment which adds an additional directory to the default jar. Each has a unique classifier that can be used in downstream processes

First off, thanks for responding. Yes, I had something like this initially. I missed the assemble.dependsOn line, which is probably why the jars where not in place for the run task.

task dspConfig() {
  doLast {
    def confPath = new File('conf')
    confPath.list().each { conf ->
      def confName = "dsp_$conf"
      def confJarTask = task("${confName}Jar", type: Jar) { baseName = confName }
      assemble.dependsOn "${confName}Jar" // added based upon your sample
      artifacts { archives confJarTask }
    }
  }
}

I was leaning towards the more explicit approaches (sourceSets or configuration) because I wanted to have 3 different JavaExec configurations to test each instance. Can you think of a way to use the jars outputted dynamically here to include them in the JavaExec tasks?

Ah, if it’s just JavaExec you could do

['tst', 'prod', 'stg'].each {
   tasks.create("exec${it.capitalize()}", type: JavaExec) {
      classpath = sourceSets.main.runtimeClasspath.plus files("conf/$it")
      main = 'foo.bar.Baz'
   }
} 

Great, that’s a useful tidbit of code. I may have a slightly older version of Gradle, running, as I had to use the task { } convention:

def dspConfig = ['tst':'TEST','stg':'STAGE','prod':'PROD']
dspConfig.each { key, value ->
  task("runDsp${value}", type: JavaExec) {
    classpath = sourceSets.main.runtimeClasspath.plus files("conf/${key}")
    main = mainClassName
    group = "application"
    description = "Run LiDEA configured against DSP ${key}"
    args = [
      "-env",
      value,
      "–Djava.net.preferIPv4Stack=true",
      "–Djavaws.cctd.lan_enabled=false"
    ]
  }
}

I’d probably want a similar appending of the classpath in the Test tasks. For the final distribution, I’ll need to ensure these configuration files are included.