Jetty System Properties are overwritten before Jetty starts in multi module projects


(Edd Grant) #1

I’m working on a multi module project where several modules use Jetty for their functional tests. Each module sets a system property, let’s call it ‘configPath’ to tell Jetty where to look for the config file for that module. We do this as follows in each module:

jettyRun { task ->
   additionalRuntimeJars = configurations.jetty.files
    System.setProperty('configPath', file('build/resources/test').absolutePath)
          jettyEnvXml = file('build/resources/test/jetty-env.xml')
  contextPath = "em3/gateway/admin"
  classpath = sourceSets.test.runtimeClasspath
  httpPort = 8088
}

From the above the important bit to note is that the ‘configPath’ system property will have a different value for each module

e.g.

module-a might set it to: /somepath/module-a/build/test/resources/test and

module-b might set it to: /somepath/module-b/build/test/resources/test

The issue is one of timing, I had hoped that the jettyRun task above (is it strictly the jettyRun ‘configuration’ task? I’ll call it that from here for clarity.) would be executed for each module immediately prior to starting Jetty. However, what actually seems to happen is that the configuration task for module-a is executed, then soon after (and importantly before module-a has started Jetty) the configuration task for module-b is executed which sets the system property to the module-b path. This then causes Jetty to fail horribly on startup during the execution of module-a.

The following options have occurred to me:

  1. Delay the setting of the system properties somehow so that they are set immediately prior to starting Jetty within each module, do this within our own Gradle build scripts not touching the Jetty plugin in any way. 2. Modify the Jetty plugin to take a Map<String, String> of system property key/ values to set immediately prior to starting Jetty. This is actually something that the maven-jetty-plugin supports: http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin#Setting_System_Properties 3. Fork the JVM for every Jetty invocation and ensure that the system properties are set only in the JVM in which each jetty will be invoked. Not sure I like this approach in principle as it adds what I consider to be unnecessary complexity.

I have tried various attempts at 1 but can’t get anything that sets the properties late enough. Anyone have any ideas on an approach I could try? Failing that does 2 sound like a sensible idea? If so I’d be happy to try writing patch to the Jetty plugin (Is there any documentation on patching plugins? I’ve not found any yet.)

Note: I know this could probably be solved by using classpaths to identify properties files rather than system properties however this is outside the realms of what we’re able to achieve with this particular project (I’m not going to go in to the reasons here suffice to say “it’s just not possible right now”).

Cheers.

Edd


(Peter Niederwieser) #2

First, it’s important to note that Gradle configures everything (configuration phase) before it executes anything (execution phase).

I think it would make sense for the Jetty plugin to provide a way to run Jetty in a separate JVM.

A pragmatic solution to the problem with the system property is ‘jettyRun.doFirst { System.setProperty(…) }’. As long as you don’t use ‘–parallel’, this should do the trick.

is it strictly the jettyRun ‘configuration’ task? I’ll call it that from here for clarity.

It’s the ‘jettyRun’ task, not the ‘jettyRun’ configuration task. The code in the build script is configuring the task.


(Edd Grant) #3

Thanks for the clarification Peter, I guess I was calling it configuration because I was aware it seemed to be happening at configuration time but that’s good to call out the distinct phases - helps me understand the Gradle model slightly better in my mind.

Your suggestion does indeed solve the issue, although I must admit I’m struggling to understand why. In my mind binding something to ‘jettyRun.doFirst’ indicates that it would be executed prior to the execution of the jettyRun task which, as you have clarified, is executed during the configuration phase. However what seems to be happening is that the content of doFirst is executed only during the execution phase. Is this a gradle convention i.e. that doFirst only applies to the execution phase? As you can see I’m still struggling with to understand the execution model so apologies for the probably seemingly obvious question.

Thanks for the help!


(Peter Niederwieser) #4

Tasks are configured in the configuration phase, and executed in the execution phase. Each task has a list of task actions. Executing a task means executing all its actions. ‘doFirst’ and ‘doLast’ add an action to the front and end of the list of actions, respectively.

Adding an action to a task is configuration. Executing that action is execution.