Use ConfigSluper Instead Of Properites Files



>> Thursday, September 9, 2010

I often use Java property files as configuration for prototypes, proofs of concepts, utility applications, etc. Groovy has a more powerful way of doing this called a ConfigSlurper (JavaDoc).

A ConfigSlurper just uses a Groovy script as input instead of a .properties file. This lets you do better (in my opinion) configuration like having typed properties (instead of them all being Strings you have to convert) including lists and maps, tree-structures of properties, even deriving a property value based on some calculation or closure.

Here are some examples. All the code can be downloaded here (box.net)


//Config1.groovy
stringProperty="Some string"
numberProperty=42
booleanProperty=false
listProperty=["Monday", "Tuesday", "Wednesday"]

Here is a basic configuration file using some different types. Here is how to read and use it:

def config = new ConfigSlurper().parse(new File('src/Config1.groovy').toURL())

assert "Some string" == config.stringProperty
assert config.stringProperty.class == String

assert 42 == config.numberProperty
assert config.numberProperty.class == Integer

assert false == config.booleanProperty
assert config.booleanProperty.class == Boolean

assert ["Monday", "Tuesday", "Wednesday"] == config.listProperty
assert 3 == config.listProperty.size()
assert config.listProperty.class == ArrayList


Another powerful feature is being able to use trees of data like this:

//Config2.groovy
teams {
packers {
quarterback="Aaron Rodgers"
recievers=["Greg Jennings", "Donald Driver"]
}
vikings {
quarterback="Brett Favre"
}
}


And then reading them like this:

def config = new ConfigSlurper().parse(new File('src/Config2.groovy').toURL())

assert "Aaron Rodgers" == config.teams.packers.quarterback
assert ["Greg Jennings", "Donald Driver"] == config.teams.packers.recievers
assert "Brett Favre" == config.teams.vikings.quarterback


Along those lines, there is a special configuration called "environment." This allows you to use different configurations based on what "environment" you are in.

//Config3.groovy
website {
//default values
url = "http://default.mycompany.com"
port = 80
user = "test"
}

environments {
development {
website {
url = "http://dev.mycompany.com"
port = 8080
}
}
production {
website {
url = "http://www.mycompany.com"
user = "prodUser"
}
}
}

In this example, there are some default values for the website properties. Then, the different environments overwrite some of the defaults. Here is how you call the ConfigSlurper to use the different environments.


//defaults
def config = new ConfigSlurper().parse(new File('src/Config3.groovy').toURL())

assert config.website.url=="http://default.mycompany.com"
assert config.website.port==80
assert config.website.user=="test"

//development environment
config = new ConfigSlurper("development").parse(new File('src/Config3.groovy').toURL())

assert config.website.url=="http://dev.mycompany.com"
assert config.website.port==8080
assert config.website.user=="test"

//production environment
config = new ConfigSlurper("production").parse(new File('src/Config3.groovy').toURL())

assert config.website.url=="http://www.mycompany.com"
assert config.website.port==80
assert config.website.user=="prodUser"


Finally (for this article), here are a few fun things you can do with a ConfigSlurper including calculated values and merging configs.


//Config4.groovy

//set the value as some calculation
calculation = 2+2

//base the value off of some other property
calc2 = calculation * 2

//set the value using a closure
doubling = 1
5.times{ doubling = doubling * 2 }


And using those values:

def config = new ConfigSlurper().parse(new File('src/Config4.groovy').toURL())

assert 4 == config.calculation
assert 8 == config.calc2

assert 32 == config.doubling

//merge config files
def config1 = new ConfigSlurper().parse(new File('src/Config1.groovy').toURL())
def config2 = new ConfigSlurper().parse(new File('src/Config2.groovy').toURL())
config1 = config1.merge(config2)
assert 42 == config1.numberProperty
assert "Aaron Rodgers" == config1.teams.packers.quarterback


Leave a comment if you have any questions or suggestions!

Read more...

Running an Ant Script in Groovy



>> Wednesday, September 1, 2010

I recently wanted to test the execution of an Ant script and I wanted to use Groovy. There are a lot of blogs about using AntBuilder to run Ant tasks in Groovy, but that isn't what I needed. I actually needed to test the Ant script itself.

This was not to hard, but the concept is tricky. I used AntBuilder to execute an external process (using the exec task). In this case, the external process is ant. Lost yet? Here is the code, maybe that will make it easier:


File antExecutable = new File("C:/Ant/bin/ant.bat")
assert antExecutable.exists()

File antScript = new File("C:/antscripts/build.xml")
assert antScript.exists()

def ant = new AntBuilder()
ant.exec(executable: antExecutable.getAbsolutePath(),
outputproperty:"cmdOutput",
errorproperty:"cmdError"){
arg(value: "-f")
arg(path: antScript.getAbsolutePath())
}
assert ant.project.properties.cmdOutput.contains("BUILD SUCCESSFUL")
assert ant.project.properties.cmdError == ""


Hopefully this is pretty straight-forward. Basically this is equivalent to calling "ant -f C:\antscripts\build.xml" from a command line. If you want to know more about how to use AntBuilder, go here.

The output gets stored in a property called "cmdOutput" which can be tested using the "ant.project.properties.cmdOutput" variable. In a similiar way, the standard error gets stored in "cmdError." If you just want to display the output, remove the outputproperty and errorproperty from the exec task.

There are a couple other things you might need to do.

First, if you want to pass additional arguments to the script (for example, setting some ant properties), you can just add additional "arg" lines like this:


ant.exec(executable: antExecutable.getAbsolutePath(),
outputproperty:"cmdOutput",
errorproperty:"cmdError"){
arg(value: "-f")
arg(path: antScript.getAbsolutePath())
arg(value: "-DsomeProperty=someValue)
}


Second, if the ant script needs to know about some classpath variables, just add an "env" line like this:


ant.exec(executable: antExecutable.getAbsolutePath(),
outputproperty:"cmdOutput",
errorproperty:"cmdError"){
arg(value: "-f")
arg(path: antScript.getAbsolutePath())
env(key: "CLASSPATH", path: "C:/jars/;C:/project/files")
}


Leave a comment if you have any questions or suggestions

Read more...

  © Blogger template Webnolia by Ourblogtemplates.com 2009

Back to TOP