Thursday, May 6, 2010

Mule: Defining Properties at Runtime

I've had the desire for sometime to investigate telling Mule at run (or start-up) time what set of properties to use for a particular environment as in development, QA, or production, instead of deciding at build or deploy time what the target environment will be. So below I've come up with a rather simplistic service that uses a system property to define which set of properties to use at startup.

We will use the following Mule configuration element to define the environment properties file (explained in more detail here).

  <context:property-placeholder location=",classpath:${env}.properties" />

With the above line included in our Mule configuration, the file will be loaded first, followed by the environment-specific properties file. The latter will have the opportunity to override anything defined by the former.

The service will report the current season. A greeter bean configured in the Mule context will have two properties to be set via injection:

  • greetee - who the greeting will be addressed to
  • season - the current season (a true property of the environment)

The greeting will take the form of:

  "Hello ${greetee}, it is ${season}"

A default properties file will be used with the hope that we can eliminate having to repeat the property definitions
whose values would be common for every environment. We'll also investigate the ability to override this property in
case a particular environment would need to do so.

The default properties file will hold the 'greetee'.

greetee = Friend
We'll have two season-defining properties files, one for spring and one for winter. The winter properties file will simply define the season:
season = winter
The spring properties file will define the season as well as override the greetee property set in
greetee = Chap
season = spring

Since I'm using Maven 2 to build my service, we'll place the properties file in the src/main/resources directory. By convention, Maven will place all files found in this directory in the JAR file produced by the build. To make the files available to Mule on the classpath, we can place the JAR in hte lib/user directory of our Mule deployment so that they are available on the classpath as requested by the property-placeholder element.

The SeasonReporter class will have the two properties injected and will be used as a service component in our Mule model:

class SeasonReporter {
def greetee
def season
def reportSeason() { "Hello $greetee, it is $season" }

Our Mule configuration will have an inbound HTTP endpoint that will reply synchronously with the environment-specific greeting. The component that is invoked will be implemented by a SeasonReporter class that takes the two properties used to create the seasonal greeting.

We'll direct Mule to use the reportSeason method with no arguments (by default the HTTP transport will provide a payload of one argument, /season here):

<context:property-placeholder location=",classpath:${env}.properties" />

<model name="seasonModel">
<service name="seasonService">
<http:inbound-endpoint address="http://localhost:8080/season"/>
<include-entry-point method="reportSeason"/>
<spring-object bean="seasonReporter"/>

<spring:bean name="seasonReporter" class="SeasonReporter" scope="prototype">
<spring:property name="greetee" value="${greetee}"/>
<spring:property name="season" value="${season}"/>

To start Mule using the winter properties file, we can pass in the env property when starting Mule on the command line with:

  $ mule/bin/mule start -M-Denv=winter

After starting Mule and hitting URL http://localhost:8080/season in a browser, we are presented with:

  Hello Friend, it is winter

Now we can try starting Mule up for season spring. The greeting should now include the overridden greetee property of 'Chap':

  $ mule/bin/mule start -M-Denv=spring
Giving us:
  Hello Chap, it is spring

Thanks for reading!