<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Kaptain on ... stuff &#187; Development</title>
	<atom:link href="http://www.kellyrob99.com/blog/category/dev/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kellyrob99.com/blog</link>
	<description>Tales of development, life and the folly that goes along with both</description>
	<lastBuildDate>Sun, 04 Dec 2011 21:51:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Five Cool Things You Can Do With Groovy Scripts</title>
		<link>http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=five-cool-things-you-can-do-with-groovy-scripts</link>
		<comments>http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/#comments</comments>
		<pubDate>Sun, 04 Dec 2011 21:51:34 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[gist]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Gradle]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[Hudson]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[jenkins]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[JsonSlurper]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1761</guid>
		<description><![CDATA[1. Ensure all of your Jenkins builds are building the correct branch from source control I manage a large number of builds at work, spread across several build servers. When we release a new version all of the builds need to be updated to point to new working branches. This script takes advantage of the [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/' rel='bookmark' title='Using Gradle to Bootstrap your Legacy Ant Builds'>Using Gradle to Bootstrap your Legacy Ant Builds</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/' rel='bookmark' title='Hooking into the Jenkins(Hudson) API'>Hooking into the Jenkins(Hudson) API</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h2>1. Ensure all of your Jenkins builds are building the correct branch from source control</h2>
<p>I manage a large number of builds at work, spread across several build servers. When we release a new version all of the builds need to be updated to point to new working branches. This script takes advantage of the fact that our branches all end in the version number to quickly check that all of the last builds were on the expected version.<br />
Using the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API">Jenkins API</a> is very easy and the new capabilities of Groovy introduced by <a href="http://groovy.codehaus.org/gapi/groovy/json/JsonSlurper.html">JSONSlurper</a> make it easier than ever to consume.<br />
<script src="http://gist.github.com/1430845.js?file=jenkinsSVNVersionChecker.groovy"></script><noscript><link rel="stylesheet" href="https://gist.github.com/stylesheets/gist/embed.css"><div id="gist-1430845" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kn">import</span> <span class="nn">groovy.json.JsonSlurper</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="k">assert</span> <span class="n">args</span> <span class="o">&amp;&amp;</span> <span class="n">args</span><span class="o">.</span><span class="na">size</span><span class="o">()</span> <span class="o">==</span> <span class="mi">2</span></div><div class='line' id='LC4'><span class="n">def</span> <span class="n">urls</span> <span class="o">=</span> <span class="n">args</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="na">split</span><span class="o">(</span><span class="sc">&#39;,&#39;</span><span class="o">)</span></div><div class='line' id='LC5'><span class="n">def</span> <span class="n">expectedVersion</span> <span class="o">=</span> <span class="n">args</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span></div><div class='line' id='LC6'><span class="n">urls</span><span class="o">.</span><span class="na">each</span> <span class="o">{</span> <span class="n">url</span> <span class="o">-&gt;</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">println</span> <span class="s">&quot;examining url $url&quot;</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">def</span> <span class="n">json</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JsonSlurper</span><span class="o">().</span><span class="na">parseText</span><span class="o">(</span><span class="n">url</span><span class="o">.</span><span class="na">toURL</span><span class="o">().</span><span class="na">text</span><span class="o">)</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">json</span><span class="o">.</span><span class="na">jobs</span><span class="o">.</span><span class="na">each</span> <span class="o">{</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">try</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">{</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">def</span> <span class="n">job</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JsonSlurper</span><span class="o">().</span><span class="na">parseText</span><span class="o">(</span><span class="s">&quot;${it.url}/api/json?depth=1&quot;</span><span class="o">.</span><span class="na">toURL</span><span class="o">().</span><span class="na">text</span><span class="o">)</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="o">(!</span><span class="n">job</span><span class="o">.</span><span class="na">builds</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="na">changeSet</span><span class="o">.</span><span class="na">revisions</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="na">module</span><span class="o">.</span><span class="na">endsWith</span><span class="o">(</span><span class="n">expectedVersion</span><span class="o">))</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">{</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">println</span> <span class="s">&quot;$it.url fails!&quot;</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">else</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">{</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">println</span> <span class="s">&quot;$it.url passes!&quot;</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">catch</span> <span class="o">(</span><span class="n">e</span><span class="o">)</span></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">{</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">println</span> <span class="s">&quot;Exception thrown processing $it.url : $e&quot;</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC28'><span class="o">}</span></div><div class='line' id='LC29'><br/></div><div class='line' id='LC30'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1430845/bbc1beba1dfd59a6fe9925af14d301460202f0d3/jenkinsSVNVersionChecker.groovy" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1430845#file_jenkins_svn_version_checker.groovy" style="float:right;margin-right:10px;color:#666">jenkinsSVNVersionChecker.groovy</a>
            <a href="https://gist.github.com/1430845">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</noscript></p>
<h2>2. Look up the artifacts from the last successful Jenkins build</h2>
<p>This is very handy if you want to automate deployment of software from your build system and can replace a lot of error prone manual updating of scripts. In this particular example you can link up quickly with the latest, greatest build of JRuby from <a href="http://ci.jruby.org/">their public CI server</a>.<br />
<script src="http://gist.github.com/1430856.js?file=jenkinsBuildArtifacts.groovy"></script><noscript><link rel="stylesheet" href="https://gist.github.com/stylesheets/gist/embed.css"><div id="gist-1430856" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kn">import</span> <span class="nn">groovy.json.*</span></div><div class='line' id='LC2'><span class="n">def</span> <span class="n">HOSTNAME</span> <span class="o">=</span> <span class="err">&#39;</span><span class="nl">http:</span><span class="c1">//ci.jruby.org&#39;</span></div><div class='line' id='LC3'><span class="n">def</span> <span class="n">JOBNAME</span> <span class="o">=</span> <span class="err">&#39;</span><span class="n">jruby</span><span class="o">-</span><span class="n">dist</span><span class="err">&#39;</span></div><div class='line' id='LC4'><span class="n">def</span> <span class="n">JOB_URL</span> <span class="o">=</span> <span class="s">&quot;$HOSTNAME/job/$JOBNAME/lastSuccessfulBuild&quot;</span></div><div class='line' id='LC5'><span class="n">def</span> <span class="n">text</span> <span class="o">=</span> <span class="s">&quot;$JOB_URL/api/json&quot;</span><span class="o">.</span><span class="na">toURL</span><span class="o">().</span><span class="na">text</span></div><div class='line' id='LC6'><span class="n">println</span> <span class="n">JsonOutput</span><span class="o">.</span><span class="na">prettyPrint</span><span class="o">(</span><span class="n">text</span><span class="o">)</span></div><div class='line' id='LC7'><span class="n">def</span> <span class="n">json</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JsonSlurper</span><span class="o">().</span><span class="na">parseText</span><span class="o">(</span><span class="n">text</span><span class="o">)</span></div><div class='line' id='LC8'><span class="n">json</span><span class="o">.</span><span class="na">artifacts</span><span class="o">.</span><span class="na">each</span><span class="o">{</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">println</span> <span class="n">it</span></div><div class='line' id='LC10'><span class="o">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1430856/cea0186a862217015fb4fc2b63eb0ad3575c06fc/jenkinsBuildArtifacts.groovy" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1430856#file_jenkins_build_artifacts.groovy" style="float:right;margin-right:10px;color:#666">jenkinsBuildArtifacts.groovy</a>
            <a href="https://gist.github.com/1430856">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</noscript><br />
Here&#8217;s the sample output at time of writing:</p>
<blockquote><p>[relativePath:dist/jruby-bin-1.7.0.dev.tar.gz, fileName:jruby-bin-1.7.0.dev.tar.gz, displayPath:null]<br />
[relativePath:dist/jruby-bin-1.7.0.dev.tar.gz.md5, fileName:jruby-bin-1.7.0.dev.tar.gz.md5, displayPath:null]<br />
[relativePath:dist/jruby-bin-1.7.0.dev.tar.gz.sha1, fileName:jruby-bin-1.7.0.dev.tar.gz.sha1, displayPath:null]<br />
[relativePath:dist/jruby-bin-1.7.0.dev.zip, fileName:jruby-bin-1.7.0.dev.zip, displayPath:null]<br />
[relativePath:dist/jruby-bin-1.7.0.dev.zip.md5, fileName:jruby-bin-1.7.0.dev.zip.md5, displayPath:null]<br />
[relativePath:dist/jruby-bin-1.7.0.dev.zip.sha1, fileName:jruby-bin-1.7.0.dev.zip.sha1, displayPath:null]<br />
[relativePath:dist/jruby-complete-1.7.0.dev.jar, fileName:jruby-complete-1.7.0.dev.jar, displayPath:null]<br />
[relativePath:dist/jruby-complete-1.7.0.dev.jar.md5, fileName:jruby-complete-1.7.0.dev.jar.md5, displayPath:null]<br />
[relativePath:dist/jruby-complete-1.7.0.dev.jar.sha1, fileName:jruby-complete-1.7.0.dev.jar.sha1, displayPath:null]<br />
[relativePath:dist/jruby-jars-1.7.0.dev.gem, fileName:jruby-jars-1.7.0.dev.gem, displayPath:null]<br />
[relativePath:dist/jruby-jars-1.7.0.dev.gem.md5, fileName:jruby-jars-1.7.0.dev.gem.md5, displayPath:null]<br />
[relativePath:dist/jruby-jars-1.7.0.dev.gem.sha1, fileName:jruby-jars-1.7.0.dev.gem.sha1, displayPath:null]<br />
[relativePath:dist/jruby-src-1.7.0.dev.tar.gz, fileName:jruby-src-1.7.0.dev.tar.gz, displayPath:null]<br />
[relativePath:dist/jruby-src-1.7.0.dev.tar.gz.md5, fileName:jruby-src-1.7.0.dev.tar.gz.md5, displayPath:null]<br />
[relativePath:dist/jruby-src-1.7.0.dev.tar.gz.sha1, fileName:jruby-src-1.7.0.dev.tar.gz.sha1, displayPath:null]<br />
[relativePath:dist/jruby-src-1.7.0.dev.zip, fileName:jruby-src-1.7.0.dev.zip, displayPath:null]<br />
[relativePath:dist/jruby-src-1.7.0.dev.zip.md5, fileName:jruby-src-1.7.0.dev.zip.md5, displayPath:null]<br />
[relativePath:dist/jruby-src-1.7.0.dev.zip.sha1, fileName:jruby-src-1.7.0.dev.zip.sha1, displayPath:null]</p></blockquote>
<h2>3. Read in a CSV file, filter it, and write out the result</h2>
<p>Groovy Grapes and one of my favorite libraries, <a href="http://opencsv.sourceforge.net/">OpenCSV</a>, make it trivial to script &#8216;one off&#8217; solutions for removing work that would normally take place manually in Excel. For me it comes up most often with data import/export from systems I&#8217;m working on and the need to create particular test environments using those import/export mechanisms. For example, using a scripted solution like this you can quickly:</p>
<ul>
<li>Export users from one test system into a CSV file, along with local phone number contact data</li>
<li>Replace the existing phone numbers with a mix of local and international numbers</li>
<li>Import the new data into a different test system</li>
<li>Verify that the system properly deals with international calling concerns</li>
</ul>
<p>This example simply trims out all of the rows where the second column of input contains values less than 100. It&#8217;s also nice to note that OpenCSV is smart enough to let you ignore one or more &#8216;header rows&#8217;, a common attribute of CSV files.<br />
<script src="http://gist.github.com/1430935.js?file=openCsv.groovy"></script><noscript><link rel="stylesheet" href="https://gist.github.com/stylesheets/gist/embed.css"><div id="gist-1430935" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nd">@Grab</span><span class="o">(</span><span class="n">group</span> <span class="o">=</span> <span class="err">&#39;</span><span class="n">net</span><span class="o">.</span><span class="na">sf</span><span class="o">.</span><span class="na">opencsv</span><span class="err">&#39;</span><span class="o">,</span> <span class="n">module</span> <span class="o">=</span> <span class="err">&#39;</span><span class="n">opencsv</span><span class="err">&#39;</span><span class="o">,</span> <span class="n">version</span> <span class="o">=</span> <span class="err">&#39;</span><span class="mf">2.3</span><span class="err">&#39;</span><span class="o">)</span></div><div class='line' id='LC2'><span class="kn">import</span> <span class="nn">au.com.bytecode.opencsv.CSVReader</span></div><div class='line' id='LC3'><span class="kn">import</span> <span class="nn">au.com.bytecode.opencsv.CSVParser</span></div><div class='line' id='LC4'><span class="kn">import</span> <span class="nn">au.com.bytecode.opencsv.CSVWriter</span></div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'><span class="n">def</span> <span class="n">TEST_FILE_NAME</span> <span class="o">=</span> <span class="err">&#39;</span><span class="n">test</span><span class="o">.</span><span class="na">csv</span><span class="err">&#39;</span></div><div class='line' id='LC7'><span class="n">def</span> <span class="n">TEST_OUTPUT_FILE_NAME</span> <span class="o">=</span> <span class="err">&#39;</span><span class="n">testOut</span><span class="o">.</span><span class="na">csv</span><span class="err">&#39;</span></div><div class='line' id='LC8'><br/></div><div class='line' id='LC9'><span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">[]&gt;</span> <span class="n">rows</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CSVReader</span><span class="o">(</span><span class="k">new</span> <span class="n">FileReader</span><span class="o">(</span><span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">TEST_FILE_NAME</span><span class="o">)),</span> <span class="n">CSVParser</span><span class="o">.</span><span class="na">DEFAULT_SEPARATOR</span><span class="o">,</span> <span class="n">CSVParser</span><span class="o">.</span><span class="na">DEFAULT_ESCAPE_CHARACTER</span><span class="o">,</span> <span class="n">CSVParser</span><span class="o">.</span><span class="na">DEFAULT_QUOTE_CHARACTER</span><span class="o">,</span> <span class="mi">1</span><span class="o">).</span><span class="na">readAll</span><span class="o">()</span></div><div class='line' id='LC10'><span class="n">def</span> <span class="n">rowsOver100</span> <span class="o">=</span> <span class="n">rows</span><span class="o">.</span><span class="na">findAll</span> <span class="o">{</span><span class="n">it</span><span class="o">[</span><span class="mi">1</span><span class="o">].</span><span class="na">toInteger</span><span class="o">()</span> <span class="o">&gt;</span> <span class="mi">100</span><span class="o">}</span></div><div class='line' id='LC11'><br/></div><div class='line' id='LC12'><span class="n">File</span> <span class="n">output</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">TEST_OUTPUT_FILE_NAME</span><span class="o">)</span></div><div class='line' id='LC13'><span class="k">if</span> <span class="o">(</span><span class="n">output</span><span class="o">.</span><span class="na">exists</span><span class="o">())</span></div><div class='line' id='LC14'><span class="o">{</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">output</span><span class="o">.</span><span class="na">delete</span><span class="o">()</span></div><div class='line' id='LC16'><span class="o">}</span></div><div class='line' id='LC17'><span class="n">output</span><span class="o">.</span><span class="na">createNewFile</span><span class="o">()</span></div><div class='line' id='LC18'><span class="n">output</span><span class="o">.</span><span class="na">withWriter</span> <span class="o">{</span> <span class="n">writer</span> <span class="o">-&gt;</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">new</span> <span class="nf">CSVWriter</span><span class="o">(</span><span class="n">writer</span><span class="o">).</span><span class="na">writeAll</span><span class="o">(</span><span class="n">rowsOver100</span><span class="o">)</span></div><div class='line' id='LC20'><br/></div><div class='line' id='LC21'><span class="o">}</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'><span class="c1">//println rows</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1430935/0c21cfe5a273ed552193c3b94e379d3bb941a5e6/openCsv.groovy" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1430935#file_open_csv.groovy" style="float:right;margin-right:10px;color:#666">openCsv.groovy</a>
            <a href="https://gist.github.com/1430935">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</noscript></p>
<h2>4. Download, install and run a stand-alone webserver</h2>
<p>This example comes courtesy of a <a href="http://www.ibm.com/developerworks/java/library/j-javadev2-20/index.html">recent article by Andrew Glover</a> about <a href="https://github.com/groovypp/gretty/wiki">Gretty</a>, a lightweight http server. I don&#8217;t have a concrete use-case for this right now, but it&#8217;s easy to note that in this case you can code a large part of the server behaviour directly in the script, unlike, for instance, if you were to use a script to stand up a Jetty server. This should let you publish a script once in a central location and stand up as many Gretty servers providing the declared services as you like. This particular example simply echos back &#8216;Hello&#8217; plus whatever path you append to localhost:8080.<br />
<script src="http://gist.github.com/1431012.js?file=grettyExample.groovy"></script><noscript><link rel="stylesheet" href="https://gist.github.com/stylesheets/gist/embed.css"><div id="gist-1431012" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kn">import</span> <span class="nn">org.mbte.gretty.httpserver.*</span> </div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="nd">@GrabResolver</span><span class="o">(</span><span class="n">name</span><span class="o">=</span><span class="err">&#39;</span><span class="n">gretty</span><span class="err">&#39;</span><span class="o">,</span> </div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="n">root</span><span class="o">=</span><span class="err">&#39;</span><span class="nl">http:</span><span class="c1">//groovypp.artifactoryonline.com/groovypp/libs-releases-local&#39;)</span></div><div class='line' id='LC5'><span class="nd">@Grab</span><span class="o">(</span><span class="err">&#39;</span><span class="n">org</span><span class="o">.</span><span class="na">mbte</span><span class="o">.</span><span class="na">groovypp</span><span class="o">:</span><span class="nl">gretty:</span><span class="mf">0.4</span><span class="o">.</span><span class="mi">279</span><span class="err">&#39;</span><span class="o">)</span> </div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'><span class="n">GrettyServer</span> <span class="n">server</span> <span class="o">=</span> <span class="o">[]</span> </div><div class='line' id='LC8'><span class="n">server</span><span class="o">.</span><span class="na">groovy</span> <span class="o">=</span> <span class="o">[</span> </div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nl">localAddress:</span> <span class="k">new</span> <span class="n">InetSocketAddress</span><span class="o">(</span><span class="s">&quot;localhost&quot;</span><span class="o">,</span> <span class="mi">8080</span><span class="o">),</span> </div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nl">defaultHandler:</span> <span class="o">{</span> </div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">response</span><span class="o">.</span><span class="na">redirect</span> <span class="s">&quot;/&quot;</span> </div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">},</span> </div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s">&quot;/:name&quot;</span><span class="o">:</span> <span class="o">{</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">get</span> <span class="o">{</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">response</span><span class="o">.</span><span class="na">text</span> <span class="o">=</span> <span class="s">&quot;Hello ${request.parameters[&#39;name&#39;]}&quot;</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span> </div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span> </div><div class='line' id='LC18'><span class="o">]</span> </div><div class='line' id='LC19'><span class="n">server</span><span class="o">.</span><span class="na">start</span><span class="o">()</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1431012/e0bcf55e0b19d2cf070dab3d3797d2ee0b231655/grettyExample.groovy" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1431012#file_gretty_example.groovy" style="float:right;margin-right:10px;color:#666">grettyExample.groovy</a>
            <a href="https://gist.github.com/1431012">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</noscript></p>
<h2>5. Remotely execute any of these scripts by url</h2>
<p>As of <a title="Groovy 1.8.3/1.9-beta-4" href="http://glaforge.appspot.com/article/groovy-1-8-3-and-1-9-beta-4-released" target="_blank">Groovy 1.8.3/1.9-beta-4</a> you can refer to a Groovy script hosted at a remote url and execute it locally. If you work on different machines a lot(as I do) this can really help keep your toolbox of scripts handy, regardless of where you are. Since these scripts are publicly hosted on GitHub(thanks guys!), you can simply copy the url from the &#8216;view raw&#8217; link at the bottom and go to your console to execute them like this:</p>
<pre class="brush: groovy; title: ; notranslate">
$ groovy https://gist.github.com/raw/1430856/cea0186a862217015fb4fc2b63eb0ad3575c06fc/jenkinsBuildArtifacts.groovy
{
    &quot;actions&quot;: [
        {
            &quot;causes&quot;: [
                {
                    &quot;shortDescription&quot;: &quot;Started by timer&quot;
                }
            ]
        },
        {
            &quot;buildsByBranchName&quot;: {
                &quot;origin/master&quot;: {
                    &quot;buildNumber&quot;: 684,
                    &quot;buildResult&quot;: null,
                    &quot;revision&quot;: {
                        &quot;SHA1&quot;: &quot;3419fee4bb9436d3222ff3df8dd7fcf2308a6919&quot;,
                        &quot;branch&quot;: [
                            {
                                &quot;SHA1&quot;: &quot;3419fee4bb9436d3222ff3df8dd7fcf2308a6919&quot;,
                                &quot;name&quot;: &quot;origin/master&quot;
                            }
                        ]
                    }
                }
            },
... and so on
</pre>
<h2>Final note</h2>
<p>Being able to share scripts across a variety of machines has definitely made my professional life a lot easier and I&#8217;m very glad to see the ability to execute code from a URL in Groovy. But what really turned me onto the idea was its usage in Gradle, which supports loading remote Groovy/Gradle scripts using the &#8220;apply from: {url or file}&#8221; syntax. I find that more and more I reference particular tasks remotely in a build, especially for static analysis tools that don&#8217;t necessarily need to be run on a regular basis.<br />
A great example of this is the recently released <a href="http://tellurianring.com/wiki/gradle/templates">Gradle Templates Plugin</a>, which is basically the Gradle answer to the <a href="http://maven.apache.org/archetype/maven-archetype-plugin/">Maven Archetype plugin</a>. Create a build.gradle with the following content:</p>
<pre class="brush: groovy; title: ; notranslate">
apply from: 'http://launchpad.net/gradle-templates/trunk/1.2/+download/apply.groovy'
</pre>
<p>And we have the following tasks available to create new Gradle projects and objects with conventional structure:</p>
<pre class="brush: groovy; title: ; notranslate">
Template tasks
--------------
createGradlePlugin - Creates a new Gradle Plugin project in a new directory named after your project.
createGroovyClass - Creates a new Groovy class in the current project.
createGroovyProject - Creates a new Gradle Groovy project in a new directory named after your project.
createJavaClass - Creates a new Java class in the current project.
createJavaProject - Creates a new Gradle Java project in a new directory named after your project.
createScalaClass - Creates a new Scala class in the current project.
createScalaObject - Creates a new Scala object in the current project.
createScalaProject - Creates a new Gradle Scala project in a new directory named after your project.
createWebappProject - Creates a new Gradle Webapp project in a new directory named after your project.
exportAllTemplates - Exports all the default template files into the current directory.
exportGroovyTemplates - Exports the default groovy template files into the current directory.
exportJavaTemplates - Exports the default java template files into the current directory.
exportPluginTemplates - Exports the default plugin template files into the current directory.
exportScalaTemplates - Exports the default scala template files into the current directory.
exportWebappTemplates - Exports the default webapp template files into the current directory.
initGradlePlugin - Initializes a new Gradle Plugin project in the current directory.
initGroovyProject - Initializes a new Gradle Groovy project in the current directory.
initJavaProject - Initializes a new Gradle Java project in the current directory.
initScalaProject - Initializes a new Gradle Scala project in the current directory.
initWebappProject - Initializes a new Gradle Webapp project in the current directory.
</pre>
<!-- AdSense Now! V1.95 -->
<!-- Post[count: 2] -->
<div class="adsense adsense-leadout" style="float:right;margin: 12px;"><script type="text/javascript"><!--
google_ad_client = "pub-6955914197200080";
/* 728x90, created 8/3/09 */
google_ad_slot = "4051815125";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/' rel='bookmark' title='Using Gradle to Bootstrap your Legacy Ant Builds'>Using Gradle to Bootstrap your Legacy Ant Builds</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/' rel='bookmark' title='Hooking into the Jenkins(Hudson) API'>Hooking into the Jenkins(Hudson) API</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Gradle to Bootstrap your Legacy Ant Builds</title>
		<link>http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=using-gradle-to-bootstrap-your-legacy-ant-builds</link>
		<comments>http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/#comments</comments>
		<pubDate>Sun, 18 Sep 2011 20:44:11 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[AntBuilder]]></category>
		<category><![CDATA[Gradle]]></category>
		<category><![CDATA[GradleBuild]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[Source code]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1422</guid>
		<description><![CDATA[Gradle provides several different ways to leverage your existing investment in Ant, both in terms of accumulated knowledge and the time you&#8217;ve already put into build files. This can greatly facilitate the process of porting Ant built projects over to Gradle, and can give you a path for incrementally doing so. The Gradle documentation does [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/11/13/why-do-i-like-gradle/' rel='bookmark' title='Why do I Like Gradle?'>Why do I Like Gradle?</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/04/03/a-groovygradle-jslint-plugin/' rel='bookmark' title='A Groovy/Gradle JSLint Plugin'>A Groovy/Gradle JSLint Plugin</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/' rel='bookmark' title='Five Cool Things You Can Do With Groovy Scripts'>Five Cool Things You Can Do With Groovy Scripts</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>Gradle provides several different ways to leverage your existing investment in Ant, both in terms of accumulated knowledge and the time you&#8217;ve already put into build files. This can greatly facilitate the process of porting Ant built projects over to Gradle, and can give you a path for incrementally doing so. The <a href="http://gradle.org/current/docs/userguide/userguide_single.html#ant">Gradle documentation</a> does a good job of describing how you can use Ant in your Gradle build script, but here&#8217;s a quick overview and some particulars I&#8217;ve run into myself.</p>
<p></p>
<h2>Gradle AntBuilder</h2>
<p>Every Gradle Project includes an AntBuilder instance, making any and all of the facilities of Ant available within your build files. Gradle provides a simple extension to the existing Groovy AntBuilder which adds a simple yet powerful way to interface with existing Ant build files: the <em>importBuild(Object antBuildFile)</em> method. Internally this method utilizes an Ant ProjectHelper to parse the specified Ant build file and then wraps all of the targets in Gradle tasks making them available in the Gradle build. The following is a simple Ant build file used for illustration which contains some properties and a couple of dependent targets.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;project name=&quot;build&quot; default=&quot;all&quot;&gt;
    &lt;echo&gt;Building ${ant.file}&lt;/echo&gt;

    &lt;property file=&quot;build.properties&quot;/&gt;
    &lt;property name=&quot;root.dir&quot; location=&quot;.&quot;/&gt;

    &lt;target name=&quot;dist&quot; description=&quot;Build the distribution&quot;&gt;
        &lt;property name=&quot;dist.dir&quot; location=&quot;dist&quot;/&gt;
        &lt;echo&gt;dist.dir=${dist.dir}, foo=${foo}&lt;/echo&gt;
    &lt;/target&gt;

    &lt;target name=&quot;all&quot; description=&quot;Build everything&quot; depends=&quot;dist&quot;/&gt;
&lt;/project&gt;
</pre>
<p>
Importing this build file using Gradle is a one-liner.<br />
</p>
<pre class="brush: groovy; title: ; notranslate">
ant.importBuild('src/main/resources/build.xml')
</pre>
<p>
And the output of gradle tasks &#8211;all on the command line shows that the targets have been added to the build tasks.<br />
</p>
<pre class="brush: groovy; title: ; notranslate">
$ gradle tasks --all
...
Other tasks
-----------
all - Build everything
    dist - Build the distribution
...
</pre>
<p>
Properties used in the Ant build file can be specified in the Gradle build or on the command line and, unlike the usual Ant property behaviour, properties set by Ant or on the command line may be overwritten by Gradle. Given a simple build.properties file with <em>foo=bar</em> as the single entry, here&#8217;s a few combinations to demonstrate the override behaviour.<br />

<table id="wp-table-reloaded-id-6-no-1" class="wp-table-reloaded wp-table-reloaded-id-6">
<thead>
	<tr class="row-1 odd">
		<th class="column-1">Command line invocation</th><th class="column-2">Gradle Build Config</th><th class="column-3">Effect</th><th class="column-4">Result</th>
	</tr>
</thead>
<tbody>
	<tr class="row-2 even">
		<td class="column-1">gradle dist</td><td class="column-2">ant.importBuild('src/main/resources/build.xml')</td><td class="column-3">build.properties value loaded from ant build is used</td><td class="column-4">foo=bar</td>
	</tr>
	<tr class="row-3 odd">
		<td class="column-1">gradle dist -Dfoo=NotBar</td><td class="column-2">ant.importBuild('src/main/resources/build.xml')</td><td class="column-3">command line property is used</td><td class="column-4">foo=NotBar</td>
	</tr>
	<tr class="row-4 even">
		<td class="column-1">gradle dist -Dfoo=NotBar</td><td class="column-2">ant.foo='NotBarFromGradle' <br />
ant.importBuild('src/main/resources/build.xml')</td><td class="column-3">Gradle build property is used</td><td class="column-4">foo=NotBarFromGradle</td>
	</tr>
	<tr class="row-5 odd">
		<td class="column-1">gradle dist -Dfoo=NotBar</td><td class="column-2">ant.foo='NotBarFromGradle'<br />
ant.importBuild('src/main/resources/build.xml')<br />
ant.foo='NotBarFromGradleAgain'</td><td class="column-3">Gradle build property override is used</td><td class="column-4">foo=NotBarFromGradleAgain</td>
	</tr>
</tbody>
</table>
</p>
<h2>How to deal with task name clashes</h2>
<p>Since Gradle insists on uniqueness of task names attempting to import an Ant build that contains a target with the same name as an existing Gradle task will fail. The most common clash I&#8217;ve encountered is with the <em>clean</em> task provided by the Gradle BasePlugin. With the help of a little bit of indirection we can still import and use any clashing targets by utilizing the GradleBuild task to bootstrap an Ant build import in an isolated Gradle project. Let&#8217;s add a new task to the mix in the Ant build imported and another dependency on the ant <em>clean</em> target to the <em>all</em> task. </p>
<pre class="brush: xml; title: ; notranslate">
&lt;!-- excerpt from buildWithClean.xml Ant build file --&gt;
    &lt;target name=&quot;clean&quot; description=&quot;clean up&quot;&gt;
        &lt;echo&gt;Called clean task in ant build with foo = ${foo}&lt;/echo&gt;
    &lt;/target&gt;
    &lt;target name=&quot;all&quot; description=&quot;Build everything&quot; depends=&quot;dist,clean&quot;/&gt;
</pre>
<p>And a simple Gradle build file which will handle the import.</p>
<pre class="brush: groovy; title: ; notranslate">
ant.importBuild('src/main/resources/buildWithClean.xml')
</pre>
<p>Finally, in our main gradle build file we add a task to run the targets we want.</p>
<pre class="brush: groovy; title: ; notranslate">
task importTaskWithExistingName(type: GradleBuild) { GradleBuild antBuild -&gt;
    antBuild.buildFile ='buildWithClean.gradle'
    antBuild.tasks = ['all']
}
</pre>
<p>This works, but unfortunately suffers from <a href="http://issues.gradle.org/browse/GRADLE-427">one small problem</a>. When Gradle is importing these tasks it doesn&#8217;t properly respect the declared order of the dependencies. Instead it executes the dependent ant targets in alphabetical order. In this particular case Ant expects to execute the <em>dist</em> target before <em>clean</em> and Gradle executes them in the reverse order. This can be worked around by explicitly stating the task order, definitely not ideal, but workable. This Gradle task will execute the  underlying Ant targets in the way we need.</p>
<pre class="brush: groovy; title: ; notranslate">
task importTasksRunInOrder(type: GradleBuild) { GradleBuild antBuild -&gt;
    antBuild.buildFile ='buildWithClean.gradle'
    antBuild.tasks = ['dist', 'clean']
}
</pre>
<h2>Gradle Rules for the rest</h2>
<p>Finally, you can use a Gradle Rule to allow for calling any arbitrary target in a GradleBuild bootstrapped import.</p>
<pre class="brush: groovy; title: ; notranslate">
tasks.addRule(&quot;Pattern: a-&lt;target&gt; will execute a single &lt;target&gt; in the ant build&quot;) { String taskName -&gt;
    if (taskName.startsWith(&quot;a-&quot;)) {
        task(taskName, type: GradleBuild) {
            buildFile = 'buildWithClean.gradle'
            tasks = [taskName - 'a-']
        }
    }
}
</pre>
<p>In this particular example, this can allow you to string together calls as well, but be warned that they execute in completely segregated environments.</p>
<pre class="brush: groovy; title: ; notranslate">
$ gradle a-dist a-clean
</pre>
<h2>Source code</h2>
<p>All of code referenced in this article is <a href="https://github.com/kellyrob99/gradleAntImport">available on github</a> if you&#8217;d like to take a closer look.</p>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/11/13/why-do-i-like-gradle/' rel='bookmark' title='Why do I Like Gradle?'>Why do I Like Gradle?</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/04/03/a-groovygradle-jslint-plugin/' rel='bookmark' title='A Groovy/Gradle JSLint Plugin'>A Groovy/Gradle JSLint Plugin</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/' rel='bookmark' title='Five Cool Things You Can Do With Groovy Scripts'>Five Cool Things You Can Do With Groovy Scripts</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Groovy/Gradle JSLint Plugin</title>
		<link>http://www.kellyrob99.com/blog/2011/04/03/a-groovygradle-jslint-plugin/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-groovygradle-jslint-plugin</link>
		<comments>http://www.kellyrob99.com/blog/2011/04/03/a-groovygradle-jslint-plugin/#comments</comments>
		<pubDate>Mon, 04 Apr 2011 01:07:31 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[example]]></category>
		<category><![CDATA[Gradle]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[GroovyMag]]></category>
		<category><![CDATA[JSLint]]></category>
		<category><![CDATA[kellyrob]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[Source code]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1552</guid>
		<description><![CDATA[This article originally appeared in the January 2011 issue of GroovyMag. Gradle is a build system in which builds are described using a declarative and concise DSL written in the Groovy language. This article describes how you can wrap proven Apache Ant Tasks in a Gradle Plugin to make using them as effortless as possible. [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/' rel='bookmark' title='Using Gradle to Bootstrap your Legacy Ant Builds'>Using Gradle to Bootstrap your Legacy Ant Builds</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/11/13/why-do-i-like-gradle/' rel='bookmark' title='Why do I Like Gradle?'>Why do I Like Gradle?</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><em>This article originally appeared in the January 2011 issue of <a href="http://www.groovymag.com/">GroovyMag</a>.</em></p>
<blockquote><p>Gradle is a build system in which builds are described using a declarative and concise DSL written in the Groovy language. This article describes how you can wrap proven Apache Ant Tasks in a Gradle Plugin to make using them as effortless as possible. We&#8217;ll also go over some of the tools Gradle provides for building and testing robust Plugin functionality following some easy patterns.</p></blockquote>
<p>Creating new custom Plugins for Gradle is a relatively straightforward and easy process. Within a Plugin it&#8217;s possible to configure a Gradle Project with new properties, dependencies, Tasks &#8211; pretty much anything that you can configure in a build.gradle file can be encapsulated into a Plugin for abstraction, portability and reuse. One of the easier ways to add functionality through a Plugin is to encapsulate an existing Ant Task and enhance it by providing the ease-of-use and configuration that Gradle users have come to expect. Recently, I&#8217;ve been writing a lot more JavaScript and was looking for static analysis tools to help guide me away from &#8216;bad habits&#8217;. The popular choice for static analysis of  JavaScript code seems to be <a href="http://www.jslint.com">JSLint</a>, so here&#8217;s an example of providing that functionality for a Gradle build by wrapping an existing <a href="http://jslint4java.googlecode.com/svn/docs/1.4/ant.html">JSLint task</a> and making it easier to work with.</p>
<p></p>
<h2>Anatomy of a Gradle Plugin</h2>
<p>Gradle plugins can most easily be built using Gradle itself. There is a conveniently available <strong>gradleApi()</strong> method you can call to include the required framework classes, demonstrated in the dependencies section of a build.gradle file shown in Listing 1. For this example we&#8217;re also using the <a href="http://gradle.org/latest/docs/userguide/groovy_plugin.html">Groovy Plugin</a> and <a href="http://www.junit.org/">JUnit</a> for testing, so we will include those dependencies as well.</p>
<pre class="brush: groovy; title: ; notranslate">
dependencies {
    compile gradleApi()
    groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.6'
    testCompile group: 'junit', name: 'junit', version: '4.8.2
}
</pre>
<p><em>Listing 1: The dependencies portion of a build.gradle file for building our Plugin </em></p>
<p>Creating a new Gradle <a href="http://www.gradle.org/latest/docs/javadoc/org/gradle/api/Plugin.html">Plugin</a> is a simple matter of implementing the Gradle interface and its single required method, the skeleton of which is shown in Listing 2. Within the apply method, the Plugin can configure the Project to add Tasks or properties as needed.</p>
<pre class="brush: groovy; title: ; notranslate">
class JSLintPlugin implements Plugin&lt;Project&gt;
{
	void apply(Project project)
	{
		//configure the Project here
	}
}
</pre>
<p><em>Listing 2: Skeleton of the Plugin implementation</em></p>
<p></p>
<h2>Integrating with Ant</h2>
<p>I&#8217;ve never been overly fond of <a href="http://ant.apache.org/">Ant</a>, mostly due to the extremely verbose and repetitive nature of the xml declaration. But the fact remains that Ant has been a primary and well-used build tool for years, and the Tasks written for it have been tried and tested by many developers. The Groovy <a href="http://groovy.codehaus.org/api/groovy/util/AntBuilder.html">AntBuilder</a>, in combination with the facilities Gradle provides for dependency resolution and classpath management, makes it very easy to incorporate existing Ant functionality into a build and abstract most of the details away from the end user. For this plugin, we add the library containing the Ant Task to a custom configuration so that we can have it automatically downloaded and easily resolve the classpath.<br />
Listing 3 shows how the configuration for the JSLint4Java Task could appear in an Ant build.xml file. Note that you&#8217;re on your own here to provide the required library for the classpath.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;taskdef name=&quot;jslint&quot;
         classname=&quot;com.googlecode.jslint4java.ant.JSLintTask&quot;
         classpath=&quot;/path/to/jslint4java-1.4.jar&quot;/&gt;
&lt;target name=&quot;jslint&quot;&gt;
    &lt;jslint options=&quot;undef,white&quot; haltOnFailure=&quot;false&quot;&gt;
        &lt;formatter type=&quot;xml&quot; destfile=&quot;${build.dir}/reports&quot;/&gt;
        &lt;fileset dir=&quot;.&quot; includes=&quot;**/*.js&quot; excludes=&quot;**/server/&quot;/&gt;
    &lt;/jslint&gt;
&lt;/target&gt;
</pre>
<p><em>Listing 3: Configuring the Ant target in a build.xml file</em></p>
<p>Gradle makes it easy to separate the configuration and execution phases of the build, allowing for a Plugin to add an Ant Task to the Gradle Project and expose the (optional) configuration in a build script. In addition, Gradle encourages a pattern of providing a &#8216;convention&#8217; object alongside of a Plugin to clearly separate the concerns.<br />
Listing 4 demonstrates some code from the Plugin implementation that adds a &#8216;jslint&#8217; Task to a Gradle Project, setting the specific options based on a convention object. Note how we extract the classpath using the notation  <strong>project.configurations.jslint.asPath</strong>.</p>
<pre class="brush: groovy; title: ; notranslate">
private static final String TASK_NAME = 'jslint'
private Project project
private JSLintPluginConvention jsLintpluginConvention
...
// some of the code in the apply method
this.jsLintpluginConvention = new JSLintPluginConvention(project)
project.convention.plugins.jslint = jsLintpluginConvention
project.task(TASK_NAME) &lt;&lt; {
    project.file(project.reportsDir).mkdirs()
    logger.info(&quot;Running jslint on project ${project.name}&quot;)
    ant.taskdef(name: TASK_NAME, classname: jsLintpluginConvention.taskName,
        classpath: project.configurations.jslint.asPath)
    ant.&quot;$TASK_NAME&quot;(jsLintpluginConvention.mapTaskProperties()) {
        formatter(type: jsLintpluginConvention.decideFormat(),
                destfile:  jsLintpluginConvention.createOutputFileName())
        jsLintpluginConvention.inputDirs.each { dirName -&gt;
            fileset(dir: dirName,
			 includes: jsLintpluginConvention.includes,
			 excludes: jsLintpluginConvention.excludes)
        }
    }
}
</pre>
<p><em>Listing 4: Adding a jslint Task to a Gradle Project </em></p>
<p>If you&#8217;re not already familiar with the Gradle syntax for creating new Tasks inline, the <strong>project.task(String taskName)</strong> method is called to instantiate a new <a href="http://www.gradle.org/latest/docs/javadoc/org/gradle/api/Task.html">Task</a>, and the &#8216;< <' syntax is used to to push the Task activities into the 'doLast' Task lifecycle phase.<br />
Allowing for configuration of the Task in a build script is as simple as exposing a method named the same as the Task that takes in a Closure parameter and applies that Closure to set properties on the convention object, as shown in Listing 5.</p>
<pre class="brush: groovy; title: ; notranslate">
/**
 * Perform custom configuration of the plugin using the provided closure.
 * @param closure
 */
def jslint(Closure closure)
{
    closure.delegate = this
    closure()
}
</pre>
<p>Listing 5: A method to allow for configuration of the jslint Task from a build script </p>
<p></p>
<h2>The simple use-case</h2>
<p>As per usual when working with Gradle, using this plugin in the most basic case requires only these things:</p>
<ul>
<li>Declare a dependency on the Plugin source.  This can be either a released jar to be downloaded from a repository by Gradle or you can download a jar manually from pretty much anywhere and add it to the classpath directly.</li>
<li>Apply the Plugin to a Gradle build.</li>
<li>Call the jslint Task as part of the build.</li>
</ul>
<p>The entire configuration and usage looks something like Listing 6, assuming that the gradle-jslint-plugin jar is found in /usr/home/gradlelibs.</p>
<pre class="brush: groovy; title: ; notranslate">
/* In a build.gradle file */
buildscript {
	dependencies {
		classpath fileTree(dir: '/usr/home/gradlelibs', include: '*.jar')
	}
}
apply plugin: org.kar.jslint.gradle.plugin.JSLintPlugin

/* and on the command line... */
gradle jslint
</pre>
<p><em>Listing 6: Configuring the jslint Plugin in a build script and calling it from the command line</em></p>
<p>By default, this is enough to scan for all .js files under the directory where the build script is located and create a JSLint text report using the basic settings.</p>
<p></p>
<h2>The not-so-simple case</h2>
<p>Of course in the real world the defaults aren't always what we need, so being able to easily configure the Task is essential. Fortunately, Gradle makes extending a custom Plugin to allow for configuration by a simple Closure, so we can exercise the code from Listing 5 in a build script with the Closure  definition in Listing 7.</p>
<pre class="brush: groovy; title: ; notranslate">
jslint {
	haltOnFailure = false
	excludes = '**/metadata/'
	options = 'rhino'
	formatterType = 'html'
}
</pre>
<p><em>Listing 7: Departing from the default jslint Task configuration </em></p>
<p></p>
<h2>Extending Ant Task capabilities</h2>
<p>The Ant Task as is can produce either a plain text document or an xml report, but transforming the results into a more consumable html format is easy to do using an Ant xslt Task. Having Gradle wrap the Task definition allows for simply adding a new formatter type to the configuration and abstracting away the details from the end user. A copy of <a href="http://code.google.com/p/memwords/source/browse/trunk/jslint/jslint.xsl?r=109">an xsl file available online</a> is easy to incorporate with the plugin and can be used to transform the xml output into a nicely formatted web page.  Being able to program around Ant Tasks like this is a great way to enhance their value in your build. An example of simple output from the test cases included in the Plugin is shown in Figure 1.<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/jslint/figure1.png" title="" class="shutterset_singlepic76" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/76__x_figure1.png" alt="figure1" title="figure1" />
</a>
<br />
<em>Figure 1: Example html formatted output from jslint </em></p>
<p></p>
<h2>Testing using ProjectBuilder</h2>
<p>In order to facilitate testing custom Tasks and Plugins, the Gradle framework provides the <a href="http://www.gradle.org/latest/docs/javadoc/org/gradle/testfixtures/ProjectBuilder.html">ProjectBuilder</a> implementation to handle most of the heavy lifting. This gives you a mocked out instance of a Gradle Project that builds into a temporary directory; very handy for testing how Tasks behave under real working conditions.  Having tools like this available directly from the framework removes a lot of potential barriers that might otherwise discourage testing of custom components. The source code that accompanies this article uses the ProjectBuilder to achieve 100% code coverage of the project and is available on github at <a href="https://github.com/kellyrob99/gradle-jslint-plugin">https://github.com/kellyrob99/gradle-jslint-plugin</a> if you'd like to look closer for some ideas on how to test your own Gradle Plugins. An already built version of the jar is also available if you'd like to try without having to build it yourself: <a href="https://github.com/kellyrob99/gradle-jslint-plugin/blob/master/releases/gradle-jslint-plugin-0.1-SNAPSHOT.jar">https://github.com/kellyrob99/gradle-jslint-plugin/blob/master/releases/gradle-jslint-plugin-0.1-SNAPSHOT.jar</a>.</p>
<p></p>
<h2>How could we improve this Plugin?</h2>
<p>This implementation represents the 'brute-force' method of wrapping an Ant Task, and there are several ways to enhance its function, if we wanted to spend some additional time and effort on the Plugin. It would actually be far more flexible if we extended the Gradle <a href="http://gradle.org/latest/docs/groovydoc/org/gradle/api/DefaultTask.html">DefaultTask</a> to provide the actual functionality; this would allow for the possibility of executing the Task separately against different sets of JavaScript in the same project with different configurations of JSLint. In the case of an application with both client and server-side JavaScript, for instance, you might want to apply different rules. In that event you'd probably also want to have the capability to aggregate multiple result sets, which would be a relatively easy feature to add.<br />
Having a separate Task implementation defined would also make it easier to clearly define the inputs and outputs of the process using one of the <a href="http://gradle.org/latest/docs/javadoc/org/gradle/api/tasks/Input.html">@Input</a> or <a href="http://gradle.org/latest/docs/javadoc/org/gradle/api/tasks/Output.html">@Output</a> Gradle annotations, allowing for incremental builds including JSLint execution. The full set of annotations available from the <a href="http://gradle.org/latest/docs/javadoc/org/gradle/api/tasks/package-summary.html">org.gradle.api.tasks package</a> allow for combining File and/or simple property types to make your Tasks smarter regarding whether or not running again would produce a different result than the last execution.<br />
This article was created using the recently released 0.9 version of Gradle and version 1.4.4 of jslint4java.</p>
<p></p>
<h2>Learn more</h2>
<p>If you'd like to find out some background or more about Gradle and how to create your own custom Plugins and Tasks, you can find some good information on these sites:</p>
<ul>
<li>The Gradle documentation at <a href="http://gradle.org/documentation.html">http://gradle.org/documentation.html</a></li>
<li>In particular, the Project API is a great starting point for getting to know Gradle: <a href="http://gradle.org/latest/docs/javadoc/org/gradle/api/Project.html">http://gradle.org/latest/docs/javadoc/org/gradle/api/Project.html</a></li>
<li>The excellent examples of Mr. Haki at <a href="http://mrhaki.blogspot.com/search/label/Gradle%3AGoodness">http://mrhaki.blogspot.com/search/label/Gradle%3AGoodness</a></li>
<li>Published plugins on github can be found with this search: <a href="https://github.com/search?type=Repositories&amp;language=&amp;q=gradle+plugin">https://github.com/search?type=Repositories&amp;language=&amp;q=gradle+plugin</a> </li>
</ul>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/' rel='bookmark' title='Using Gradle to Bootstrap your Legacy Ant Builds'>Using Gradle to Bootstrap your Legacy Ant Builds</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/11/13/why-do-i-like-gradle/' rel='bookmark' title='Why do I Like Gradle?'>Why do I Like Gradle?</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2011/04/03/a-groovygradle-jslint-plugin/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Hooking into the Jenkins(Hudson) API</title>
		<link>http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=hooking-into-the-jenkinshudson-api</link>
		<comments>http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 17:24:09 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[cli]]></category>
		<category><![CDATA[Gradle]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[HTTPBuilder]]></category>
		<category><![CDATA[Hudson]]></category>
		<category><![CDATA[jenkins]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[kellyrob99.com]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1587</guid>
		<description><![CDATA[Which one &#8211; Hudson or Jenkins? Both. I started working on this little project a couple of months back using Hudson v1.395 and returned to it after the great divide happened. I took it as an opportunity to see whether there would be any significant problems should I choose to move permanently to Jenkins in [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/06/02/a-grails-app-demoing-the-stackexchange-api/' rel='bookmark' title='A Grails App Demoing the StackExchange API'>A Grails App Demoing the StackExchange API</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/' rel='bookmark' title='Five Cool Things You Can Do With Groovy Scripts'>Five Cool Things You Can Do With Groovy Scripts</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h2>Which one &#8211; Hudson or Jenkins?</h2>
<p>Both. I started working on this little project a couple of months back using Hudson v1.395 and returned to it after the great divide happened. I took it as an opportunity to see whether there would be any significant problems should I choose to move permanently to Jenkins in the future. There were a couple of hiccups- most notably that the new CLI jar didn&#8217;t work right out of the box- but overall v1.401 of Jenkins worked as expected after the switch. The good news is the old version of the CLI jar still works, so this example is actually using a mix of code to get things done. Anyway, the software is great and there&#8217;s more than enough credit to go around.</p>
<p></p>
<h2>The API</h2>
<p>Jenkins/Hudson has a <a href="http://wiki.hudson-ci.org/display/HUDSON/Remote+access+API">handy remote API</a> packed with information about your builds and supports a rich set of functionality to control them, and the server in general, remotely. It is possible to trigger builds, copy jobs, stop the server and even install plugins remotely. You have your choice of XML, JSON or Python when interacting with the APIs of the server.  And, as the build in documentation says, you can find the functionality you need on a relative path from the build server url at:</p>
<blockquote><p>&#8220;/&#8230;/api/ where &#8216;&#8230;&#8217; portion is the object for which you&#8217;d like to access&#8221;.</p></blockquote>
<p>This will show a brief documentation page if you navigate to it in a browser, and will return a result if you add the desired format as the last part of the path. For instance, to load information about the computer running a locally hosted Jenkins server, a get request on this url would return the result in JSON format: http://localhost:8080/computer/api/json.</p>
<pre class="brush: plain; title: ; notranslate">
{
  &quot;busyExecutors&quot;: 0,
  &quot;displayName&quot;: &quot;nodes&quot;,
  &quot;computer&quot;: [
    {
      &quot;idle&quot;: true,
      &quot;executors&quot;: [
        {
        },
        {
        }
      ],
      &quot;actions&quot;: [

      ],
      &quot;temporarilyOffline&quot;: false,
      &quot;loadStatistics&quot;: {
      },
      &quot;displayName&quot;: &quot;master&quot;,
      &quot;oneOffExecutors&quot;: [

      ],
      &quot;manualLaunchAllowed&quot;: true,
      &quot;offline&quot;: false,
      &quot;launchSupported&quot;: true,
      &quot;icon&quot;: &quot;computer.png&quot;,
      &quot;monitorData&quot;: {
        &quot;hudson.node_monitors.ResponseTimeMonitor&quot;: {
          &quot;average&quot;: 111
        },
        &quot;hudson.node_monitors.ClockMonitor&quot;: {
          &quot;diff&quot;: 0
        },
        &quot;hudson.node_monitors.TemporarySpaceMonitor&quot;: {
          &quot;size&quot;: 58392846336
        },
        &quot;hudson.node_monitors.SwapSpaceMonitor&quot;: null,
        &quot;hudson.node_monitors.DiskSpaceMonitor&quot;: {
          &quot;size&quot;: 58392846336
        },
        &quot;hudson.node_monitors.ArchitectureMonitor&quot;: &quot;Mac OS X (x86_64)&quot;
      },
      &quot;offlineCause&quot;: null,
      &quot;numExecutors&quot;: 2,
      &quot;jnlpAgent&quot;: false
    }
  ],
  &quot;totalExecutors&quot;: 2
}
</pre>
<p>Here&#8217;s the same tree rendered using GraphViz.</p>

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/computer.png" title="" class="shutterset_singlepic74" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/74_watermark_700x500_computer.png" alt="computer" title="computer" />
</a>

<p>This functionality extends out in a tree from the root of the server, and you can gate how much of the tree you load from any particular branch by supplying a &#8216;depth&#8217; parameter on your urls. Be careful how high you specify this variable. Testing with a load depth of four against a populous, long-running build server (dozens of builds with thousands of job executions) managed to regularly timeout for me. To give you an idea, here&#8217;s a very rough visualization of the domain at depth three from the root of the api.</p>

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/hudsonapidepth3.png" title="" class="shutterset_singlepic68" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/68_watermark_700x500_hudsonapidepth3.png" alt="hudsonapidepth3" title="hudsonapidepth3" />
</a>

<p>Getting data out of the server is very simple, but the ability to remotely trigger activity on the server is more interesting. In order to trigger a build of a job named &#8216;test&#8217;, a POST on http://localhost:8080/job/test/build does the job. Using the available facilities, it&#8217;s pretty easy to do things like:</p>
<ul>
<li>load a job&#8217;s configuration file, modify it and create a new job by POSTing the new config.xml file</li>
<li>move a job from one build machine to another</li>
<li>build up an overview of scheduled builds</li>
</ul>
<p></p>
<h2>The CLI Jar</h2>
<p>There&#8217;s another way to remotely drive build servers in the CLI jar distributed along with the server. This jar provides simple facilities for executing certain commands remotely on the build server. Of note, this enables installing plugins remotely and executing a remote Groovy shell. I incorporated this functionality with a very thin wrapper around the main class exposed by the CLI jar as shown in the next code sample.</p>
<pre class="brush: groovy; title: ; notranslate">
/**
 * Drive the CLI with multiple arguments to execute.
 * Optionally accepts streams for input, output and err, all of which
 * are set by default to System unless otherwise specified.
 * @param rootUrl
 * @param args
 * @param input
 * @param output
 * @param err
 * @return
 */
def runCliCommand(String rootUrl, List&lt;String&gt; args, InputStream input = System.in,
        OutputStream output = System.out, OutputStream err = System.err)
{
    def CLI cli = new CLI(rootUrl.toURI().toURL())
    cli.execute(args, input, output, err)
    cli.close()
}
</pre>
<p>And here&#8217;s a simple test showing how you can execute a Groovy script to load information about jobs, similar to what you can do from the built-in Groovy script console on the server, which can be found for a locally installed deployment at http://localhost:8080/script.</p>
<pre class="brush: groovy; title: ; notranslate">
def &quot;should be able to query hudson object through a groovy script&quot;()
{
    final ByteArrayOutputStream output = new ByteArrayOutputStream()
    when:
    api.runCliCommand(rootUrl, ['groovysh', 'for(item in hudson.model.Hudson.instance.items) { println(&quot;job $item.name&quot;)}'],
            System.in, output, System.err)

    then:
    println output.toString()
    output.toString().split('\n')[0].startsWith('job')
}
</pre>
<p>Here are some links to articles about the CLI, if you want to learn more :</p>
<ul>
<li><a href="http://wiki.hudson-ci.org/display/HUDSON/Hudson+CLI">Hudson CLI wikidoc</a></li>
<li><a href="http://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI">Jenkins CLI wikidoc</a></li>
<li><a href="http://jenkins-php.org/">A template for PHP jobs on Jenkins</a></li>
<li><a href="http://weblogs.java.net/blog/kohsuke/archive/2009/05/hudson_cli_and.html">An article from Kohsuke Kawaguchi</a></li>
<li><a href="http://meera-subbarao.blogspot.com/2010/08/hudson-and-cli.html">A nice tutorial</a></li>
</ul>
<p></p>
<h2>HTTPBuilder</h2>
<p><a href="http://groovy.codehaus.org/modules/http-builder/">HTTPBuilder</a> is my tool of choice when programming against an HTTP API nowadays. The usage is very straightforward and I was able to get away with only two methods to support reaching the entire API: one for GET and one for POST. Here&#8217;s the GET method, sufficient for executing the request, parsing the JSON response, and complete with (albeit naive) error handling.</p>
<pre class="brush: groovy; title: ; notranslate">
/**
 * Load info from a particular rootUrl+path, optionally specifying a 'depth' query
 * parameter(default depth = 0)
 *
 * @param rootUrl the base url to access
 * @param path  the api path to append to the rootUrl
 * @param depth the depth query parameter to send to the api, defaults to 0
 * @return parsed json(as a map) or xml(as GPathResult)
 */
def get(String rootUrl, String path, int depth = 0)
{
    def status
    HTTPBuilder http = new HTTPBuilder(rootUrl)
    http.handler.failure = { resp -&gt;
        println &quot;Unexpected failure on $rootUrl$path: ${resp.statusLine} ${resp.status}&quot;
        status = resp.status
    }

    def info
    http.get(path: path, query: [depth: depth]) { resp, json -&gt;
        info = json
        status = resp.status
    }
    info ?: status
}
</pre>
<p>Calling this to fetch data is a one liner, as the only real difference is the &#8216;path&#8217; variable used when calling the API.</p>
<pre class="brush: groovy; title: ; notranslate">
private final GetRequestSupport requestSupport = new GetRequestSupport()
    ...
/**
 * Display the job api for a particular Hudson job.
 * @param rootUrl the url for a particular build
 * @return job info in json format
 */
def inspectJob(String rootUrl, int depth = 0)
{
    requestSupport.get(rootUrl, API_JSON, depth)
}
</pre>
<p>Technically, there&#8217;s nothing here that limits this to JSON only. One of the great things about HTTPBuilder is that it will happily just try to do the right thing with the response. If the data returned is in JSON format, as these examples are, it gets parsed into a JSONObject. If on the other hand, the data is XML, it gets parsed into a Groovy GPathResult. Both of these are very easily navigable, although the syntax for navigating their object graphs is different.</p>
<p></p>
<h2>What can you do with it?</h2>
<p>My primary motivation for exploring the API of Hudson/Jenkins was to see how I could make managing multiple servers easier. At present I work daily with four build servers and another handful of slave machines, and support a variety of different version branches. This includes a mix of unit and functional test suites, as well as a continuous deployment job that regularly pushes changes to test machines matching our supported platform matrix, so unfortunately things are not quite as simple as copying a single job when branching. Creating the build infrastructure for new feature branches in an automatic, or at least semi-automatic, fashion is attractive indeed, especially since plans are in the works to expand build automation. For a recent 555 day project, I utilized the API layer to build a Grails app functioning as both a cross-server build radiator and a central facility for server management. This proof of concept is capable of connecting to multiple build servers and visualizing job data as well as specific system configuration, triggering builds, and direct linking to each of the connected servers to allow for drilling down further. Here&#8217;s a couple of mock-ups that pretty much show the picture.<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/grailsapp1.png" title="" class="shutterset_singlepic71" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/71_watermark_700x500_grailsapp1.png" alt="grailsapp1" title="grailsapp1" />
</a>
<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/grailsapp2.png" title="" class="shutterset_singlepic73" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/73_watermark_700x500_grailsapp2.png" alt="grailsapp2" title="grailsapp2" />
</a>
</p>
<p></p>
<h2>Just a pretty cool app for installing Jenkins</h2>
<p>This is only very indirectly related, but I came across this very nice and simple Griffon app, called the <a href="http://code.google.com/p/jenkins-assembler/">Jenkins-Assembler</a> which simplifies preparing your build server. It presents you with a list of plugins, letting you pick and choose, and then downloads and composes them into a single deployable war.<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/jenkins-assembler.png" title="" class="shutterset_singlepic75" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/75__x_jenkins-assembler.png" alt="jenkins-assembler" title="jenkins-assembler" />
</a>
</p>
<p></p>
<h2>Enough talking &#8211; where&#8217;s the code???</h2>
<p>Source code related to this article is <a href="https://github.com/kellyrob99/Jenkins-api-tour">available on github</a>.  The tests are more of an exploration of the live API than an actual test of the code in this project. They run against a local server launched using the Gradle Jetty plugin. Finally, here&#8217;s some pretty pictures for you.</p>

<div class="ngg-galleryoverview" id="ngg-gallery-13-1587">

	<!-- Slideshow link -->
	<div class="slideshowlink">
		<a class="slideshowlink" href="http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/?show=slide">
			[Show as slideshow]		</a>
	</div>

	<!-- Piclense link -->
	<div class="piclenselink">
		<a class="piclenselink" href="javascript:PicLensLite.start({feedUrl:'http://www.kellyrob99.com/blog/wp-content/plugins/nextgen-gallery/xml/media-rss.php?gid=13&amp;mode=gallery'});">
			[View with PicLens]		</a>
	</div>
	
	<!-- Thumbnails -->
		
	<div id="ngg-image-65" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/computerdepth4.png" title=" " class="shutterset_set_13" >
								<img title="computerdepth4" alt="computerdepth4" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_computerdepth4.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-66" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/gradleconfig.png" title=" " class="shutterset_set_13" >
								<img title="gradleconfig" alt="gradleconfig" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_gradleconfig.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-67" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/hudsonapi.png" title=" " class="shutterset_set_13" >
								<img title="hudsonapi" alt="hudsonapi" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_hudsonapi.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-68" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/hudsonapidepth3.png" title=" " class="shutterset_set_13" >
								<img title="hudsonapidepth3" alt="hudsonapidepth3" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_hudsonapidepth3.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-69" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/lastbuilddepth1.png" title=" " class="shutterset_set_13" >
								<img title="lastbuilddepth1" alt="lastbuilddepth1" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_lastbuilddepth1.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-70" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/overallloaddepth3.png" title=" " class="shutterset_set_13" >
								<img title="overallloaddepth3" alt="overallloaddepth3" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_overallloaddepth3.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-71" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/grailsapp1.png" title=" " class="shutterset_set_13" >
								<img title="grailsapp1" alt="grailsapp1" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_grailsapp1.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-74" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/computer.png" title=" " class="shutterset_set_13" >
								<img title="computer" alt="computer" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_computer.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-73" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/grailsapp2.png" title=" " class="shutterset_set_13" >
								<img title="grailsapp2" alt="grailsapp2" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_grailsapp2.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-75" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/jenkins-assembler.png" title=" " class="shutterset_set_13" >
								<img title="jenkins-assembler" alt="jenkins-assembler" src="http://www.kellyrob99.com/blog/wp-content/gallery/hudson-api/thumbs/thumbs_jenkins-assembler.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 	 	
	<!-- Pagination -->
 	<div class='ngg-clear'></div>
 	
</div>


<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/06/02/a-grails-app-demoing-the-stackexchange-api/' rel='bookmark' title='A Grails App Demoing the StackExchange API'>A Grails App Demoing the StackExchange API</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/' rel='bookmark' title='Five Cool Things You Can Do With Groovy Scripts'>Five Cool Things You Can Do With Groovy Scripts</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Why do I Like Gradle?</title>
		<link>http://www.kellyrob99.com/blog/2010/11/13/why-do-i-like-gradle/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=why-do-i-like-gradle</link>
		<comments>http://www.kellyrob99.com/blog/2010/11/13/why-do-i-like-gradle/#comments</comments>
		<pubDate>Sat, 13 Nov 2010 23:53:47 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[build]]></category>
		<category><![CDATA[Gradle]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1526</guid>
		<description><![CDATA[Gradle, if you don&#8217;t already know it, is rapidly gaining traction as a strong leader in the next generation of build systems. It builds heavily upon excellent aspects of the Maven and Ant frameworks, yet is pitched as not suffering from the same &#8220;Frameworkitis&#8220;. And I&#8217;ve gotta say &#8211; the results are pretty spectacular. Among [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/' rel='bookmark' title='Using Gradle to Bootstrap your Legacy Ant Builds'>Using Gradle to Bootstrap your Legacy Ant Builds</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/04/03/a-groovygradle-jslint-plugin/' rel='bookmark' title='A Groovy/Gradle JSLint Plugin'>A Groovy/Gradle JSLint Plugin</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><a href="http://gradle.org/">Gradle</a>, if you don&#8217;t already know it, is rapidly gaining traction as a strong leader in the next generation of build systems. It builds heavily upon excellent aspects of the <a href="http://maven.apache.org/">Maven</a> and <a href="http://ant.apache.org/">Ant</a> frameworks, yet is pitched as not suffering from the same &#8220;<a href="http://www.codinghorror.com/blog/2005/11/conversations-with-erich-gamma.html">Frameworkitis</a>&#8220;. And I&#8217;ve gotta say &#8211; the results are pretty spectacular. Among the major selling features, at least as I see it, are:</p>
<ul>
<li>Groovy syntax and a very terse and descriptive dsl that makes build scripts easily comprehensible</li>
<li>flexibility of layout, configuration, organizing build logic &#8211; pretty much everything</li>
<li>incremental builds, based on an easily implementable pattern</li>
<li>convention over configuration paradigm, thank you very much Maven</li>
<li>clear separation of build configuration from execution</li>
<li>extensibility at every level</li>
</ul>
<h2>The most basic Java build</h2>
<pre class="brush: groovy; title: ; notranslate">
apply plugin: 'java'
</pre>
<p>That&#8217;s it. One line of Groovy in a file called &#8216;build.gradle&#8217; and you can build a Java project with a Maven-standardized project layout.</p>
<pre>
├── build.gradle
└── src
    ├── main
    │   ├── java
    │   └── resources
    └── test
        ├── java
        └── resources
</pre>
<p>Included with the Java plugin are tasks to compile, package, test and javadoc your code. You also get <a href="http://gradle.org/latest/docs/userguide/artifact_dependencies_tutorial.html#sec:artifact_configurations">configuration</a> objects to describe the artifacts that your build depends on and those  that it produces. Of course, with this most basic setup these configurations don&#8217;t yet have anything in them, but in a complex build they&#8217;re very handy for isolating the responsibilities of each task. Because you can both configure the existing configurations and add custom ones yourself, it&#8217;s very easy to accommodate a project that follows a different structure, whether that is just differently named source directories or multiple directories that need specific processing. This is VERY handy for legacy builds.</p>
<h2>Incremental builds</h2>
<p>Gradle provides a very easy way to create tasks that are able to execute only if their declared input and/or output artifacts have changed. This makes it trivial to incorporate your custom build behaviour into an incremental build. As an example I&#8217;d like to expand upon something I read by <a href="http://twitter.com/etiennestuder">Etienne Studer</a> in this month&#8217;s <a href="http://jaxenter.com/jaxmag">JAXmag</a>. It&#8217;s a great example of developing an incremental task. First here&#8217;s the task implementation almost verbatim from the article. I&#8217;ve updated it slightly to make the output more readable using FileUtils, and you can examine the file it spits out from the build/reports/size directory that will be automatically created when it executes.</p>
<pre class="brush: groovy; title: ; notranslate">
class Size extends DefaultTask
{
    @InputFiles FileTree inputDir
    @OutputFile File outputFile

    @TaskAction
    void generate()
    {
        def totalSize = inputDir.files.inject(0) { def size, File file -&gt; size + file.size()
        }
        outputFile.text = FileUtils.byteCountToDisplaySize(totalSize)
    }
}
</pre>
<p>If you simply include this class definition in a build file, it will be automatically compiled and available for use elsewhere in the script. It could just as easily be defined in a separate file(local or remote), in a jar on the classpath or in the buildSrc directory of your Gradle project. This flexibility enables developing and evolving tasks in a very agile fashion, encouraging you to publish the results for reuse instead of re-implementing the logic in other projects.<br />
In order to execute this task as part of a build, we first need to configure it. In this case, I&#8217;m configuring it to work on all declared configurations and all source, both code and associated resources. In order to do so, I&#8217;m using a couple of Gradle internal classes, <a href="http://www.gradle.org/latest/docs/javadoc/org/gradle/api/file/FileTree.html">FileTree</a> and <a href="http://www.gradle.org/latest/docs/javadoc/org/gradle/api/tasks/SourceSet.html">SourceSet</a>, which actually sound pretty self-explanatory to me. The key part is the assignment of the &#8216;inputDir&#8217; and &#8216;outputFile&#8217; properties on the task.</p>
<pre class="brush: groovy; title: ; notranslate">
task size(type:Size){
    def filetree = sourceSets.inject(new UnionFileTree()) { FileTree total, SourceSet sourceSet -&gt;
        total += sourceSet.allSource
        total
    }
    inputDir = filetree
    outputFile = file(&quot;$reportsDir/size/size.txt&quot;)
}
</pre>
<p>Just to prove that it&#8217;s working incrementally, here&#8217;s the output from successive invocations. Note that &#8216;UP-TO-DATE&#8217; in the output that indicates the task was skipped the second time around, because none of the inputs changed and the output file hasn&#8217;t been deleted.</p>
<pre class="brush: groovy; title: ; notranslate">
gradle-intro$ gradle size
:size

BUILD SUCCESSFUL

Total time: 2.963 secs

gradle-intro$ gradle size
:size UP-TO-DATE

BUILD SUCCESSFUL

Total time: 2.912 secs
</pre>
<p>This task does actually have a concrete dependency on the Java plugin, since without that convention applied neither the &#8216;sourceSets&#8217; or &#8216;reportsDir&#8217; objects would be present. Here&#8217;s the complete version of the build file that&#8217;s been built so far, 28 lines including imports and spacing.</p>
<pre class="brush: groovy; title: ; notranslate">
import org.apache.commons.io.FileUtils
import org.gradle.api.internal.file.UnionFileTree
import org.gradle.api.tasks.SourceSet

apply plugin: 'java'           

task size(type:Size){
    def filetree = sourceSets.inject(new UnionFileTree()) { FileTree total, SourceSet sourceSet -&gt;
        total += sourceSet.allSource
        total
    }
    inputDir = filetree
    outputFile = file(&quot;$reportsDir/size/size.txt&quot;)
}

class Size extends DefaultTask
{
    @InputFiles FileTree inputDir
    @OutputFile File outputFile

    @TaskAction
    void generate()
    {
        def totalSize = inputDir.files.inject(0) { def size, File file -&gt; size + file.size()
        }
        outputFile.text = FileUtils.byteCountToDisplaySize(totalSize)
    }
}
</pre>
<h2>Sharing your new Task</h2>
<p>The simplest way to share build logic is to &#8216;apply&#8217; it. This simple shorthand covers everything from plugins to local files to remotely hosted resources. Here&#8217;s how easy it is to incorporate this particular task implementation and configuration into a build using a relative file path.</p>
<pre class="brush: groovy; title: ; notranslate">
apply from : '../gradle-intro/build.gradle'
</pre>
<p>And because only a simple http connection is required to share it to a broader base, here&#8217;s how you can reference a copy on this site. Sorry about the .txt extension, but I didn&#8217;t feel like editing php to allow a new filetype today <img src='http://www.kellyrob99.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<pre class="brush: groovy; title: ; notranslate">
apply from : 'http://www.kellyrob99.com/blog/wp-content/uploads/downloads/2010/11/gradleSizeTask.txt'
</pre>
<h2>Some other reading</h2>
<p>If you&#8217;re still not sold on Gradle, here&#8217;s some articles I&#8217;ve seen recently that at the very least will give you a better perspective.<br />
<a href="http://community.jboss.org/wiki/Gradlewhy">Hibernate &#8211; Gradle why?</a><br />
<a href="http://jaxenter.com/maven-vs-gradle-vs-ant.1-30682.html">Maven VS Gradle VS Ant</a><br />
Maven to Gradle: <a href="http://www.beeworks.be/maven-to-gradle-part-1/">Part 1</a>, <a href="http://www.beeworks.be/maven-to-gradle-part-2/">Part 2</a>,  <a href="http://www.beeworks.be/maven-to-gradle-part-3/">Part 3</a><br />
<a href="http://kaczanowscy.pl/tomek/2010-11/build-script-length-maven3-polyglot-maven-gradle-ant">A comparison of build script length</a><br />
<a href="http://kaczanowscy.pl/tomek/2009-11/ant-gradle-and-maven-comparison-install-script">Ant/Gradle/Maven comparison</a><br />
<a href="http://java.dzone.com/hibernate-users-learn-gradle">DZone article</a><br />
<a href="http://openmrs-mailing-list-archives.1560443.n2.nabble.com/Maven-vs-Gradle-td4511793.html">OpenMRS Mailing list on Maven VS Gradle</a></p>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2011/09/18/using-gradle-to-bootstrap-your-legacy-ant-builds/' rel='bookmark' title='Using Gradle to Bootstrap your Legacy Ant Builds'>Using Gradle to Bootstrap your Legacy Ant Builds</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/04/03/a-groovygradle-jslint-plugin/' rel='bookmark' title='A Groovy/Gradle JSLint Plugin'>A Groovy/Gradle JSLint Plugin</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/11/13/why-do-i-like-gradle/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Groovy inspect()/Eval for Externalizing Data</title>
		<link>http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=groovy-inspecteval-for-externalizing-data</link>
		<comments>http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/#comments</comments>
		<pubDate>Sun, 26 Sep 2010 20:32:13 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Bamboo]]></category>
		<category><![CDATA[Eval]]></category>
		<category><![CDATA[Gradle]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[Hudson]]></category>
		<category><![CDATA[inspect()]]></category>
		<category><![CDATA[Junit]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1502</guid>
		<description><![CDATA[One of the things I love about Groovy is how easy it makes reading and writing text files. I&#8217;ve written Groovy scripts for everything from parsing log files for extracting timing information to finding (and replacing with selectors) in-line css blocks. Often there&#8217;s a piece of information extracted from a file that I want to [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/07/01/groovy-and-csv-how-to-get-your-data-out/' rel='bookmark' title='Groovy and CSV: How to Get Your Data Out?'>Groovy and CSV: How to Get Your Data Out?</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/' rel='bookmark' title='Five Cool Things You Can Do With Groovy Scripts'>Five Cool Things You Can Do With Groovy Scripts</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/' rel='bookmark' title='Hooking into the Jenkins(Hudson) API'>Hooking into the Jenkins(Hudson) API</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>One of the things I love about Groovy is how easy it makes reading and writing text files. I&#8217;ve written Groovy scripts for everything from parsing log files for extracting timing information to finding (and replacing with selectors) in-line css blocks. Often there&#8217;s a piece of information extracted from a file that I want to keep for further examination, or just for future reference. The Groovy <a href="http://groovy.codehaus.org/api/org/codehaus/groovy/runtime/DefaultGroovyMethods.html#inspect%28java.lang.Object%29">inspect()</a> method provides a nice easy way to take simple results that are stored in variables and write them to a file. Then the Groovy <a href="http://groovy.codehaus.org/api/groovy/util/Eval.html">Eval</a> class provides convenience methods to parse that information back from the file in a single line. Here&#8217;s examples of test code that creates Lists and Maps, writes them out to a file and then asserts that evaluating the stored Groovy code results in the same data structures.</p>
<pre class="brush: groovy; title: ; notranslate">
    private static final Closure RANDOM_STRING = RandomStringUtils.&amp;randomAlphanumeric
    private static final String TMP_DIR = System.getProperty('java.io.tmpdir')

    @Test
    public void testSerializeListToFile()
    {
        List&lt;String&gt; accumulator = []
        100.times { int i -&gt;
            accumulator &lt;&lt; RANDOM_STRING(i + 1)
        }
        File file = new File(&quot;$TMP_DIR/inspectListTest.groovy&quot;)
        file.deleteOnExit()
        file &lt;&lt; accumulator.inspect()
        assertThat(accumulator, equalTo(Eval.me(file.text)))
    }

    @Test
    public void testSerializeMapToFile()
    {
        Map&lt;String, String&gt; accumulator = [:]
        100.times { int i -&gt;
            accumulator[RANDOM_STRING(i + 1)] = RANDOM_STRING(i + 1)
        }
        File file = new File(&quot;$TMP_DIR/inspectMapTest.groovy&quot;)
        file.deleteOnExit()
        file &lt;&lt; accumulator.inspect()
        assertThat(accumulator, equalTo(Eval.me(file.text)))
    }
</pre>
<p>Two little tidbits of goodness embedded in this example are the ability to capture a method as a closure, in this case RandomStringUtils.randomAlphanumeric(), and the <a href="http://download-llnw.oracle.com/javase/6/docs/api/java/io/File.html#deleteOnExit%28%29">File.deleteOnExit()</a> method &#8211; which is only cool because I never noticed it in the API before and it turns out to be a great way to clean up after tests.<br />
 <img src='http://www.kellyrob99.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>A particular usage of this technique I&#8217;ve been using lately has been sparked by a shift of tools at work. I&#8217;ve worked with the Atlassian stack of web applications for years now, and have always enjoyed the rich feedback Bamboo gives for build history. But now I&#8217;m using Hudson as the primary continuous integration tool and one of the things I&#8217;ve been sorely missing is the &#8216;Top 10 Longest Running Tests&#8217;.  If you&#8217;re not familiar with this view in Bamboo, stroll on over to <a href="http://bamboo.ci.codehaus.org/browse/GROOVY-DEF17J6EX/test">the Groovy build results page</a> and click on the tab.<br />
One of my present priorities at work is to speed up build times and rooting out slow or inefficient tests is one way to do this. It&#8217;s possible to elicit this information from JUnit test reports using xsl(<a href="http://stackoverflow.com/questions/277923/longest-running-unit-tests">see this link for an example</a>)  but I came up with a nice way to incorporate similar functionality into a Gradle build. Following the <a href="http://gradle.org/">Gradle</a> project-report conventions, this task simply uses the inspect() method to write out a results file in the &#8216;reportsDir&#8217;. I&#8217;ve captured this output(manually) over time to track the progress of speeding up test times, and the format makes it easy to read back in results and do deeper analysis and aggregation &#8211; such as the creation of csv reports and simple graphs for instance.</p>
<pre class="brush: groovy; title: ; notranslate">
tolerance = 2.0
task findLongRunningTests &lt;&lt; {
    description= &quot;find all tests that take over $tolerance seconds to run&quot;
    String testDir = &quot;${project.reportsDir}/tests&quot;.toString()
    file(testDir).mkdirs()
    File file = file(&quot;$testDir/longRunningTests.txt&quot;)
    file.createNewFile()
    BufferedWriter writer = file.newWriter()
    writer &lt;&lt; parseTestResults('**/TESTS-TestSuites.xml', tolerance)
    writer.close()
}

/**
 * Read in xml files in the junit format and extract test names and times
 * @includePattern ant pattern describing junit xml reports to inspect, recursively gathered from the rootDir
 * @tolerance the number of seconds over which tests should be included in the report
 */
private String parseTestResults(includePattern, float tolerance)
{
    def resultMap = [:]
    fileTree(dir: rootDir, include: includePattern).files.each {
        def testResult = new XmlSlurper().parse(it)
        testResult.depthFirst().findAll {it.name() == 'testcase'}.each { testcase -&gt;
            def key = [testcase.@classname.text(), testcase.@name.text()].join(':')
            def value = testcase.@time.text() as float
            resultMap[(key)] = value
        }
    }
    return resultMap.findAll {it.value &gt; tolerance}.sort {-it.value}.inspect()
}
</pre>
<p>Note that this works recursively from the &#8216;rootDir&#8217; of a <a href="http://www.gradle.org/latest/docs/javadoc/org/gradle/api/Project.html">Project</a>, so it is effective for multi-project Gradle builds. Source code for this simple example <a href="http://github.com/kellyrob99/groovy-inspect-eval">is available on github</a> if you want to check it out yourself.</p>
<p>Here&#8217;s a sample result drawn from examining some test output in the Gradle build itself. Only one of the tests executed in WrapperTest takes more than 2 seconds to execute.</p>
<pre class="brush: groovy; title: ; notranslate">
[&quot;org.gradle.api.tasks.wrapper.WrapperTest:testWrapper&quot;:2.37]
</pre>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/07/01/groovy-and-csv-how-to-get-your-data-out/' rel='bookmark' title='Groovy and CSV: How to Get Your Data Out?'>Groovy and CSV: How to Get Your Data Out?</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/' rel='bookmark' title='Five Cool Things You Can Do With Groovy Scripts'>Five Cool Things You Can Do With Groovy Scripts</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/' rel='bookmark' title='Hooking into the Jenkins(Hudson) API'>Hooking into the Jenkins(Hudson) API</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Groovy and CSV: How to Get Your Data Out?</title>
		<link>http://www.kellyrob99.com/blog/2010/07/01/groovy-and-csv-how-to-get-your-data-out/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=groovy-and-csv-how-to-get-your-data-out</link>
		<comments>http://www.kellyrob99.com/blog/2010/07/01/groovy-and-csv-how-to-get-your-data-out/#comments</comments>
		<pubDate>Thu, 01 Jul 2010 21:07:35 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Comma-separated values]]></category>
		<category><![CDATA[csv]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[hsqldb]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[OpenCSV]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Spreadsheet]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1420</guid>
		<description><![CDATA[I don&#8217;t know exactly how many CSV files I&#8217;ve read/written to date, but I&#8217;m willing to bet it&#8217;s a lot. These kind of files are a simple and common way to exchange data and are interoperable with spreadsheet programs as well, making them more easily accessible to non-programmer types. There is some excellent support out [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/' rel='bookmark' title='Five Cool Things You Can Do With Groovy Scripts'>Five Cool Things You Can Do With Groovy Scripts</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/' rel='bookmark' title='Achieving Groovy-like Fluency in Java with Google Collections'>Achieving Groovy-like Fluency in Java with Google Collections</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t know exactly how many <a class="zem_slink" title="Comma-separated values" rel="wikipedia" href="http://en.wikipedia.org/wiki/Comma-separated_values">CSV</a> files I&#8217;ve read/written to date, but I&#8217;m willing to bet it&#8217;s a lot. These kind of files are a simple and common way to exchange data and are interoperable with spreadsheet programs as well, making them more easily accessible to non-programmer types.  There is some excellent support out there for reading and writing CSV files and so here, from simplest to most complex, are a few different ways to load and query the data trapped inside your CSV files. But first off&#8230;</p>
<p></p>
<h2>CSV is Not XML</h2>
<p>Or any other suitably constrained data format for that matter.  There are some pretty clear &#8216;rules&#8217; out there for transporting data in this format, but of course hardly anybody listens to them. I found <a href="http://creativyst.com/Doc/Articles/CSV/CSV01.htm#FileFormat">this</a> and <a href="http://en.wikipedia.org/wiki/Comma-separated_values#Basic_rules">this</a> in the first page of a quick Google search.<br />
However, while looking for available sample material on the web to demonstrate with, I found many great examples of how to screw it up: not quoting empty strings, not escaping embedded line breaks, commas embedded in unquoted text, etc.  All of these are things that prevent automation from properly interacting with the data.  There are also, of course, the CSV &#8216;formats&#8217; that insist on embedding comments and descriptions, trying to present more than one matrix of information or any of the other crazy things you can do when writing to a format with no real metadata layer.</p>
<p>&lt; \rant&gt;</p>
<p>Unfortunately, there&#8217;s nothing as convenient as an xml schema available for describing what information is encoded in the document and, in general, the only potentially useful metadata in an individual file is the header line. The good news is that all of these deficiencies can be overcome if you know they exist. And there&#8217;s some pretty nifty tools you can use to take out much of the guesswork. I&#8217;ll suggest a couple of ideas for how to deal with files that don&#8217;t adhere to the &#8216;rules&#8217;, but the main example I&#8217;ve decided on is a straightforward  and well formed set representing the periodic table of elements, provided generously by <a href="http://akiscode.com/pt/">Akiscode</a>. This file is directly machine readable(has no headers or embedded data), quotes all values and just follows all the &#8216;rules&#8217;. Here&#8217;s the first five lines as an example.<br />

<table id="wp-table-reloaded-id-4-no-1" class="wp-table-reloaded wp-table-reloaded-id-4">
<tbody>
	<tr class="row-1 odd">
		<td class="column-1">Atomic Number</td><td class="column-2">Atomic Mass</td><td class="column-3">Name</td><td class="column-4">Symbol</td>
	</tr>
	<tr class="row-2 even">
		<td class="column-1">1</td><td class="column-2">1.00794</td><td class="column-3">Hydrogen</td><td class="column-4">H</td>
	</tr>
	<tr class="row-3 odd">
		<td class="column-1">2</td><td class="column-2">4.002602</td><td class="column-3">Helium</td><td class="column-4">He</td>
	</tr>
	<tr class="row-4 even">
		<td class="column-1">3</td><td class="column-2">6.941</td><td class="column-3">Lithium</td><td class="column-4">Li</td>
	</tr>
	<tr class="row-5 odd">
		<td class="column-1">4</td><td class="column-2">9.012182</td><td class="column-3">Beryllium</td><td class="column-4">Be</td>
	</tr>
	<tr class="row-6 even">
		<td class="column-1">5</td><td class="column-2">10.811</td><td class="column-3">Boron</td><td class="column-4">B</td>
	</tr>
</tbody>
</table>
<span class="wp-table-reloaded-table-description-id-4 wp-table-reloaded-table-description">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The simple format of the example CSV file.</span>
</p>
<p></p>
<h2>Groovy All by Itself</h2>
<p><a href="http://groovy.codehaus.org/">Groovy</a> makes dealing with String objects pretty painless.  By adding facilities like easy casting and find()/findAll() for quickly turning raw Strings into real data, you can program some fairly complex questions. In this simple example I&#8217;m depending on all values being quoted and I am not protecting against casting problems. I&#8217;m running this through Maven which really helps to keep test data organized; all you have to do is drop your test file in /src/test/resources and it&#8217;s automagically available on the test classpath.<br />
No specific handling is done for different types here; everything is read in as a String and cast to a more specific type as needed. In a &#8216;real&#8217; application you&#8217;re very likely going to encounter mixed alphanumeric data in any given column of data &#8211; &#8216;UNKNOWN&#8217; instead of a number in a column labeled &#8216;Quantity&#8217; for instance &#8211; and be more careful about casting.</p>
<pre class="brush: groovy; title: ; notranslate">
//load and split the file
InputStream inputFile = getClass().classLoader.getResourceAsStream(TEST_FILE_NAME)
String[] lines = inputFile.text.split('\n')
List&lt;String[]&gt; rows = lines.collect {it.split(',')}

/**
 * A little helper method to get rid of the quotes in the input
 * and cast values so they can be compared properly.
 */
private double castToDouble(string)
{
    return string.replaceAll('&quot;', '').toDouble()
}

//OK, it's parsed - let's ask some questions
private static final int ATOMIC_MASS = 1;

def elementsOver200Mass = rows.findAll {castToDouble(it[ATOMIC_MASS]) &gt; 200}
def elementsBetween10And20 = rows.findAll { row -&gt;
            double mass = castToDouble(row[ATOMIC_MASS])
            mass &lt;= 20 &amp;&amp; mass &gt;= 10
}
</pre>
<p>So this approach works fine for well formed input, but falls apart quickly in other cases. For instance, if any columns in the file are missing values the split() function treats them as nulls, leading to different size arrays being stored in the list. Similarly you need to deal with quoted VS non-quoted content, embedded line breaks and other issues individually. Fortunately, some nice guys have done that for us.</p>
<p></p>
<h2>OpenCSV</h2>
<p><a href="http://blogs.bytecode.com.au/glen/">Glen Smith&#8217;s</a> <a href="http://opencsv.sourceforge.net/">OpenCSV</a> library nicely abstracts away a lot of the minutiae of dealing with CSV. It properly deals with escaped characters, multiline input and a host of other issues for you. Give it pretty much anything that satisfies the Reader interface as an input and it&#8217;s good to go. The return type of the CSVReader.readAll() method also satisfies the same contract as the plain Groovy version shown above, so we can interact with the parsed results in exactly the same way as in the previous example.<br />
All values are still typed as Strings, so we need to cast in order to compare numeric values.</p>
<pre class="brush: groovy; title: ; notranslate">
import au.com.bytecode.opencsv.CSVReader

List&lt;String[]&gt; rows = new CSVReader(
        new InputStreamReader(getClass().classLoader.getResourceAsStream(TEST_FILE_NAME)))
            .readAll()

//same finders as in the Groovy version
def elementsOver200Mass = rows.findAll {it[ATOMIC_MASS].toDouble() &gt; 200}
def elementsBetween10And20 = rows.findAll { row -&gt;
    double mass = castToDouble(row[ATOMIC_MASS])
    mass &lt;= 20 &amp;&amp; mass &gt;= 10
}
</pre>
<p></p>
<h2>HsqlDB</h2>
<p>HsqlDB allows for using flat files as <a href="http://hsqldb.org/doc/2.0/guide/texttables-chapt.html">Text Tables</a>, effectively turning a CSV file into a database table. Data values are cast to the types specified in your table definition, so any potential type cast failures happen right up front when loading the data. The benefit is that once the data is read in no further manual processing is necessary. Note: by default the csv file and the database file must be located in the same directory, as a security precaution (can be overridden through configuration).</p>
<p>In addition, leveraging sql makes querying the data extremely easy. Groovy brings in the <a href="http://groovy.codehaus.org/api/groovy/sql/Sql.html">Sql class</a> to abstract away a lot of the normal <a class="zem_slink" title="Java (programming language)" rel="homepage" href="http://java.sun.com">Java</a> boilerplate you encounter when working with a <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html">ResultSet</a>. I didn&#8217;t do any in-depth testing to prove it out, but this is also the only one of the strategies described here that doesn&#8217;t require holding the entire data in memory in order to do arbitrary queries. That can be mitigated in the previously shown methods by processing files line by line rather than in bulk if memory usage is a concern.</p>
<pre class="brush: groovy; title: ; notranslate">
//create the table definition to insert
String tableName = 'elements'
String tableDefinition = &quot;&quot;&quot;CREATE TEXT TABLE $tableName (
    atomic_number INTEGER PRIMARY KEY,
    atomic_mass NUMERIC,
    name VARCHAR(255),
    symbol VARCHAR(3)
);&quot;&quot;&quot;

//create a new file database and a table corresponding to the csv file
Sql sql = Sql.newInstance(&quot;jdbc:hsqldb:file:${testdbDir.absolutePath}/testdb&quot;, 'sa', ''
    ,'org.hsqldb.jdbcDriver')
sql.execute(tableDefinition)

//set the source to the csv file
sql.execute(&quot;SET TABLE elements SOURCE '${TEST_FILE_NAME};all_quoted=true'&quot;.toString())

//querying the database that's wrapping our CSV file
def elementsOver200Mass = sql.rows(&quot;SELECT * FROM $tableName WHERE atomic_mass &gt; ?&quot;, [200])
def elementsBetween10And20 = sql.rows(
    &quot;SELECT * FROM $tableName WHERE atomic_mass &lt;= ? AND atomic_mass &gt;= ?&quot;, [20, 10])

//simple db aggregates
def count = 0
sql.eachRow(&quot;SELECT count(1) FROM $tableName WHERE atomic_mass &lt;= ?&quot;, [20]){row-&gt;
    count = row[0]
}
def avg = 0
sql.eachRow(&quot;SELECT avg(atomic_mass) FROM $tableName&quot;.toString()){row-&gt;
    avg = row[0]
}
</pre>
<p></p>
<h2>Which One do I Use???</h2>
<p>Pick the one that fits best for your use case is the real answer. I didn&#8217;t know about the HsqlDB option until recently, but OpenCSV has been a personal standby for years. Then again, if you&#8217;re writing something quick and dirty at the script level, the simplicity of just applying a couple of split() operations is pretty appealing. Here&#8217;s how I generally decide.</p>

<table id="wp-table-reloaded-id-5-no-1" class="wp-table-reloaded wp-table-reloaded-id-5">
<thead>
	<tr class="row-1">
		<th class="column-1"></th><th class="column-2">Plain Groovy</th><th class="column-3">OpenCSV</th><th class="column-4">HsqlDB</th>
	</tr>
</thead>
<tbody>
	<tr class="row-2">
		<td class="column-1">Use it</td><td class="column-2">File contains well-formed input and questions to be asked involve a small subset of columns.</td><td class="column-3">File contains well or badly formed input and questions to be asked involve a small subset of columns.</td><td class="column-4">File contains well or badly formed input, questions to be asked involve many columns or span multiple files.</td>
	</tr>
	<tr class="row-3">
		<td class="column-1">Don't use it</td><td class="column-2">File contains badly formed input or questions being asked are complex.</td><td class="column-3">Not able to easily leverage the OpenCSV library.</td><td class="column-4">Not able to easily leverage the HsqlDB database.</td>
	</tr>
	<tr class="row-4">
		<td class="column-1">Where it works</td><td class="column-2">Groovy only</td><td class="column-3">Groovy or Java</td><td class="column-4">Groovy or Java</td>
	</tr>
</tbody>
</table>
<span class="wp-table-reloaded-table-description-id-5 wp-table-reloaded-table-description">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Some common sense guidelines for which method to apply given a problem to solve.</span>

<div class="zemanta-pixie"><a class="zemanta-pixie-a" title="Enhanced by Zemanta" href="http://www.zemanta.com/"><img class="zemanta-pixie-img" src="http://img.zemanta.com/zemified_a.png?x-id=104c23a4-eae4-4092-87ab-7680f9df82e2" alt="Enhanced by Zemanta" /></a><span class="zem-script more-related pretty-attribution"><script src="http://static.zemanta.com/readside/loader.js" type="text/javascript"></script></span></div>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/09/26/groovy-inspecteval-for-externalizing-data/' rel='bookmark' title='Groovy inspect()/Eval for Externalizing Data'>Groovy inspect()/Eval for Externalizing Data</a></li>
<li><a href='http://www.kellyrob99.com/blog/2011/12/04/five-cool-things-you-can-do-with-groovy-scripts/' rel='bookmark' title='Five Cool Things You Can Do With Groovy Scripts'>Five Cool Things You Can Do With Groovy Scripts</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/' rel='bookmark' title='Achieving Groovy-like Fluency in Java with Google Collections'>Achieving Groovy-like Fluency in Java with Google Collections</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/07/01/groovy-and-csv-how-to-get-your-data-out/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>A Grails App Demoing the StackExchange API</title>
		<link>http://www.kellyrob99.com/blog/2010/06/02/a-grails-app-demoing-the-stackexchange-api/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-grails-app-demoing-the-stackexchange-api</link>
		<comments>http://www.kellyrob99.com/blog/2010/06/02/a-grails-app-demoing-the-stackexchange-api/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 07:12:17 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Application programming interface]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[Representational State Transfer]]></category>
		<category><![CDATA[Source code]]></category>
		<category><![CDATA[Stack Overflow]]></category>
		<category><![CDATA[StackApps]]></category>
		<category><![CDATA[StackExchange]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1367</guid>
		<description><![CDATA[So I was making an attempt to catch up on my Google Reader&#8216;ing this weekend and I came across this post on StackOverflow regarding the shiny new StackExchange API. That and a fresh 1.3.1 drop of Grails seemed like as good a reason as any to hack together a little app suitable for seeing what [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/' rel='bookmark' title='Hooking into the Jenkins(Hudson) API'>Hooking into the Jenkins(Hudson) API</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/10/25/grails-ui-datatable-using-xml-for-a-model/' rel='bookmark' title='Grails-UI DataTable using XML for a model'>Grails-UI DataTable using XML for a model</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/03/21/gource-visualizations-of-the-groovygrailsgriffon-projects/' rel='bookmark' title='Gource Visualizations of the Groovy/Grails/Griffon Projects'>Gource Visualizations of the Groovy/Grails/Griffon Projects</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>So I was making an attempt to catch up on my <a class="zem_slink" href="http://www.google.com/reader" title="Google Reader" rel="homepage">Google Reader</a>&#8216;ing this weekend and I came across <a href="http://blog.stackoverflow.com/2010/05/stack-exchange-api-contest/">this post on StackOverflow</a> regarding the shiny new <a class="zem_slink" href="http://www.stackexchange.com" title="StackExchange" rel="homepage">StackExchange</a> <a class="zem_slink" href="http://en.wikipedia.org/wiki/Application_programming_interface" title="Application programming interface" rel="wikipedia">API</a>. That and a fresh 1.3.1 drop of <a class="zem_slink" href="http://grails.org" title="Grails (framework)" rel="homepage">Grails</a> seemed like as good a reason as any to hack together a little app suitable for seeing what you can do with said API.<br />
Turns out it&#8217;s not a whole lot, at least not yet. The minor detraction of having  read-only access and limited connects without an API key are more than offset by seeing such a minimal, clean and easy to use interface. According to the grails stats script, it took about this much effort to implement calls to each and every one of the API endpoints for all of the supported domains:</p>
<pre class="brush: xml; title: ; notranslate">
    +----------------------+-------+-------+
    | Name                 | Files |  LOC  |
    +----------------------+-------+-------+
    | Controllers          |     1 |    42 |
    | Groovy Helpers       |     1 |    47 |
    +----------------------+-------+-------+
    | Totals               |     2 |    89 |
    +----------------------+-------+-------+
</pre>
<p>
Please note that this is about as minimal as you could reasonably get away with(and kinda ugly to boot), but nevertheless it does manage to implement a UI and backend for exercising the entire API in a total of 2 gsp files and 1 controller action.  What&#8217;s noticeably missing are some tailored views for each of the different <a class="zem_slink" href="http://json.org/" title="JSON" rel="homepage">JSON</a> responses and the implementation of additional query parameters on the calls.</p>
<p></p>
<h2>StackExchange API</h2>
<p>This is really <a href="http://api.stackoverflow.com/0.8/help">pretty well documented</a> and &#8220;consistent&#8221;. Calls in some cases require an {id} in the url and that&#8217;s about it. Each of the individual calls has its own help page that describes the options, like the <a href="http://api.stackoverflow.com/0.8/help/method?method=badges">badges page</a> for instance. To make things a little more helpful while exploring the API, each of the implemented endpoints in this app are also hyper-linked to the corresponding manual page on api.stackoverflow.com.</p>
<p></p>
<h2><a class="zem_slink" href="http://en.wikipedia.org/wiki/Representational_State_Transfer" title="Representational State Transfer" rel="wikipedia">RESTful</a> Access</h2>
<p>Couldn&#8217;t be a whole lot easier than using <a href="http://groovy.codehaus.org/modules/http-builder/">HttpBuilder</a>, which provides nice and concise ways to execute the GET request, inspect the response and deal with success/failure of the request. Aside from assigning the root domain and method using variables, this is little different from the <a href="http://groovy.codehaus.org/HTTP+Builder">canonical example on codehaus</a>.</p>
<pre class="brush: groovy; title: ; notranslate">
def http = new HTTPBuilder(&quot;http://api.$domain&quot;)
http.request(GET, JSON) {
    uri.path = &quot;/${VERSION}$method&quot;
    headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'
     response.success = { resp, json -&gt;
        answer = json
    }
     response.failure = { resp -&gt;
        answer = &quot;Unexpected error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}&quot;
    }
}
</pre>
<p>The syntax here could probably get even Groovier using the <a href="http://www.grails.org/plugin/rest">Grails REST client plugin</a> wrappers, and indeed incorporating that plugin is how the HttpBuilder dependency is being provided in this app, but I hit on a working implementation first time out so we&#8217;ll leave that for another day, shall we?</p>
<p></p>
<h2>What&#8217;s it Look Like?</h2>
<p><img src='http://www.kellyrob99.com/blog/wp-content/gallery/stackoverflow-api-grails/stackapps-demo_1275451039026.png' alt='stackapps-demo' class='ngg-singlepic ngg-none'  width='860' height='480'/><br />
Did I mention it was ugly?  Where the API call requires a parameter, you get a text field. Each domain gets its own submit button, officially representing my first attempted usage of g:actionSubmit in Grails. Doesn&#8217;t work quite the way I expected, but it does certainly work. Click a button and you&#8217;re shown the raw JSON result, along with the call you made. In an ugly fashion, or did I say that already? Still, for a couple of hours of hacking, I&#8217;m not unhappy with the result.</p>
<p></p>
<h2>StackApps</h2>
<p>This is where the apps in the contest get shown off and, in a wonderful display of <a href="http://en.wikipedia.org/wiki/Eating_your_own_dog_food">dogfooding</a>, it&#8217;s guess what &#8211; another StackOverflow clone! The page for this application <a href="http://stackapps.com/questions/491/a-grails-app-demoing-the-stackexchange-api">can be found here</a>. And the <a href="http://github.com/kellyrob99/stackoverflow-api-grails">source code is up on github</a> if you&#8217;d like to take a look.</p>
<p></p>
<h2>Next Steps?</h2>
<p>Toying with the idea of porting this to appengine, which would unfortunately mean replacing HttpBuilder and the underlying Apache HttpClient in favor of something that didn&#8217;t use a threaded approach, most likely using <a href="http://code.google.com/appengine/docs/java/urlfetch/">URL fetch</a>. That and some slightly less ugly tabular and/or tree views of the JSON responses would be kinda nice to have.<br />
 <img src='http://www.kellyrob99.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2011/03/27/hooking-into-the-jenkinshudson-api/' rel='bookmark' title='Hooking into the Jenkins(Hudson) API'>Hooking into the Jenkins(Hudson) API</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/10/25/grails-ui-datatable-using-xml-for-a-model/' rel='bookmark' title='Grails-UI DataTable using XML for a model'>Grails-UI DataTable using XML for a model</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/03/21/gource-visualizations-of-the-groovygrailsgriffon-projects/' rel='bookmark' title='Gource Visualizations of the Groovy/Grails/Griffon Projects'>Gource Visualizations of the Groovy/Grails/Griffon Projects</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/06/02/a-grails-app-demoing-the-stackexchange-api/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Achieving Groovy-like Fluency in Java with Google Collections</title>
		<link>http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=achieving-groovy-like-fluency-in-java-with-google-collections</link>
		<comments>http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/#comments</comments>
		<pubDate>Sun, 16 May 2010 05:33:19 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Collections]]></category>
		<category><![CDATA[DataProvider]]></category>
		<category><![CDATA[fluent syntax]]></category>
		<category><![CDATA[GMaven]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[google-collections]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[guava]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[MultiMap]]></category>
		<category><![CDATA[mvn]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[TestNG]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1261</guid>
		<description><![CDATA[One of the most compelling things about using Groovy is the fluent and concise syntax, as well as the productivity and readability gains that come out of it. But there&#8217;s no reason not to take advantage of some of the same techniques and some library support, in this case google-collections, to make Java code easy [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2009/04/19/groovy-and-glazed-lists-with-grape/' rel='bookmark' title='Groovy and Glazed Lists with Grape'>Groovy and Glazed Lists with Grape</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/11/21/different-flavors-of-embedded-groovy-in-java-apps-or-how-to-make-your-java-groovier/' rel='bookmark' title='Different Flavors of Embedded Groovy in Java Apps or &#8220;How To Make your Java Groovier!&#8221;'>Different Flavors of Embedded Groovy in Java Apps or &#8220;How To Make your Java Groovier!&#8221;</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/02/08/my-favorite-new-groovy-trick/' rel='bookmark' title='My favorite new Groovy trick'>My favorite new Groovy trick</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>One of the most compelling things about using Groovy is the fluent and concise syntax, as well as the productivity and readability gains that come out of it. But there&#8217;s no reason not to take advantage of some of the same techniques and some library support, in this case <a href="http://code.google.com/p/google-collections/">google-collections</a>, to make Java code easy to write AND to read.</p>
<h2>Creating Collections</h2>
<p>Groovy really shines for this one, making the creation of Lists and Maps, empty or populated, an absolute breeze. Java has some help for creating basic Lists but begins to struggle when creating maps. This is an area that google-collections can help in, especially in regards to creating immutable Maps.</p>
<pre class="brush: groovy; title: ; notranslate">
//Empty Lists
        List&lt;String&gt; groovyList = []
        List&lt;String&gt; javaList = new ArrayList&lt;String&gt;()
        List&lt;String&gt; googleList = Lists.newArrayList()  //can omit generics

//Populated Lists
        List&lt;String&gt; groovyList = [&quot;1&quot;, &quot;2&quot;]
        List&lt;String&gt; javaList = Arrays.asList(&quot;1&quot;, &quot;2&quot;)
        List&lt;String&gt; googleList = Lists.newArrayList(&quot;1&quot;, &quot;2&quot;)

//Immutable Lists
        List&lt;String&gt; groovyList = [&quot;1&quot;, &quot;2&quot;].asImmutable()
        List&lt;String&gt; javaList = Collections.unmodifiableList(Arrays.asList(&quot;1&quot;, &quot;2&quot;))
        List&lt;String&gt; googleList = ImmutableList.of(&quot;1&quot;, &quot;2&quot;)

//Empty Maps
        Map&lt;String, String&gt; groovyMap = [:]
        Map&lt;String, String&gt; javaMap = new LinkedHashMap&lt;String,String&gt;()
        Map&lt;String, String&gt; googleMap = Maps.newLinkedHashMap()

//Immutable Maps
        Map&lt;String, String&gt; groovyMap = [&quot;a&quot;:&quot;1&quot;, &quot;b&quot;:&quot;2&quot;].asImmutable()

        Map&lt;String, String&gt; javaMap = new LinkedHashMap&lt;String,String&gt;()
        javaMap.put(&quot;a&quot;, &quot;1&quot;)
        javaMap.put(&quot;b&quot;, &quot;2&quot;)
        javaMap = Collections.unmodifiableMap(javaMap)

        //OR(works only in Java, will not compile in Groovy)
        Map&lt;String, String&gt; javaMap = new LinkedHashMap&lt;String, String&gt;()
        {
            {
                put(&quot;a&quot;, &quot;1&quot;);
                put(&quot;b&quot;, &quot;2&quot;);
            }
        };

        Map&lt;String, String&gt; googleMap = ImmutableMap.of(&quot;a&quot;, &quot;1&quot;, &quot;b&quot;, &quot;2&quot;)  //clunky syntax but it works
</pre>
<h2>Filtering Collections</h2>
<p>Groovy provides the very handy &#8216;findAll&#8217; method that allows you to filter a Collection by applying a Closure. Google-collections provides similar facilities using the Predicate interface and two filter methods available statically on Collections2 and Iterables. This would also be a lot more readable if the Predicate definition were extracted but I wanted to show that it&#8217;s still possible to create them in-line quickly.</p>
<pre class="brush: groovy; title: ; notranslate">
import static com.google.common.collect.Collections2.*

List&lt;Integer&gt; toFilter = [1, 2, 3, 4, 5]
List&lt;Integer&gt; groovyVersion = toFilter.findAll{ it &lt; 3}
List&lt;Integer&gt; googleVersion = filter(toFilter, new Predicate&lt;Integer&gt;()
    {
        public boolean apply(Integer input)
        {
            return input &lt; 3;
        }
    };)
</pre>
<h2>Joining Collections into a String Representation</h2>
<p>This one has come up pretty often over the years, and it&#8217;s not surprising that where the JDK hasn&#8217;t provided, enterprising developers have added support through libraries. The problem is: given a Collection of objects, create a String representation of that Collection suitable for view from a consumer of the system. And admit it &#8211; the first time you hand-coded the algorithm you left a trailing comma, didn&#8217;t you? I know I did.<br />
Groovy has fantastic support for this use-case by simply including the &#8216;join&#8217; method on Lists. Google-collections utilizes static calls on the Joiner class along with a simple DSL-like syntax to achieve the same effect. Throw in a static import to make it even more concise and it does a fine job. These two examples yield the same result.</p>
<pre class="brush: groovy; title: ; notranslate">
import static com.google.common.base.Joiner.*
def toJoin = ['a', 'b', 'c']
def separator = ', '

//groovy version
def groovyJoin = toJoin.join(separator)

//google-collections version
def googleJoin = on(separator).join(toJoin)
</pre>
<p>And google-collections also supports join for Maps, something missing from Groovy(although not very hard to implement).</p>
<pre class="brush: groovy; title: ; notranslate">
import static com.google.common.base.Joiner.*
def toJoin = [1: 'a', 2: 'b', 3: 'c']
def separator = ', '
def keyValueSeparator = ':'

//results in '1:a, 2:b, 3:c' which is essentially what is returned from Groovy map.toMapString()
def googleVersion = on(separator).withKeyValueSeparator(keyValueSeparator).join(map)

//results in '1 is a and 2 is b and 3 is c'
googleVersion = on(&quot; and &quot;).withKeyValueSeparator(&quot; is &quot;).join(map)

//doing the same in Groovy is slightly more involved, but really not that bad
def groovyVersion = toJoin.inject([]) {builder, entry -&gt;
            builder &lt;&lt; &quot;${entry.key} is ${entry.value}&quot;
            builder
        }.join(' and ')
</pre>
<h2>Multimaps</h2>
<p>Multimaps are one of the more interesting parts of google-collections, at least to me. Have you ever found yourself writing code to create a Map of keys to Lists? Well the various <a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multimap.html">Multimap</a> implementations in google-collections mean you never have to write that boilerplate kind of code again. Here&#8217;s a &#8220;first-stab&#8221; effort to simulate a fairly generic Multimap with pure Java code.</p>
<pre class="brush: groovy; title: ; notranslate">
public class JavaMultimap
{
    private Map&lt;Object, List&lt;Object&gt;&gt; multimap = new LinkedHashMap&lt;Object, List&lt;Object&gt;&gt;();

    public boolean put(Object key, Object value)
    {
        List&lt;object&gt; objects = multimap.get(key);
        objects = objects != null ? objects : new ArrayList&lt;object&gt;();
        objects.add(value);
        multimap.put(key, objects);
        return true;
    }
}
</pre>
<p>
And the same thing in Groovy, achieving a slightly smaller version.</p>
<pre class="brush: groovy; title: ; notranslate">
class GroovyMultimap
{
    Map map = [:]

    public boolean put(Object key, Object value)
    {
        List list = map.get(key, [])
        list.add(value)
        map.&quot;$key&quot; = list
    }
}
</pre>
<p>I did some primitive timings comparing Java, Groovy and google-collections Multimaps implementations and, as you&#8217;d pretty much expect, google clearly takes the lead.  Where things really start to get interesting though is when you start using the Multimap in Groovy code. Imagine if you will that you want to iterate over a collection of Objects and map some of the properties to a List. Here&#8217;s a contrived example of what I&#8217;m talking about, but applying this same pattern to domain objects in your application or even a directory full of xml files is pretty much the same. If you look closely you&#8217;ll notice that Groovy actually makes this a one liner to extract all values for a property across a List of Objects(used in the assertion), but I imagine that Multimap is probably a better alternative for large data sets.</p>
<pre class="brush: groovy; title: ; notranslate">
class GoogleCollectionsMultiMapTest
{
    private Random random = new Random()

    @Test
    public void testMultimap()
    {
        def list = []
        10.times {
            list &lt;&lt; createObject()
        }
        List properties = ['value1', 'value2', 'value3']
        Multimap multimap = list.inject(LinkedListMultimap.create()) {Multimap map, object -&gt;
            properties.each {
                map.put(it, object.&quot;$it&quot;)
            }
            map
        }
        properties.each {
            assertEquals (multimap.get(it), list.&quot;$it&quot;)
        }
    }

    Object createObject()
    {
        Expando expando = new Expando()
        expando.value1 =  random.nextInt(10) + 1
        expando.value2 =  random.nextInt(100) + 100
        expando.value3 =  random.nextInt(50) + 50
        return expando
    }
}
</pre>
<h2>So Where Does This Get Us?</h2>
<p>Between google-collections and <a href="http://code.google.com/p/guava-libraries/">the newer guava-libraries</a> that contain it, there&#8217;s lots of help available for simplifying programming problems and making your code more readable. I haven&#8217;t even touched on the newly available support for primitives, Files, Streams and more, but if you&#8217;re interested in reducing the amount of code you write AND simultaneously making it more readable you should probably take a look. There&#8217;s a very nice overview available in <a href="http://codemunchies.com/2009/10/beautiful-code-with-google-collections-guava-and-static-imports-part-1/">part one</a> and <a href="http://codemunchies.com/2009/10/diving-into-the-google-guava-library-part-2/">part two</a> by <a href="http://twitter.com/astensby">Aleksander Stensby</a>.  And here&#8217;s a <a href="http://bwinterberg.blogspot.com/2009/09/introduction-to-google-collections.html">closer look at what google-collections can do for you</a>.</p>
<h2>Source Code</h2>
<p>As per usual, source code is <a href="http://github.com/kellyrob99/groovy-google-collections">available at github as a maven project</a>. Big thanks to the Spock team for sharing <a href="http://old.nabble.com/GMaven-and-Groovy-1.7-td27378212.html">how they configure GMaven to properly utilize Groovy 1.7</a>.  Please feel free to take a look and comment here. Thanks!</p>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2009/04/19/groovy-and-glazed-lists-with-grape/' rel='bookmark' title='Groovy and Glazed Lists with Grape'>Groovy and Glazed Lists with Grape</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/11/21/different-flavors-of-embedded-groovy-in-java-apps-or-how-to-make-your-java-groovier/' rel='bookmark' title='Different Flavors of Embedded Groovy in Java Apps or &#8220;How To Make your Java Groovier!&#8221;'>Different Flavors of Embedded Groovy in Java Apps or &#8220;How To Make your Java Groovier!&#8221;</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/02/08/my-favorite-new-groovy-trick/' rel='bookmark' title='My favorite new Groovy trick'>My favorite new Groovy trick</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Groovy and Hibernate Validator for Dynamic Constraints</title>
		<link>http://www.kellyrob99.com/blog/2010/04/17/groovy-and-hibernate-validator-for-dynamic-constraints/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=groovy-and-hibernate-validator-for-dynamic-constraints</link>
		<comments>http://www.kellyrob99.com/blog/2010/04/17/groovy-and-hibernate-validator-for-dynamic-constraints/#comments</comments>
		<pubDate>Sun, 18 Apr 2010 06:17:50 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JBoss Seam]]></category>
		<category><![CDATA[kellyrob99.com]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Source code]]></category>
		<category><![CDATA[theKaptain]]></category>
		<category><![CDATA[User interface]]></category>
		<category><![CDATA[validator]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1263</guid>
		<description><![CDATA[I was reading this article about hibernate validator today and it inspired me to apply a little Groovy to the problem of validating a bean. More specifically, finding out how hard it would be to apply different validation rules to the same classes at runtime. Turns out it&#8217;s really pretty simple. Hibernate validator, if you [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/07/01/groovy-and-csv-how-to-get-your-data-out/' rel='bookmark' title='Groovy and CSV: How to Get Your Data Out?'>Groovy and CSV: How to Get Your Data Out?</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/12/16/jira-grails-plugin/' rel='bookmark' title='Jira Grails Plugin'>Jira Grails Plugin</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/03/14/breaking-weak-captcha-in-slightly-more-than-26-lines-of-groovy-code/' rel='bookmark' title='Breaking Weak CAPTCHA in&#8230; slightly more than 26 Lines of Groovy Code'>Breaking Weak CAPTCHA in&#8230; slightly more than 26 Lines of Groovy Code</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I was reading <a href="http://java.dzone.com/articles/using-hibernate-validator">this article about hibernate validator</a> today and it inspired me to apply a little <a class="zem_slink" href="http://groovy.codehaus.org" title="Groovy (programming language)" rel="homepage">Groovy</a> to the problem of validating a bean.  More specifically, finding out how hard it would be to apply different validation rules to the same classes at runtime. Turns out it&#8217;s really pretty simple.<br />
<a href="http://www.hibernate.org/subprojects/validator/download.html">Hibernate validator</a>, if you didn&#8217;t already know, is the reference implementation of <a href="http://jcp.org/en/jsr/detail?id=303">JSR-303</a> and it provides the ability to specify by xml or annotation configuration validation rules for pojos.</p>
<p></p>
<h2>Where Hibernate Validator Shines</h2>
<p>Annotations on domain classes allow for easily validating object state at the time of persistence. Excellent integration with frameworks like <a class="zem_slink" href="http://www.seamframework.org" title="JBoss Seam" rel="homepage">JBoss Seam</a> allow this same ability to be utilized for validating web forms on the client-side with little more than an <a href="http://docs.jboss.org/seam/1.2.1.GA/reference/en/html/validation.html">&lt;s:validateAll/&gt; tag</a>. Seam practically hides the entire interaction with validation components from the developer. Since validation rules are defined directly in the domain class, you can (almost) guarantee that no objects with inconsistent state will ever end up being saved in your database.  There are certain validations that aren&#8217;t possible to verify without actually looking in the database, unique constraints for example, but generally in my experience hibernate validator is extremely easy to configure and work with. Implementing <a class="zem_slink" href="http://en.wikipedia.org/wiki/Create%2C_read%2C_update_and_delete" title="Create, read, update and delete" rel="wikipedia">CRUD</a> functionality is pretty trivial, and UIs can achieve consistency since all validations are applied equally.<br />
Alternatively, if you can&#8217;t or don&#8217;t want to use annotations for some reason, you can specify your validation rules in an xml file. Usually a singleton validation.xml file is made available on the classpath and picked up automagically when a ValidationFactory is created. A simple xml configuration looks like this:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;constraint-mappings xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemalocation=&quot;http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd&quot; xmlns=&quot;http://jboss.org/xml/ns/javax/validation/mapping&quot;&gt;
    &lt;default-package&gt;org.kar.test&lt;/default-package&gt;
    &lt;bean class=&quot;ValidateTestableClass&quot;&gt;
        &lt;field name=&quot;name&quot;&gt;
            &lt;constraint annotation=&quot;javax.validation.constraints.NotNull&quot;&gt;
        &lt;/constraint&gt;
    &lt;/field&gt;
&lt;/bean&gt;
</pre>
<p>and is meant to be applied to this simple class:</p>
<pre class="brush: groovy; title: ; notranslate">
class ValidateTestableClass
{
    int id
    String name
    String description
    boolean enabled
}
</pre>
<p></p>
<h2>Comparing with <a class="zem_slink" href="http://grails.org" title="Grails (framework)" rel="homepage">Grails</a> Validation</h2>
<p>Grails automatically provides <a href="http://www.grails.org/doc/latest/guide/7.%20Validation.html">validation capabilities</a> for domain classes and command objects, and enables adding the same behavior to any pogo through a combination of the @Validateable annotation and a static constraints closure. Adding validation support to arbitrary classes also requires specifying which packages to scan for the annotation.<br />
Plugin support from projects like <a href="http://www.grails.org/plugin/bean-fields">bean-fields</a> simplifies the handling of client-side validation and rendering error markers in the UI, an ability which the Grails framework provides natively by adding an &#8216;errors&#8217; field directly onto the domain or command object class instances bound to a web form.</p>
<p></p>
<h2>Dynamic Constraints</h2>
<p>Both the hibernate validator and the Grails strategies for applying validation described here have the same limitation: both are universally applied to all instances of a class. There&#8217;s no easy apparent way to override those constraints at runtime, although I suspect that some fancy MOP&#8217;ing or configuration could probably be used to accomplish overrides at runtime.<br />
Hibernate validator also supports creation of ad hoc validators by seeding with one or more xml documents. Or if you&#8217;re like me and hate hand editing xml, you can leverage Groovy to take a bit of the pain away. Here&#8217;s the same xml snippet from above in a Groovy Closure, generated simply by turning the DomToGroovy class loose on the raw xml:</p>
<pre class="brush: groovy; title: ; notranslate">
looseConstraint = {
        mkp.declareNamespace(xsi: 'http://www.w3.org/2001/XMLSchema-instance')
        'constraint-mappings'(xmlns: 'http://jboss.org/xml/ns/javax/validation/mapping',
                'xsi:schemaLocation': 'http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd') {
            'default-package'('org.kar.test.objects')
            bean('class': 'ValidateTestableClass') {
                field(name: 'name') {
                    constraint(annotation: 'javax.validation.constraints.NotNull')
                }
            }
        }
    }
</pre>
<p>Losing all the angle brackets is a good start, but we really haven&#8217;t saved a lot of typing. Until you start taking advantage of the ability to define more complicated structures. Note the use of a list structure here to apply NotNull constraints to multiple fields.</p>
<pre class="brush: groovy; title: ; notranslate">
strictConstraint = {
        mkp.declareNamespace(xsi: 'http://www.w3.org/2001/XMLSchema-instance')
        'constraint-mappings'(xmlns: 'http://jboss.org/xml/ns/javax/validation/mapping',
                'xsi:schemaLocation': 'http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd') {
            'default-package'('org.kar.test.objects')
            bean('class': 'ValidateTestableClass') {
                ['name', 'description'].each {
                    field(name: it) {
                        constraint(annotation: 'javax.validation.constraints.NotNull')
                    }
                }
                field(name: 'id') {
                    constraint(annotation: 'javax.validation.constraints.DecimalMin') {
                        element(name: 'value', '2')
                    }
                }
                field(name: 'enabled') {
                    constraint(annotation: 'javax.validation.constraints.AssertTrue')
                }
            }
        }
    }
</pre>
<p></p>
<h2>Applying Dynamic Constraints</h2>
<p>Applying constraints is as simple as converting Closures to xml and mapping them to a Configuration object, which then supplies a Validator to use. StreamingMarkupBuilder is utilized to create the xml behind the scenes.</p>
<pre class="brush: groovy; title: ; notranslate">
    /**
     * Create a configuration object passing closures as validation mapping documents.
     * @param closures closures to render into validation mapping documents
     * @return config
     */
    public Configuration createConfig(Closure... closures)
    {
        Configuration config = Validation.byDefaultProvider().configure()
        closures.each {
            config.addMapping(new ByteArrayInputStream(GroovyXmlConversionUtil.convertToXml(it).bytes))
        }
        config
    }
</pre>
<p>I haven&#8217;t tested the use of multiple mappings extensively, but minimally each class you&#8217;re configuring must be confined to a single mapping &#8211; you can&#8217;t extend the validations by layering configurations on top of one another. You should however be able to map constraints for different classes in separate Closures.</p>
<p></p>
<h2>Crying out for a Builder!</h2>
<p>Going from Closures to xml is a quick and dirty way to test out this functionality, but what would really be nice is a Builder that could create an appropriate validation environment more directly. At the least it would allow for removing the namespace declarations and explicit package naming that make up the bulk of the content.</p>
<h2>So what do you get?</h2>
<ol>
<li>1. Ability to declare validations against any existing <a class="zem_slink" href="http://java.sun.com" title="Java (programming language)" rel="homepage">Java</a> or Groovy class without changing the source code</li>
<li>2. Programmatic ability to create the configuration of validations</li>
<li>3. A choice of which validations to apply at runtime</li>
<li>4. Consistency with the behavior of domain class validation</li>
</ol>
<p>And what&#8217;d I get? A fun bit of quick coding on a Saturday afternoon. Nice! Source code is <a href="http://github.com/kellyrob99/groovy-hibernate-validator">available on git-hub</a> if you want to check it out.</p>
<div class="zemanta-pixie"><a class="zemanta-pixie-a" title="Reblog this post [with Zemanta]" href="http://reblog.zemanta.com/zemified/c83e9a1b-1079-49a8-80cb-95c76b967f69/"><img class="zemanta-pixie-img" src="http://img.zemanta.com/reblog_c.png?x-id=c83e9a1b-1079-49a8-80cb-95c76b967f69" alt="Reblog this post [with Zemanta]" /></a><span class="zem-script more-related pretty-attribution"><script src="http://static.zemanta.com/readside/loader.js" type="text/javascript"></script></span></div>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/07/01/groovy-and-csv-how-to-get-your-data-out/' rel='bookmark' title='Groovy and CSV: How to Get Your Data Out?'>Groovy and CSV: How to Get Your Data Out?</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/12/16/jira-grails-plugin/' rel='bookmark' title='Jira Grails Plugin'>Jira Grails Plugin</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/03/14/breaking-weak-captcha-in-slightly-more-than-26-lines-of-groovy-code/' rel='bookmark' title='Breaking Weak CAPTCHA in&#8230; slightly more than 26 Lines of Groovy Code'>Breaking Weak CAPTCHA in&#8230; slightly more than 26 Lines of Groovy Code</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/04/17/groovy-and-hibernate-validator-for-dynamic-constraints/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Gource Visualizations of the Groovy/Grails/Griffon Projects</title>
		<link>http://www.kellyrob99.com/blog/2010/03/21/gource-visualizations-of-the-groovygrailsgriffon-projects/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gource-visualizations-of-the-groovygrailsgriffon-projects</link>
		<comments>http://www.kellyrob99.com/blog/2010/03/21/gource-visualizations-of-the-groovygrailsgriffon-projects/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 01:58:41 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Cool Toys]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Concurrent Versions System]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[git-svn]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[MacPorts]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Open source]]></category>
		<category><![CDATA[Revision control]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[SVN]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1226</guid>
		<description><![CDATA[That&#8217;s a whole lot of Gr8ness in the title, don&#8217;t you think? Ok, ok &#8211; I apologize for the pun. I whipped these up using the open source Gource visualization software and with HD content free on Youtube now, I just had to try that out too. Gource Gource is a software version control visualization [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/01/07/bamboo-grails-and-git-for-continuous-integration/' rel='bookmark' title='Bamboo, Grails and Git for Continuous Integration'>Bamboo, Grails and Git for Continuous Integration</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/06/02/a-grails-app-demoing-the-stackexchange-api/' rel='bookmark' title='A Grails App Demoing the StackExchange API'>A Grails App Demoing the StackExchange API</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/10/25/grails-ui-datatable-using-xml-for-a-model/' rel='bookmark' title='Grails-UI DataTable using XML for a model'>Grails-UI DataTable using XML for a model</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>That&#8217;s a whole lot of Gr8ness in the title, don&#8217;t you think? Ok, ok &#8211; I apologize for the pun. I whipped these up using the open source <a href="http://code.google.com/p/gource/">Gource</a> visualization software and with <a href="http://www.google.com/support/youtube/bin/answer.py?hl=en&amp;answer=153665">HD content free on Youtube</a> now, I just had to try that out too.</p>
<h2>Gource</h2>
<p>Gource is a software <a class="zem_slink" href="http://en.wikipedia.org/wiki/Revision_control" title="Revision control" rel="wikipedia">version control</a> visualization program with support for <a class="zem_slink" href="http://git-scm.com/" title="Git (software)" rel="homepage">Git</a>, <a class="zem_slink" href="http://mercurial.selenic.com/" title="Mercurial" rel="homepage">Mercurial</a>, and with a tiny bit of extra effort, <a class="zem_slink" href="http://www.nongnu.org/cvs" title="Concurrent Versions System" rel="homepage">CVS</a> and <a href="http://subversion.tigris.org/">Subversion</a>. It&#8217;s available as a macport install, as is the ffmpeg program used to stitch together a series of screenshots into the final video.&nbsp; All of these visualizations were created with Git or Git-svn. When the Gource program is running it brings up an interactive window so you can interact with it to a degree, affecting the camera, zoom, etc.&nbsp; The default resolution is 1024&#215;768 but I tried to bump it up to 1920&#215;1080. I&#8217;m assuming that stretched the limits of the rendering, as there&#8217;s quite a bit of pixellation in the final product; either that or the ffmpeg params need to be tweaked. The three visualizations on this page were all created using this one-liner command line invocation (broken down here over several lines for readability).</p>
<pre class="brush: bash; title: ; notranslate">
gource -1920x1080 --highlight-all-users --bloom-intensity .3 -a 1 -s .01
     --hide-dirnames --hide-filenames --stop-at-end --output-ppm-stream -
     | ffmpeg -y -b 3000K -r 60 -f image2pipe -vcodec ppm -i -
     -vcodec libx264 -vpre default  gource.mp4
</pre>
<h2>Groovy</h2>
<p>From the initial commit on August 28, 2003, Groovy has come a long way. I tried the Gource provided python script to translate an svn log file into the required format the first time, but cloning the repository with git-svn seemed to produce better results. It&#8217;s interesting to see that the overall structure of the Groovy project doesn&#8217;t look like is has changed very much over the years. I recognized a lot of the names you see on the screen. Be sure to watch the <a class="zem_slink" href="http://en.wikipedia.org/wiki/1080p" title="1080p" rel="wikipedia">1080p</a> version if you&#8217;re having trouble reading the text and see if you can&#8217;t find some recognizable committers.</p>
<p><a href="http://www.kellyrob99.com/blog/2010/03/21/gource-visualizations-of-the-groovygrailsgriffon-projects/"><em>Click here to view the embedded video.</em></a></p>
<h2>Grails</h2>
<p>Starting on Sunday March 14, 2004 here&#8217;s how it all unfolded, at least  from the perspective of the public Git repository. Grails looks like it grew a little more spontaneously than Groovy; there are more frequent restructurings and some transitions that seem to cover a whole lot of ground in very little time. In particular watch out for the burst of activity in the summer of 2009.</p>
<p><a href="http://www.kellyrob99.com/blog/2010/03/21/gource-visualizations-of-the-groovygrailsgriffon-projects/"><em>Click here to view the embedded video.</em></a></p>
<h2>Griffon</h2>
<p>September 17, 2008 marks the first commit for Griffon and this short but sweet video explodes right from the start. Benefiting greatly from the Grails model this project shows a lot of progress in a very short time indeed. Most, if not all, of the names you see here you probably caught in the previous two videos as well.<br />
<p><a href="http://www.kellyrob99.com/blog/2010/03/21/gource-visualizations-of-the-groovygrailsgriffon-projects/"><em>Click here to view the embedded video.</em></a></p></p>
<h2>What&#8217;s the Point?</h2>
<p>Watching these gives me (and maybe you) some appreciation for how much effort over time it takes to bring a new language/framework/technology to maturity and all of the individual contributions that go into it. Gource provides a lot more detail into the actual structure if you want to dig in. For purposes of keeping these images fairly uncluttered I removed file and directory names and just focused on the committers and the general structure. I think I gained a git of insight into how a codebase can evolve, and properly appreciate that organizing the increasing complexity of an ever-growing system over time is not a simple job. Plus they look cool. Enjoy!</p>
<div class="zemanta-pixie"><a class="zemanta-pixie-a" href="http://reblog.zemanta.com/zemified/2f2c3e09-4284-4248-b30f-d47242fd57a1/" title="Reblog this post [with Zemanta]"><img class="zemanta-pixie-img" src="http://img.zemanta.com/reblog_c.png?x-id=2f2c3e09-4284-4248-b30f-d47242fd57a1" alt="Reblog this post [with Zemanta]" /></a><span class="zem-script more-related pretty-attribution"><script type="text/javascript" src="http://static.zemanta.com/readside/loader.js" defer="defer"></script></span></div>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/01/07/bamboo-grails-and-git-for-continuous-integration/' rel='bookmark' title='Bamboo, Grails and Git for Continuous Integration'>Bamboo, Grails and Git for Continuous Integration</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/06/02/a-grails-app-demoing-the-stackexchange-api/' rel='bookmark' title='A Grails App Demoing the StackExchange API'>A Grails App Demoing the StackExchange API</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/10/25/grails-ui-datatable-using-xml-for-a-model/' rel='bookmark' title='Grails-UI DataTable using XML for a model'>Grails-UI DataTable using XML for a model</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/03/21/gource-visualizations-of-the-groovygrailsgriffon-projects/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Breaking Weak CAPTCHA in&#8230; slightly more than 26 Lines of Groovy Code</title>
		<link>http://www.kellyrob99.com/blog/2010/03/14/breaking-weak-captcha-in-slightly-more-than-26-lines-of-groovy-code/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=breaking-weak-captcha-in-slightly-more-than-26-lines-of-groovy-code</link>
		<comments>http://www.kellyrob99.com/blog/2010/03/14/breaking-weak-captcha-in-slightly-more-than-26-lines-of-groovy-code/#comments</comments>
		<pubDate>Sun, 14 Mar 2010 23:44:59 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Application programming interface]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java2D]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[Open source]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Source code]]></category>
		<category><![CDATA[tesseract-ocr]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1158</guid>
		<description><![CDATA[I read an interesting article recently about using python and open source software to defeat a particular captcha implementation and I set out to see how hard it would be to do the same in Groovy. In particular, coming from the Java side of the fence, I was impressed by how the available libraries in [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2009/11/21/different-flavors-of-embedded-groovy-in-java-apps-or-how-to-make-your-java-groovier/' rel='bookmark' title='Different Flavors of Embedded Groovy in Java Apps or &#8220;How To Make your Java Groovier!&#8221;'>Different Flavors of Embedded Groovy in Java Apps or &#8220;How To Make your Java Groovier!&#8221;</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/' rel='bookmark' title='Achieving Groovy-like Fluency in Java with Google Collections'>Achieving Groovy-like Fluency in Java with Google Collections</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/04/17/groovy-and-hibernate-validator-for-dynamic-constraints/' rel='bookmark' title='Groovy and Hibernate Validator for Dynamic Constraints'>Groovy and Hibernate Validator for Dynamic Constraints</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I read <a href="http://www.bonsai-sec.com/blog/index.php/breaking-weak-captcha-in-26-lines-of-code/">an interesting article</a> recently about using python and <a class="zem_slink" href="http://www.wikinvest.com/concept/Open_Source" title="Open Source" rel="wikinvest">open source</a> software to defeat a particular captcha implementation and I set out to see how hard it would be to do the same in Groovy. In particular, coming from the <a class="zem_slink" href="http://java.sun.com" title="Java (programming language)" rel="homepage">Java</a> side of the fence, I was impressed by how the available libraries in python made loading, mutating and saving images so easy. Admittedly I have limited experience working with image data, but when I have it has always seemed like a complex(and easy to get wrong) process. Maybe there&#8217;s a Java library out there that provides a simple &#8216;image_resize&#8217; method, but it&#8217;s certainly not in the BufferedImage <a class="zem_slink" href="http://en.wikipedia.org/wiki/Application_programming_interface" title="Application programming interface" rel="wikipedia">API</a>. Still, when porting the 26 lines of code over to Groovy, I was able to get it considerably less verbose than the Java equivalent.</p>
<p></p>
<h2>The Pretty Pictures</h2>
<p>Here are the three images to test against. In order to put them in a suitable format for <a href="http://code.google.com/p/tesseract-ocr">the open source tesseract-ocr program</a> to process we need to make them bigger, remove the background noise and transform them into a &#8216;tif&#8217; format. The python program we&#8217;re porting utilizes the PIL library for image handling and the pytesseract library for wrapping tesseract; I didn&#8217;t look very hard for java equivalents and just coded the required functions directly.</p>
<table>
<tbody>
<tr>
<td>
<a href="http://www.kellyrob99.com/blog/wp-content/gallery/captcha-breaker/9koo.gif" title="Original image for 9koO" class="shutterset_singlepic58" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/58__x_9koo.gif" alt="9koo" title="9koo" />
</a>
</td>
<td>
<a href="http://www.kellyrob99.com/blog/wp-content/gallery/captcha-breaker/jxt9.gif" title="Original image for jxt9" class="shutterset_singlepic60" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/60__x_jxt9.gif" alt="jxt9" title="jxt9" />
</a>
</td>
<td>
<a href="http://www.kellyrob99.com/blog/wp-content/gallery/captcha-breaker/e4ya.gif" title="Original image for e4ya" class="shutterset_singlepic59" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/59__x_e4ya.gif" alt="e4ya" title="e4ya" />
</a>
</td>
</tr>
</tbody>
</table>
<p></p>
<h2>Reading in the Image</h2>
<p>The python code for this is three lines, one to load the image and a couple more to convert it into a format suitable for directly manipulating pixel color through <a class="zem_slink" href="http://en.wikipedia.org/wiki/RGB_color_model" title="RGB color model" rel="wikipedia">RGB</a> values. Groovy takes a bit more to do the same, but being able to use a &#8216;with&#8217; block makes interacting with the Graphics object a lot cleaner than the same Java code</p>
<pre class="brush: groovy; title: ; notranslate">
//python
from PIL import Image
img = Image.open('input.gif')
img = img.convert(&quot;RGBA&quot;)
pixdata = img.load()

//Groovy
BufferedImage image = ImageIO.read(new File(fileName))
BufferedImage dimg = new BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_ARGB)
dimg.createGraphics().with {
    setComposite(AlphaComposite.Src)
    drawImage(image, null, 0, 0)
    dispose()
}
</pre>
<p></p>
<h2>Removing the Background Noise</h2>
<p>In both cases we&#8217;re doing essentially the same thing: finding all non-black pixels and setting them to white. This leaves only the actual embedded text to stand out. Being able to utilize the Java Color constants makes the Groovy version a little more readable, IMO, but otherwise the two pieces of code are generally equivalent.</p>
<pre class="brush: groovy; title: ; notranslate">
//python
for y in xrange(img.size[1]):
    for x in xrange(img.size[0]):
        if pixdata[x, y] != (0, 0, 0, 255):
            pixdata[x, y] = (255, 255, 255, 255)

//Groovy
(0..&lt;dimg.height).each {i=&quot;&quot; -=&quot;&quot;&gt;
    (0..&lt;dimg.width).each {j=&quot;&quot; -=&quot;&quot;&gt;
        if (dimg.getRGB(j, i) != Color.BLACK.RGB)
        {
            dimg.setRGB(j, i, Color.WHITE.RGB)
        }
    }
}
</pre>
<p></p>
<h2>Resizing the Image</h2>
<p><a class="zem_slink" href="http://www.python.org/" title="Python (programming language)" rel="homepage">Python</a>&#8216;s library usage really shines here, making this a one line call. Not quite the same in Java-land, although again there&#8217;s probably a better way to do this(I just don&#8217;t know it offhand).</p>
<pre class="brush: groovy; title: ; notranslate">
//python
big = im_orig.resize((116, 56), Image.NEAREST)

//Groovy
dimg = resizeImage(dimg, 116, 56)
...
def resizeImage = {BufferedImage image, int w, int h -&amp;gt;
    BufferedImage dimg = new BufferedImage(w, h, image.type)
    dimg.createGraphics().with {
        setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
        drawImage(image, 0, 0, w, h, 0, 0, image.width, image.height, null)
        dispose()
    }
    return dimg
}
</pre>
<p>By this point the original images now look like this, and are <i>almost</i> ready for OCR.</p>
<table>
<tbody>
<tr>
<td>
<a href="http://www.kellyrob99.com/blog/wp-content/gallery/captcha-breaker/tmp0.gif" title="Resized and cleaned for OCR" class="shutterset_singlepic61" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/61__x_tmp0.gif" alt="9koO-readyForOCR" title="9koO-readyForOCR" />
</a>
</td>
<td>
<a href="http://www.kellyrob99.com/blog/wp-content/gallery/captcha-breaker/tmp1.gif" title="Resized and cleaned for OCR" class="shutterset_singlepic62" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/62__x_tmp1.gif" alt="jxt9-readyForOCR" title="jxt9-readyForOCR" />
</a>
</td>
<td>
<a href="http://www.kellyrob99.com/blog/wp-content/gallery/captcha-breaker/tmp2.gif" title="Resized and cleaned for OCR" class="shutterset_singlepic63" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/63__x_tmp2.gif" alt="e4ya-readyForOCR" title="e4ya-readyForOCR" />
</a>
</td>
</tr>
</tbody>
</table>
<p></p>
<h2>Converting to a tif File</h2>
<p>This one turns out to be a bit of a PITA in Java and particularly on a Mac, and represents the bulk of the Groovy code. Unfortunately it is also the only format that tesseract appears to accept &#8216;out of the box&#8217;.  After googling the fun that is JAI and working with the <a class="zem_slink" href="http://en.wikipedia.org/wiki/Tagged_Image_File_Format" title="Tagged Image File Format" rel="wikipedia">.tif</a>(f) format with it on a Mac,   I ended up taking the code kindly provided in <a href="http://www.ideyatech.com/2009/05/converting-to-tiff-on-mac-using-java-advanced-imaging/">this blog post</a> and Groovified it a bit to make a working transformation. Thanks very much to Allan Tan for that. One more time, there&#8217;s likely a better/easier way to do this, but honestly it&#8217;s more effort than I&#8217;m willing to put in on a weekend afternoon just to satisfy my curiosity.<br />
 <img src='http://www.kellyrob99.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<pre class="brush: groovy; title: ; notranslate">
//python
ext = &quot;.tif&quot;
big.save(&quot;input-NEAREST&quot; + ext)

//Groovy
void convertToTiff(String inputFile, String outputFile)
{
    OutputStream ios
    try
    {
        ios = new BufferedOutputStream(new FileOutputStream(new File(outputFile)))
        ImageEncoder enc = ImageCodec.createImageEncoder(&quot;tiff&quot;, ios, new TIFFEncodeParam(compression: TIFFEncodeParam.COMPRESSION_NONE, littleEndian: false))
        RenderedOp src = JAI.create(&quot;fileload&quot;, inputFile)

        //Apply the color filter and return the result.
        ColorConvertOp filterObj = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null)
        BufferedImage dst = new BufferedImage(src.width, src.height, BufferedImage.TYPE_3BYTE_BGR)
        filterObj.filter(src.getAsBufferedImage(), dst)

        // save the output file
        enc.encode(dst)
    }
    catch (Exception e)
    {
        println e
    }
    finally
    {
        ios.close()
    }
}
</pre>
<p></p>
<h2>OCR with Tesseract-OCR</h2>
<p>Finally we need to pass the processed image to tesseract so it can &#8216;read&#8217; it for us. Again, the python library makes this a breeze, but calling out to a command line program with Groovy is so simple that it ends up being about the same. Tesseract itself is available as a macport, as well in downloadable unix binaries and a windows executable so installing the software is a breeze.</p>
<pre class="brush: groovy; title: ; notranslate">
//python
from pytesser import *
image = Image.open('input-NEAREST.tif')
print image_to_string(image)

//Groovy
def tesseract = ['/opt/local/bin/tesseract', tmpTif, tmpTesseract].execute()
tesseract.waitFor()
return new File(&quot;${tmpTesseract}.txt&quot;).readLines()[0]
</pre>
<p></p>
<h2>Testing it out</h2>
<p>To test it out I implemented the code in a maven project, iterate over the images and write out intermediate results to a temp directory. And it only works on two out of three of the cases. For some reason tesseract insists on consistently seeing &#8216;e4ya&#8217; as &#8216;e4ga&#8217;.  I tried to see if I could get it working by tweaking the image manipulation parameters and the order of operations(resizing before removing the background noise for instance) but that just caused the other cases to fail as well. Since in the final image the &#8216;y&#8217; seems pretty clear, it&#8217;s more likely that tweaking tesseract configuration might yield better results.</p>
<pre class="brush: groovy; title: ; notranslate">
public void testPrintImage()
{
    def breaker = new CaptchaBreaker()
    /* tesseract interprets &quot;e4ya&quot; as &quot;e4ga&quot; unfortunately */
    ['9koO', 'jxt9'/*,'e4ya'*/].each {String imageName -&amp;gt;
        def fileName = &quot;src/test/resources/${imageName}.gif&quot;
        assertEquals(&quot;Testing $imageName&quot;,imageName, breaker.imageToString(fileName))
    }
}
</pre>
<p></p>
<h2>C&#8217;est Finis</h2>
<p>I had some fun playing with areas of Java that I don&#8217;t usually interact with, and gained some appreciation for the diversity and ease-of-use exposed by just a couple of python libraries. It&#8217;s comforting to note that I was able to implement all of the required functionality from those libraries in &lt; 90 lines of Groovy. With a little more effort I think the final product could be tweaked to avoid the intermediate file system reads/writes as well, but that&#8217;s for another day.<br />
Source code is <a href="http://github.com/kellyrob99/catcha-breaker">available on github</a> if you&#8217;d care to take a look, and thanks for stopping by!</p>
<div class="zemanta-pixie"><a class="zemanta-pixie-a" href="http://reblog.zemanta.com/zemified/7a2ae51d-774b-47b5-894b-592c38ebf542/" title="Reblog this post [with Zemanta]"><img class="zemanta-pixie-img" src="http://img.zemanta.com/reblog_c.png?x-id=7a2ae51d-774b-47b5-894b-592c38ebf542" alt="Reblog this post [with Zemanta]" /></a><span class="zem-script more-related pretty-attribution"><script type="text/javascript" src="http://static.zemanta.com/readside/loader.js" defer="defer"></script></span></div>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2009/11/21/different-flavors-of-embedded-groovy-in-java-apps-or-how-to-make-your-java-groovier/' rel='bookmark' title='Different Flavors of Embedded Groovy in Java Apps or &#8220;How To Make your Java Groovier!&#8221;'>Different Flavors of Embedded Groovy in Java Apps or &#8220;How To Make your Java Groovier!&#8221;</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/' rel='bookmark' title='Achieving Groovy-like Fluency in Java with Google Collections'>Achieving Groovy-like Fluency in Java with Google Collections</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/04/17/groovy-and-hibernate-validator-for-dynamic-constraints/' rel='bookmark' title='Groovy and Hibernate Validator for Dynamic Constraints'>Groovy and Hibernate Validator for Dynamic Constraints</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/03/14/breaking-weak-captcha-in-slightly-more-than-26-lines-of-groovy-code/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Developing Faster with the Atlassian IntelliJ Connector</title>
		<link>http://www.kellyrob99.com/blog/2010/02/21/developing-faster-with-the-atlassian-intellij-connector/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=developing-faster-with-the-atlassian-intellij-connector</link>
		<comments>http://www.kellyrob99.com/blog/2010/02/21/developing-faster-with-the-atlassian-intellij-connector/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 19:53:38 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Cool Toys]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Atlassian]]></category>
		<category><![CDATA[Atlassian IntelliJ Connector]]></category>
		<category><![CDATA[Bamboo]]></category>
		<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[Fisheye]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[Integrated development environment]]></category>
		<category><![CDATA[JBoss Seam]]></category>
		<category><![CDATA[Jira]]></category>
		<category><![CDATA[Jira Studio]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[theKaptain]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1051</guid>
		<description><![CDATA[Once upon a time I used Eclipse as a development environment. It had a lot of things going for it: free(as in beer), rich community involvement, a plethora of plugins and probably my favorite feature: Mylyn. The problem was that it seemed everytime I wanted to upgrade to a newer version, inevitably half of the [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/01/02/atlassian-here-be-dragons/' rel='bookmark' title='Atlassian: Here Be Dragons'>Atlassian: Here Be Dragons</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/08/14/griffon-support-in-latest-intellij-eap/' rel='bookmark' title='Griffon support in latest Intellij EAP'>Griffon support in latest Intellij EAP</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/01/27/thanks-for-the-shirt-atlassian/' rel='bookmark' title='Thanks for the shirt Atlassian!'>Thanks for the shirt Atlassian!</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>Once upon a time I used <a class="zem_slink" href="http://www.eclipse.org/" title="Eclipse (software)" rel="homepage">Eclipse</a> as a development environment. It had a lot of things going for it: free(as in beer), rich community involvement, a plethora of plugins and probably my favorite feature: <a href="http://www.eclipse.org/mylyn/">Mylyn</a>. The problem was that it seemed everytime I wanted to upgrade to a newer version, inevitably half of the integrations broke.   Please don&#8217;t get me wrong, Eclipse is AMAZING software and I do still use it occasionally for specific tasks &#8211; but nevertheless I now spend most of my day in <a class="zem_slink" href="http://www.jetbrains.com/idea/" title="IntelliJ IDEA" rel="homepage">IntelliJ</a>. In particular it had better support for Groovy/Grails development and Maven integration &#8211; both of which were essential to my everyday work. Throw in default included support for <a class="zem_slink" href="http://www.seamframework.org" title="JBoss Seam" rel="homepage">JBoss Seam</a>, JSF/Facelets, html and css and I didn&#8217;t really need a lot of plugins anymore. One of the ones I have been using, and that I&#8217;ve watched mature over the course of the last year, is the <a href="http://www.atlassian.com/software/ideconnector/intellij.jsp">Atlassian IntelliJ Connector</a>. Between it and the greatly improved changeset functionality I finally feel like I have a solid replacement for Mylyn&#8217;s excellent task management facilities.</p>
<p>This plugin integrates the IDE with one or more components of the <a class="zem_slink" href="http://www.atlassian.com/" title="Atlassian" rel="homepage">Atlassian</a> application suite. Multiple instances of <a class="zem_slink" href="http://atlassian.com/software/jira" title="JIRA (software)" rel="homepage">Jira</a>, <a class="zem_slink" href="http://www.atlassian.com/software/fisheye" title="FishEye (software)" rel="homepage">Fisheye</a>, <a class="zem_slink" href="http://www.atlassian.com/software/bamboo" title="Bamboo (software)" rel="homepage">Bamboo</a> and <a href="http://www.atlassian.com/software/crucible/">Crucible</a> can all be configured and used to streamline the development workflow.</p>
<p></p>
<h2>Jira</h2>
<p>This is perhaps the most essential piece of the puzzle, and inevitably the part a developer is going to interact with the most &#8211; the issue tracker. From within the IDE Jira master view you can load filters(basically stored searches for issues), do ad hoc searches and start work on a particular issue. If you drill down to a particular issue you can comment on it, assign it to yourself or another user, log work against it and generally manage it in most of the ways you can from the Jira web interface. Granted it&#8217;s not quite as pretty as the web interface, but the essential information and interaction is all there, and if you&#8217;re missing something an action is provided to open any issue in a web browser.</p>
<p>What really works for me is how the interaction supports my general workflow so closely:</p>
<div style="padding-left: 10px;">
<ul>
<li>Look in Jira for an issue to work on</li>
<li>Assign it to myself(if it&#8217;s not already)</li>
<li>Start progress on the issue, which starts a timer and creates a corresponding changeset</li>
<li>Do whatever development work that is required to satisfy the issue, pausing and resuming as necessary for<br />
            the duration of the task
        </li>
<li>Commit the changeset, optionally logging time against the issue and creating a Crucible review for later
        </li>
<li>Rinse and repeat</li>
</ul>
</div>
<p>Granted, I&#8217;m not the best at remembering to pause the timer, but being confronted with the time when I commit forces me to honestly evaluate how much time it took to complete the task when it&#8217;s clearest in my mind. And incidentally, while we&#8217;re here, the option to automatically organize imports in the commit dialog, a built in IDE function, has saved my butt from maven dependency-analyze any number of times.</p>
<p>It&#8217;s also convenient that you can see all comments and attachments for issues &#8211; viewing a screenshot describing a UI issue is pretty much essential after all, don&#8217;t you think?<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/jiraissuedetailview.png" title="Jira detail view for an issue, including access to commentary and attachments." class="shutterset_singlepic53" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/53__x_jiraissuedetailview.png" alt="jiraissuedetailview" title="jiraissuedetailview" />
</a>
</p>
<h2>Bamboo</h2>
<p>So once your code is committed, a build is kicked off on Bamboo. Hopefully all goes well, but if any build you&#8217;re listening to fails the IDE will give you a message to that effect. You also have access to changes, tests and any associated build logs. And whether or not your build does fail, stacktraces from the log are immediately available and clickable in the IDE. In addition, you can manually trigger builds and label or comment them.<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/bamboologview.png" title="Linking Bamboo logs to code in the IDE." class="shutterset_singlepic46" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/46__x_bamboologview.png" alt="bamboologview" title="bamboologview" />
</a>
</p>
<h2>Fisheye</h2>
<p>Integration with Fisheye is bi-directional between the IDE and the Fisheye webview. Context menus are available on right clicks in the IDE that open a file in Fisheye. And in the Fisheye web app clicking an IntelliJ icon will open a file in the IDE. It should be noted that this feature only appears to be available with Fisheye 2. I know because I&#8217;ve been missing it in Jira Studio, which still uses the 1.6 version of Fisheye.<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/fisheyealtf1menu.png" title="Alt-F1 context menu for a file linked to Fisheye." class="shutterset_singlepic50" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/50__x_fisheyealtf1menu.png" alt="fisheyealtf1menu" title="fisheyealtf1menu" />
</a>
<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/fisheyerightclickmenu.png" title="Right click context menu for a file linked to Fisheye." class="shutterset_singlepic52" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/52__x_fisheyerightclickmenu.png" alt="fisheyerightclickmenu" title="fisheyerightclickmenu" />
</a>
</p>
<h2>Crucible</h2>
<p>This is the one integration I&#8217;ve used the least so far, primarily because I don&#8217;t have Crucible installed locally for testing and again it seems a lot of the power of the integration is only available with version 2. The documentation certainly seems to suggest more rich functionality than I&#8217;ve found available anyhow. Fisheye and Crucible are actually bundled together for installation, so the Jira Studio version appears also restricted to the 1.6 version &#8211; for the time being at least. Mostly the Crucible integration is convenient because it provides messaging when reviews are assigned or commented.</p>
<p></p>
<h2>Documentation</h2>
<p>To be perfectly honest, I didn&#8217;t even look for these until writing this blog post. Configuring and using the plugin is very straightforward, provided you&#8217;re familiar with using these Atlassian tools at least. Nevertheless, I did discover a few additional bonuses and as usual <a href="http://confluence.atlassian.com/display/IDEPLUGIN/Atlassian+Connector+for+IntelliJ+IDEA">the docs are both complete and up to date</a>.</p>
<p></p>
<h2>Overall</h2>
<p>Really the point of using this plugin is to significantly reduce context switching; as much as possible your work is concentrated in one interface, and for the vast majority of cases you only need one piece of software running to get the job done. Where context switching is inevitable, this software tries to make it as &#8220;one-click&#8221; as possible. The end result is to put the power of your Atlassian products front and center in the IDE, where us developer types spend most of our working lives. Now, if only Jira Studio gets updated to the latest available software versions, because I&#8217;m dying to try out side-by-side diffs for Crucible reviews in IntelliJ!</p>
<p>Anyhow, if you use Atlassian tools the Connector is well worth checking out. And you Eclipse users aren&#8217;t left in the dark either. I can&#8217;t vouch for it&#8217;s quality, but there is an equivalent plugin for Eclipse available as well. </p>

<div class="ngg-galleryoverview" id="ngg-gallery-10-1051">

	<!-- Slideshow link -->
	<div class="slideshowlink">
		<a class="slideshowlink" href="http://www.kellyrob99.com/blog/2010/02/21/developing-faster-with-the-atlassian-intellij-connector/?show=slide">
			[Show as slideshow]		</a>
	</div>

	<!-- Piclense link -->
	<div class="piclenselink">
		<a class="piclenselink" href="javascript:PicLensLite.start({feedUrl:'http://www.kellyrob99.com/blog/wp-content/plugins/nextgen-gallery/xml/media-rss.php?gid=10&amp;mode=gallery'});">
			[View with PicLens]		</a>
	</div>
	
	<!-- Thumbnails -->
		
	<div id="ngg-image-42" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/atlassianconnectorautoupdate.png" title="The plugin includes its own auto-update functionality, very handy!" class="shutterset_set_10" >
								<img title="atlassianconnectorautoupdate" alt="atlassianconnectorautoupdate" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_atlassianconnectorautoupdate.png" width="81" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-43" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/atlassianconnectorgeneralsettings.png" title="Preferences page of general settings for each application type." class="shutterset_set_10" >
								<img title="atlassianconnectorgeneralsettings" alt="atlassianconnectorgeneralsettings" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_atlassianconnectorgeneralsettings.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-44" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/bamboobuildcomment.png" title="Adding a comment to a completed Bamboo build." class="shutterset_set_10" >
								<img title="bamboobuildcomment" alt="bamboobuildcomment" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_bamboobuildcomment.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-45" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/bamboobuildpopup.png" title="This is the overview information presented when hovering over a build in the Bamboo view." class="shutterset_set_10" >
								<img title="bamboobuildpopup" alt="bamboobuildpopup" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_bamboobuildpopup.png" width="96" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-46" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/bamboologview.png" title="Linking Bamboo logs to code in the IDE." class="shutterset_set_10" >
								<img title="bamboologview" alt="bamboologview" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_bamboologview.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-47" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/bamboooverview.png" title="Overview of Bamboo builds you have configured." class="shutterset_set_10" >
								<img title="bamboooverview" alt="bamboooverview" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_bamboooverview.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-48" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/configuringnewapplications.png" title="Host specific configuration for each of the Atlassian applications." class="shutterset_set_10" >
								<img title="configuringnewapplications" alt="configuringnewapplications" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_configuringnewapplications.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-49" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/createajiraissue.png" title="Creating a new Jira issue from the IDE." class="shutterset_set_10" >
								<img title="createajiraissue" alt="createajiraissue" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_createajiraissue.png" width="77" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-50" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/fisheyealtf1menu.png" title="Alt-F1 context menu for a file linked to Fisheye." class="shutterset_set_10" >
								<img title="fisheyealtf1menu" alt="fisheyealtf1menu" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_fisheyealtf1menu.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-51" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/fisheyeexamplemacroview.png" title="Fisheye view, complete with IntelliJ button to open file directly in IDE." class="shutterset_set_10" >
								<img title="fisheyeexamplemacroview" alt="fisheyeexamplemacroview" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_fisheyeexamplemacroview.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-52" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/fisheyerightclickmenu.png" title="Right click context menu for a file linked to Fisheye." class="shutterset_set_10" >
								<img title="fisheyerightclickmenu" alt="fisheyerightclickmenu" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_fisheyerightclickmenu.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-53" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/jiraissuedetailview.png" title="Jira detail view for an issue, including access to commentary and attachments." class="shutterset_set_10" >
								<img title="jiraissuedetailview" alt="jiraissuedetailview" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_jiraissuedetailview.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-54" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/jiraissuepopup.png" title="This is the overview information presented when hovering over an issue in the Jira view." class="shutterset_set_10" >
								<img title="jiraissuepopup" alt="jiraissuepopup" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_jiraissuepopup.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-55" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/jiraissuesoverview.png" title="Overview of all Jira issues matching a filter or search." class="shutterset_set_10" >
								<img title="jiraissuesoverview" alt="jiraissuesoverview" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_jiraissuesoverview.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-56" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/jirastopwork.png" title="Dialog presented when 'stopping work' on a Jira issue; includes the ability to change the Jira state and log work against the issue." class="shutterset_set_10" >
								<img title="jirastopwork" alt="jirastopwork" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_jirastopwork.png" width="89" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-57" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/jiratoolbaradditions.png" title="Buttons the Connector adds to the top IDE button bar." class="shutterset_set_10" >
								<img title="jiratoolbaradditions" alt="jiratoolbaradditions" src="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian-intellij-connector/thumbs/thumbs_jiratoolbaradditions.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 	 	
	<!-- Pagination -->
 	<div class='ngg-clear'></div>
 	
</div>


<div class="zemanta-pixie"><a class="zemanta-pixie-a" href="http://reblog.zemanta.com/zemified/51641feb-8bfa-4376-b1dc-c90be9a1987f/" title="Reblog this post [with Zemanta]"><img class="zemanta-pixie-img" src="http://img.zemanta.com/reblog_c.png?x-id=51641feb-8bfa-4376-b1dc-c90be9a1987f" alt="Reblog this post [with Zemanta]" /></a><span class="zem-script more-related pretty-attribution"><script type="text/javascript" src="http://static.zemanta.com/readside/loader.js" defer="defer"></script></span></div>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/01/02/atlassian-here-be-dragons/' rel='bookmark' title='Atlassian: Here Be Dragons'>Atlassian: Here Be Dragons</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/08/14/griffon-support-in-latest-intellij-eap/' rel='bookmark' title='Griffon support in latest Intellij EAP'>Griffon support in latest Intellij EAP</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/01/27/thanks-for-the-shirt-atlassian/' rel='bookmark' title='Thanks for the shirt Atlassian!'>Thanks for the shirt Atlassian!</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/02/21/developing-faster-with-the-atlassian-intellij-connector/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A One Day Griffon Application/Presentation</title>
		<link>http://www.kellyrob99.com/blog/2010/02/11/a-one-day-griffon-applicationpresentation/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-one-day-griffon-applicationpresentation</link>
		<comments>http://www.kellyrob99.com/blog/2010/02/11/a-one-day-griffon-applicationpresentation/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 05:15:57 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[beta]]></category>
		<category><![CDATA[Collections]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[kellyrob99]]></category>
		<category><![CDATA[plugin architecture]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[slideware]]></category>
		<category><![CDATA[Source code]]></category>
		<category><![CDATA[Swing]]></category>
		<category><![CDATA[TestNG]]></category>
		<category><![CDATA[theKaptain]]></category>
		<category><![CDATA[Transitions2D]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1072</guid>
		<description><![CDATA[I took the opportunity this past weekend to test drive the latest beta version of Griffon and along with it the as-of-yet unreleased slideware plugin. If you&#8217;re not already aware, Griffon is a Grails inspired framework for creating Java Swing applications. The project lead, Andres Almiray, has given several presentations using this plugin and it [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2009/08/27/vijug-griffongroovy-presentation/' rel='bookmark' title='VIJUG Griffon/Groovy Presentation'>VIJUG Griffon/Groovy Presentation</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/' rel='bookmark' title='Achieving Groovy-like Fluency in Java with Google Collections'>Achieving Groovy-like Fluency in Java with Google Collections</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/03/15/fun-day-playing-with-new-stuff/' rel='bookmark' title='Fun day playing with new Stuff'>Fun day playing with new Stuff</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I took the opportunity this past weekend to test drive the latest beta version of <a href="http://griffon.codehaus.org/">Griffon</a> and along with it the as-of-yet unreleased slideware plugin. If you&#8217;re not already aware, Griffon is a Grails inspired framework for creating <a class="zem_slink" href="http://en.wikipedia.org/wiki/Swing_%28Java%29" title="Swing (Java)" rel="wikipedia">Java Swing</a> applications. The project lead, Andres Almiray, has given several presentations using this plugin and it provides an excellent platform for showcasing both the power of Swing and the capabilities of Griffon to make it all look so easy.</p>
<p>The slideware plugin provides a framework for creating presentations with a little twist &#8211; you can execute code live from the presentation software.  If you&#8217;ve ever given a presentation about programming you probably are fully aware of the transition from presentation software to your preferred environment for demonstrating code samples. Well, now you can stay entirely within the same application, editing and running code live.</p>
<p>The plugin itself isn&#8217;t available from the Griffon repository but source code and a built 0.2 version can be <a href="http://github.com/aalmiray/Presentations">found on github</a>.  Considering both the youth of the plugin and the beta status of the framework, it worked impressively well AND had a rich feature set.  All of the expected &#8220;powerpoint&#8221; features are there: themes, layout control, styling, slide transitions and export are all pretty easy to incorporate and configure. The code editor view also works very well. A great variety of additional plugins are harnessed to put all the pieces together and as a result building one of these applications is a great way to tour the platform.</p>
<p></p>
<h2>Theming</h2>
<p>Applying a theme to the presentation is simply selecting a Java Look and Feel to apply in Initialize.groovy. The Substance jar is included with the plugin so I test drove a few of the nice setups in there and finally settled on the SubstanceMagmaLookAndFeel. There is definitely a wide variety of L&amp;F&#8217;s to choose from in that bundle alone and, although I haven&#8217;t done it myself, they seem pretty tweakable as well. Plus any old L&amp;F should plug in nicely, I would imagine. </p>
<pre class="brush: groovy; title: ; notranslate">
//Initialize.groovy
SwingBuilder.lookAndFeel('org.jvnet.substance.skin.SubstanceMagmaLookAndFeel',
       'mac', 'nimbus', 'gtk', ['metal', [boldFonts: false]])
</pre>
<p></p>
<h2>Layout</h2>
<p>Controlling the page composition is a standard Swing Layout or, in the case of the default slide you get with the included &#8220;create-slide&#8221; script, a MigLayout. Framing the standard variety of slides is very simple. Bulleted pages, title slides, code slides and custom layouts are very easy to accomplish. I don&#8217;t have a lot of experience using this particular layout but the presentations Andres has made available on github have a good diversity of examples of how they look in practice.</p>
<pre class="brush: groovy; title: ; notranslate">
//the default create-slide generated template
import net.miginfocom.swing.MigLayout

slide(id: &quot;slide0&quot;, layout: new MigLayout(&quot;fill&quot;,&quot;[center]&quot;,&quot;[center]&quot;)) {
    label(&quot;Insert your text here&quot;)
}
</pre>
<p></p>
<h2>Styling</h2>
<p>Styling is supplied by the css plugin, on which slideware has a dependency. The default style.css file sets out just some reasonable defaults for the fonts used in different parts of the app, and I didn&#8217;t see any real need to fiddle with it. Especially happy to see the nice monospace code font. On a totally related note I recently installed the <a href="http://www.levien.com/type/myfonts/inconsolata.html">Inconsolata</a> monospace font to try for development and I&#8217;ve been very happy seeing it in my editor, but it&#8217;s still nice to see this kind of polish applied to the presentation. The code editor view even includes syntax highlighting! More on that coming right up&#8230;</p>
<p></p>
<h2>Slide Transitions</h2>
<p>Moving between slides with style is the responsibility of the <a href="http://griffon.codehaus.org/Transitions+Plugin">transitions plugin</a>. You can see see all of the animations this plugin enables over here at <a href="http://javagraphics.blogspot.com/2007/04/slideshows-transitions-swf.html">this page describing Transitions and Transition2Ds</a>. Pretty slick stuff and defined as simply as a parameter to each &#8220;slide&#8221; node in a script.</p>
<pre class="brush: groovy; title: ; notranslate">
slide(id: &quot;slide3&quot;, layout: new MigLayout(&quot;fill&quot;,&quot;3%[center]3%&quot;,&quot;3%[center]3%&quot;),
        title: &quot;Junit3&quot;,
        transition: new FlurryTransition2D(Transition2D.OUT)) {
    scrollPane(constraints: &quot;grow&quot;) {
        widget(createEditor(text: script))
    }
}
</pre>
<p></p>
<h2>Code Editor</h2>
<p>Code slides embed an editable widget and allow for composing and executing Groovy scripts or classes of arbitrary complexity. You can execute the code with a keyboard shortcut and a window will open displaying the console output. The code itself is executed through a GroovyShell, enabling pretty much anything you might want to do. If you have an internet connection and the required repositories configured, Grapes simplifies packaging the dependencies for the application as your code samples can directly Grab the jars they need. Basically, the first time you execute a code slide you&#8217;ll have to put up with a small pause while Ivy downloads to your local repository, unless of course the required dependencies are already there.  In my case I changed strategies from including jars in the application lib directory to a Grapes approach and I think it&#8217;s a better way to go.</p>
<p>I was surprised to find that the editor even included undo functionality. It&#8217;s definitely not close to a full blown IDE, and there&#8217;s absolutely no reason that it should be. For the task of demoing simple code examples it&#8217;s more than up to the task, even to the point of maintaining your edits between slide transitions, allowing you to move back and forth through the slide deck without any state problems.<br />

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/screen-shot-2010-02-11-at-7-47-04-pm.png" title="Code slide with JUnit4 and Hamcrest matcher example" class="shutterset_singlepic38" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/38__x_screen-shot-2010-02-11-at-7-47-04-pm.png" alt="Code slide with JUnit4 and Hamcrest matcher example" title="Code slide with JUnit4 and Hamcrest matcher example" />
</a>
</p>
<p></p>
<h2>Export</h2>
<p>The application includes a &#8220;Print&#8221; feature which iterates through the entire slide deck and renders it to a pdf. Distribution of one of these presentations is really very easy, including the ability to create installers for all major platforms simply by adding the packaging plugin.</p>
<p></p>
<h2>Test Application</h2>
<p>The test app I built while looking into this is pretty simple. It&#8217;s got a title slide, a bullet slide and 4 code slides. The code simply demonstrates how you can create test classes and make assertions for Junit 3(with GroovyTestCase), Junit 4 and TestNG. GroovyShell recognizes all 3 of these test files by interface or annotation and executes them appropriately. In each case the console output of the test framework is the result, including the new Spock inspired ascii art assert failure renderings. The Test result files are also written to disk, and that TestNG html output is what I&#8217;m used to looking at anyhow. Show me the Green!</p>
<p>The last code slide is just a slightly updated version of an example script on the Grapes page, using the current version of Google Collections and intentionally introducing a failure- mostly just to show off that new assert rendering I mentioned a moment ago. VERY helpful at highlighting the exact nature of a failure. It also encourages me to pay more attention to how I name variables, something I&#8217;m sure every developer that has ever worked with me will cheer at. Man, I suck at naming things.</p>
<p>I also developed a brute force test that loads each slide and executes scripts if finds embedded there. Failures are hard to detect since the direct output is simply a text block, but some fairly simple regex&#8217;s applied to the output make me at least moderately confident that the code won&#8217;t fail at show time.</p>
<p></p>
<h2>Overall Impression</h2>
<p>It took a couple of afternoons(six hours or so total) to download the source code from github, explore it, create a simple presentation and document the experience. I won&#8217;t begin to suggest that I&#8217;m fully aware of all the details happening behind the scenes, but the end user experience is pretty fluid: create a slide, tailor the layout, add content and then repeat. The included examples were more than enough documentation on how to hit the ground running. The plugin code itself is a great example of the MVC nature of Griffon, not a whole lot of code, but a great deal of power and expressability. There were a couple of glitches happening in the background, mostly just logging to the console with no visible effect to the application, but overall it functioned as well as (not) advertised. For publicly unreleased software it was an absolute pleasure to work with and I plan on continuing with the development of this particular presentation.</p>
<p>Everything you need to build and run this stuff yourself is publicly available. In my case, Griffon generally has a recent Macport available for both the released(griffon @0.2.1) and development versions(griffon-devel @0.3-BETA-2). Switching versions is relatively painless and, for applications this simple, testing out upgrades is basically just going through the presentation once in a functional test. Versions for other platforms can be downloaded from the <a href="http://griffon.codehaus.org/Download">Griffon download page</a>.</p>
<p></p>
<h2>Deliverables</h2>
<p>Source code for the sample application is <a href="http://github.com/kellyrob99/Groovy-Testing-Presentation">available on github here</a>. Please just leave a comment on this page if you have any problems running it.</p>
<p>Here&#8217;s the pdf produced by the application &#8216;Print&#8217; feature: <a class="downloadlink" href="http://www.kellyrob99.com/blog/wp-content/plugins/download-monitor/download.php?id=2" title="Version0.1 downloaded 252 times" >Groovy Testing Presentation (252)</a></p>
<p>And if you don&#8217;t feel like downloading anything, here&#8217;s how it all looks in pretty pictures.<br />

<div class="ngg-galleryoverview" id="ngg-gallery-9-1072">

	<!-- Slideshow link -->
	<div class="slideshowlink">
		<a class="slideshowlink" href="http://www.kellyrob99.com/blog/2010/02/11/a-one-day-griffon-applicationpresentation/?show=slide">
			[Show as slideshow]		</a>
	</div>

	<!-- Piclense link -->
	<div class="piclenselink">
		<a class="piclenselink" href="javascript:PicLensLite.start({feedUrl:'http://www.kellyrob99.com/blog/wp-content/plugins/nextgen-gallery/xml/media-rss.php?gid=9&amp;mode=gallery'});">
			[View with PicLens]		</a>
	</div>
	
	<!-- Thumbnails -->
		
	<div id="ngg-image-35" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/screen-shot-2010-02-11-at-7-46-46-pm.png" title="Title slide" class="shutterset_set_9" >
								<img title="Title slide" alt="Title slide" src="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/thumbs/thumbs_screen-shot-2010-02-11-at-7-46-46-pm.png" width="99" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-36" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/screen-shot-2010-02-11-at-7-46-50-pm.png" title="Bullet slide" class="shutterset_set_9" >
								<img title="Bullet slide" alt="Bullet slide" src="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/thumbs/thumbs_screen-shot-2010-02-11-at-7-46-50-pm.png" width="99" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-37" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/screen-shot-2010-02-11-at-7-47-00-pm.png" title="Code slide with JUnit 3 example" class="shutterset_set_9" >
								<img title="Code slide with JUnit 3 example" alt="Code slide with JUnit 3 example" src="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/thumbs/thumbs_screen-shot-2010-02-11-at-7-47-00-pm.png" width="99" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-38" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/screen-shot-2010-02-11-at-7-47-04-pm.png" title="Code slide with JUnit4 and Hamcrest matcher example" class="shutterset_set_9" >
								<img title="Code slide with JUnit4 and Hamcrest matcher example" alt="Code slide with JUnit4 and Hamcrest matcher example" src="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/thumbs/thumbs_screen-shot-2010-02-11-at-7-47-04-pm.png" width="99" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-39" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/screen-shot-2010-02-11-at-7-47-08-pm.png" title="Code slide with TestNG example" class="shutterset_set_9" >
								<img title="Code slide with TestNG example" alt="Code slide with TestNG example" src="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/thumbs/thumbs_screen-shot-2010-02-11-at-7-47-08-pm.png" width="99" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-40" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/screen-shot-2010-02-11-at-7-47-13-pm.png" title="Code slide with Google Collections example" class="shutterset_set_9" >
								<img title="Code slide with Google Collections example" alt="Code slide with Google Collections example" src="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/thumbs/thumbs_screen-shot-2010-02-11-at-7-47-13-pm.png" width="99" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-41" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/screen-shot-2010-02-08-at-8-53-43-pm.png" title="Help screen showing keyboard shortcuts" class="shutterset_set_9" >
								<img title="Help screen showing keyboard shortcuts" alt="Help screen showing keyboard shortcuts" src="http://www.kellyrob99.com/blog/wp-content/gallery/groovy-testing-presentation-with-griffon/thumbs/thumbs_screen-shot-2010-02-08-at-8-53-43-pm.png" width="99" height="75" />
							</a>
		</div>
	</div>
	
		
 	 	
	<!-- Pagination -->
 	<div class='ngg-clear'></div>
 	
</div>

</p>
<div class="zemanta-pixie"><a class="zemanta-pixie-a" href="http://reblog.zemanta.com/zemified/a9a507d7-67b9-4178-bf0f-e90f2cc1d0a6/" title="Reblog this post [with Zemanta]"><img class="zemanta-pixie-img" src="http://img.zemanta.com/reblog_c.png?x-id=a9a507d7-67b9-4178-bf0f-e90f2cc1d0a6" alt="Reblog this post [with Zemanta]" /></a><span class="zem-script more-related pretty-attribution"><script type="text/javascript" src="http://static.zemanta.com/readside/loader.js" defer="defer"></script></span></div>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2009/08/27/vijug-griffongroovy-presentation/' rel='bookmark' title='VIJUG Griffon/Groovy Presentation'>VIJUG Griffon/Groovy Presentation</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/05/15/achieving-groovy-like-fluency-in-java-with-google-collections/' rel='bookmark' title='Achieving Groovy-like Fluency in Java with Google Collections'>Achieving Groovy-like Fluency in Java with Google Collections</a></li>
<li><a href='http://www.kellyrob99.com/blog/2009/03/15/fun-day-playing-with-new-stuff/' rel='bookmark' title='Fun day playing with new Stuff'>Fun day playing with new Stuff</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/02/11/a-one-day-griffon-applicationpresentation/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Thanks for the shirt Atlassian!</title>
		<link>http://www.kellyrob99.com/blog/2010/01/27/thanks-for-the-shirt-atlassian/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=thanks-for-the-shirt-atlassian</link>
		<comments>http://www.kellyrob99.com/blog/2010/01/27/thanks-for-the-shirt-atlassian/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 04:12:43 +0000</pubDate>
		<dc:creator>TheKaptain</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Atlassian]]></category>
		<category><![CDATA[Balsamiq]]></category>
		<category><![CDATA[Bamboo]]></category>
		<category><![CDATA[Confluence]]></category>
		<category><![CDATA[Dragon]]></category>
		<category><![CDATA[Jira]]></category>
		<category><![CDATA[kellyrob]]></category>
		<category><![CDATA[OmniGraffle]]></category>
		<category><![CDATA[theKaptain]]></category>
		<category><![CDATA[Wiki]]></category>

		<guid isPermaLink="false">http://www.kellyrob99.com/blog/?p=1052</guid>
		<description><![CDATA[So my t-shirt arrived today in the mail compliments of Atlassian. Bright green and well earned when I slayed the dragon, I&#8217;ll wear it with pride.&#160; So far I&#8217;ve been getting the most mileage out of Bamboo and Jira, but I&#8217;ve also been tweaking Confluence to make it just right. Following right along with Atlassian&#8217;s [...]
Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/01/02/atlassian-here-be-dragons/' rel='bookmark' title='Atlassian: Here Be Dragons'>Atlassian: Here Be Dragons</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/02/21/developing-faster-with-the-atlassian-intellij-connector/' rel='bookmark' title='Developing Faster with the Atlassian IntelliJ Connector'>Developing Faster with the Atlassian IntelliJ Connector</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/01/07/bamboo-grails-and-git-for-continuous-integration/' rel='bookmark' title='Bamboo, Grails and Git for Continuous Integration'>Bamboo, Grails and Git for Continuous Integration</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>So my t-shirt arrived today in the mail compliments of <a class="zem_slink" href="http://www.atlassian.com/" title="Atlassian" rel="homepage">Atlassian</a>. Bright green and well earned <a href="http://www.kellyrob99.com/blog/2010/01/02/atlassian-here-be-dragons/">when I slayed the dragon</a>, I&#8217;ll wear it with pride.&nbsp; So far I&#8217;ve been getting the most mileage out of Bamboo and Jira, but I&#8217;ve also been tweaking Confluence to make it <em>just</em> right. Following right along with Atlassian&#8217;s lead, both <a href="https://plugins.atlassian.com/plugin/details/13744">TaskDock</a> and <a href="https://plugins.atlassian.com/plugin/details/254">Gliffy</a> are offering $10 donation licenses for less than ten user systems, so I&#8217;ve pretty much <strong>got</strong> to at least try them out right?</p>
<p>Actually I&#8217;ve used Gliffy in Confluence before, and it&#8217;s come in handy more than once or twice. But between <a href="http://www.balsamiq.com/products/mockups/desktop">Balsamiq</a> and <a href="http://www.omnigroup.com/applications/OmniGraffle/">OmniGraffle</a> I&#8217;m already well equipped to cover up the fact that my artistic abilities lie somewhere below drawing <a class="zem_slink" href="http://en.wikipedia.org/wiki/Stick_figure" title="Stick figure" rel="wikipedia">stick men</a>. TaskDock has however been installed and set up to nag me via email when I am getting behind schedule. Next will be Customware&#8217;s <a href="http://www.customware.net/repository/display/AtlassianPlugins/Scaffolding+Plugin">scaffolding</a> and <a href="http://www.customware.net/repository/display/AtlassianPlugins/Reporting+Plugin">reporting</a> plugins.  The scaffolding capabilities make dealing with tables in Confluence a breeze &#8211; almost(but not quite) enough to make me abandon the wiki editor completely. Why take my word for it when you can just <a href="http://www.customware.net/repository/download/attachments/2072/SCAFF101_Table.mov?version=1">watch the video</a>?</p>
<p>Anyhow, so far I&#8217;m very happy with the software and how it&#8217;s already helped me organize projects at home better. The t-shirt is just a nice bonus.</p>

<a href="http://www.kellyrob99.com/blog/wp-content/gallery/atlassian/img_1405.jpg" title="Well earned and bright green, I&amp;#039;ll wear it with pride." class="shutterset_singlepic34" >
	<img class="ngg-singlepic" src="http://www.kellyrob99.com/blog/wp-content/gallery/cache/34__770x_img_1405.jpg" alt="Here&#039;s the t-shirt" title="Here&#039;s the t-shirt" />
</a>

<div class="zemanta-pixie"><a class="zemanta-pixie-a" href="http://reblog.zemanta.com/zemified/d2e13ff0-ce55-4eb2-959f-765985ac709f/" title="Reblog this post [with Zemanta]"><img class="zemanta-pixie-img" src="http://img.zemanta.com/reblog_c.png?x-id=d2e13ff0-ce55-4eb2-959f-765985ac709f" alt="Reblog this post [with Zemanta]" /></a><span class="zem-script more-related pretty-attribution"><script type="text/javascript" src="http://static.zemanta.com/readside/loader.js" defer="defer"></script></span></div>
<p>Related posts:<ol>
<li><a href='http://www.kellyrob99.com/blog/2010/01/02/atlassian-here-be-dragons/' rel='bookmark' title='Atlassian: Here Be Dragons'>Atlassian: Here Be Dragons</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/02/21/developing-faster-with-the-atlassian-intellij-connector/' rel='bookmark' title='Developing Faster with the Atlassian IntelliJ Connector'>Developing Faster with the Atlassian IntelliJ Connector</a></li>
<li><a href='http://www.kellyrob99.com/blog/2010/01/07/bamboo-grails-and-git-for-continuous-integration/' rel='bookmark' title='Bamboo, Grails and Git for Continuous Integration'>Bamboo, Grails and Git for Continuous Integration</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.kellyrob99.com/blog/2010/01/27/thanks-for-the-shirt-atlassian/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

