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...

Scrape Powerball Number Frequency



>> Monday, August 30, 2010

I know that buying lottery tickets is a total waste of money. I also know that there is nothing you can do to increase the odds of hitting a Powerball jackpot (1 in 195,249,054). However, just for fun, I thought I'd fire off a quick groovy script that will read the frequencies from the Powerball website.

Once I have all the numbers I could sort the lists to find out which numbers are most frequently picked (or least frequently picked). I'm sure there is other statistical analysis that you could do too if you wanted. You could also watch the frequency trends over time (though this historic list of numbers may be better at that)

Here's the simple script:

import org.cyberneko.html.parsers.SAXParser;

//initialize
def maxPowerBall = 39
def whiteBallFreq = [:]
def pbFreq = [:]

//read the numbers
def url = 'http://powerball.com/powerball/pb_frequency.asp'
def html = new XmlSlurper(new SAXParser()).parse(url)

//create the lists from the HTML
html.BODY.TABLE.TBODY.TR[3].TD[1].TABLE.TBODY.TR[4].TD[1].TABLE.TBODY.TR[2..-2].each{nextRow ->
def cols = nextRow.children()
def ball = Integer.parseInt(cols[0].text())

whiteBallFreq[ball] = parsePossiblyBlankNumber(cols[1].text())
if(ball <= maxPowerBall){
pbFreq[ball] = parsePossiblyBlankNumber(cols[2].text())
}
}

def int parsePossiblyBlankNumber(String value) {
if(value.trim().length() == 0){
return 0;
} else {
return Integer.parseInt(value)
}
}

The import is found here. The long "html.BODY.TABLE..." line is needed because of how the Powerball website is set up.

I put in the parsePossiblyBlankNumber method since the website uses blanks instead of 0s when there are no frequencies.

Leave a comment if you have any questions or suggestions!

Read more...

Code Formatting in Blogger Using SyntaxHighlighter



>> Friday, August 20, 2010

I wanted to use SyntaxHighlighter, but it turns out it takes a little tweaking on Blogger. I found a number of blogs that had instructions, but none of them seemed to work. Here is what I did to get the code formatting.

1. Upload files to Google Sites (Optional)
You need to link to a few javascript and css files. It looks like SyntaxHighlighter has a hosted version, but I decided to host the specific files I wanted. Here are the files you need:

  1. shCore.js
  2. shCore.css
  3. shCoreDefault.css (or your theme, I used shCoreEclipse.css)
  4. Brushes (for type of code). I used shBrushPlain.css, shBrushJava.css, and shBrushGroovy.css
2. Edit your Blogger template
Go to Design > Edit HTML. Add this code towards the bottom:





The "trick" for blogger is to set the "bloggerMode" to true.

3. Wrap your code in "pre"
For example, if I wanted to use blog about this code in Java, I would use class="brush: java" like this:


public static void main(String[] args){
System.out.println("Hello World!");
}


And it would look like this:

public static void main(String[] args){
System.out.println("Hello World!");
}

Read more...

Fantasy Football Cheat Sheet Scraper



>> Wednesday, August 18, 2010

With my fantasy football draft coming up, I thought I would create a quick Groovy script to scrape a couple Fantasy Football cheat sheets. If you don't know, a cheat sheet has a ranking of players that you can use to make your draft picks. There are a bunch available online, and they are updated frequently (like now that Brett Favre is back with the Vikings I assume he will move up and Tarvaris Jackson will move down in rank).

Since I wanted the most up-to-date ones on the day of my draft, I wrote a couple classes in Groovy to read the webpages and print out the results in a common format. This turned out the be pretty easy to do.

For example, here is one from http://www.fftoolbox.com:


import org.cyberneko.html.parsers.SAXParser;

class FFToolbox {
public List getPlayerList(){
def playerList = []

//read the XML
['http://www.fftoolbox.com/football/2010/overall.cfm?page=1',
'http://www.fftoolbox.com/football/2010/overall.cfm?page=2',
'http://www.fftoolbox.com/football/2010/overall.cfm?page=3',
'http://www.fftoolbox.com/football/2010/overall.cfm?page=4'].each{url ->
def html = new XmlSlurper(new SAXParser()).parse(url)
def table = html.BODY.'**'.findAll{ it.name() == 'TABLE'}[0]
def rows = table.TBODY.children()[1..-2]

//convert to my BO
rows.each{ nextRow ->
def columns = nextRow.children()
playerList.add(new CheatSheetEntry(
rank: columns[0],
name: columns[1],
position: columns[2],
team: columns[3],
byeWeek: columns[4])
)
}
}
return playerList
}
}


Note that the import is from here and provides an HTML parser

Here is another example from ESPN.com:

class ESPN {
public List getPlayerList(){
def playerList = []

def url = 'http://sports.espn.go.com/fantasy/football/ffl/story?page=NFLDK2K10rankstop200'
def html = new XmlSlurper(new SAXParser()).parse(url)

def table = html.BODY.'**'.findAll{ it.name() == 'TABLE'}[0]
def rows = table.TBODY.children()

rows.each{nextRow ->
def columns = nextRow.children()
def positionMatcher = columns[3].text() =~ /\D+/
playerList.add(new CheatSheetEntry(
rank: columns[0],
name: columns[1].text().substring(0, columns[1].text().indexOf(",")),
position: positionMatcher[0],
team: columns[1].text().substring(columns[1].text().indexOf(",") + 2),
byeWeek: columns[2])
)
}

return playerList
}
}


Basically they do the same things: Connect to and parse the url(s), find the table with the cheat sheet, and then go through the rows and columns assigning the correct values to a GroovyBean called CheatSheetEntry.

Now I just need to combine the lists somehow to get an average ranking of the players.

Read more...

  © Blogger template Webnolia by Ourblogtemplates.com 2009

Back to TOP