<?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"
	>

<channel>
	<title>m i k e  b r e v o o r t &#187; Grails</title>
	<atom:link href="http://mike.brevoort.com/category/grails/feed/" rel="self" type="application/rss+xml" />
	<link>http://mike.brevoort.com</link>
	<description>life technology cycling etc</description>
	<pubDate>Wed, 07 May 2008 04:00:00 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5</generator>
	<language>en</language>
			<item>
		<title>Colorado Springs Open Source Software Meetup Group</title>
		<link>http://mike.brevoort.com/2008/02/29/colorado-springs-open-source-software-meetup-group/</link>
		<comments>http://mike.brevoort.com/2008/02/29/colorado-springs-open-source-software-meetup-group/#comments</comments>
		<pubDate>Fri, 29 Feb 2008 06:37:39 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Technology]]></category>

		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2008/02/29/colorado-springs-open-source-software-meetup-group/</guid>
		<description><![CDATA[Tonight I headed down to the Springs for the first meeting of the Colorado Springs Open Source Software Meetup Group.  I learned about the group from this post on the Atlassian developer blog.  Though it was a bit slow tonight, overall it was a good event and I think it will develop into [...]]]></description>
			<content:encoded><![CDATA[<p>Tonight I headed down to the Springs for the first meeting of the <a href="http://opensource.meetup.com/88/">Colorado Springs Open Source Software Meetup Group</a>.  I learned about the group from <a href="http://blogs.atlassian.com/developer/2008/02/atlassian_wants_to_sponsor_you.html">this post</a> on the <a href="http://www.atlassian.com">Atlassian</a> <a href="http://blogs.atlassian.com/developer/">developer blog</a>.  Though it was a bit slow tonight, overall it was a good event and I think it will develop into a solid user group.  My only concern is that the topic is too broad to successfully satisfy everyone&#8217;s interest.  Tonight&#8217;s speaker was Kirstan Vandersluis who demoed the open source data integration platform <a href="http://www.xaware.com/">XAware</a>.  There seems to be a lot of momentum in the commercially backed open source BI/EAI space lately with others including <a href="http://www.pentaho.com/">Pentaho</a> and <a href="http://www.apatar.com/">Apatar</a>.</p>
<p>I walked away tonight with a free license of Intellij IDEA so thanks to Dave Booth from <a href="http://www.jetbrains.com/">Jetbrains</a> for the free swag!  Definitely my favorite IDE, and I was actually in need of a license!  And thanks <a href="http://www.teksystems.com/">TEKsystems</a> for the food and the other sponsors as well!</p>
<p>I&#8217;m scheduled to present on <a href="http://grails.org">Grails</a> in May so if you&#8217;re in the area feel free to come heckle!  Wow, four sentences ending in exclamation points (make that five)!</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/02/29/colorado-springs-open-source-software-meetup-group/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Part 2: Terracotta: 1, Grails Searchable Plugin+Me: 1</title>
		<link>http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/</link>
		<comments>http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/#comments</comments>
		<pubDate>Wed, 30 Jan 2008 00:36:56 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Technology]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[compass]]></category>

		<category><![CDATA[terracotta]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/</guid>
		<description><![CDATA[Round Two of my quest to cluster the Grails Searchable Plugin index with Terracotta!  In my first post I outlined my intent to use Terracotta to cluster the Grails Searchable Plugin (Lucene + Compass) using the Lucene RAMDirectory approach.  Incidentally, my first attempt failed miserably.
As a quick confidence booster before setting out again, [...]]]></description>
			<content:encoded><![CDATA[<p>Round Two of my quest to cluster the <a href="http://grails.codehaus.org/Searchable+Plugin">Grails Searchable Plugin</a> index with Terracotta!  In <a href="http://mike.brevoort.com/2008/01/22/terracotta-1-grails-searchable-pluginme-0/">my first post</a> I outlined my intent to use <a href="http://www.terracotta.org">Terracotta</a> to cluster the Grails Searchable Plugin (<a href="http://www.google.com/url?sa=t&#038;ct=res&#038;cd=2&#038;url=http%3A%2F%2Flucene.apache.org%2F&#038;ei=F72fR6mANY-4gQTJweS1Bw&#038;usg=AFQjCNFlWzRUABueiSQ0PYLo1g0KjXCBRw&#038;sig2=TXtJGiDzcEqX2_NScUhT1Q">Lucene</a> + <a href="http://www.google.com/url?sa=t&#038;ct=res&#038;cd=1&#038;url=http%3A%2F%2Fwww.opensymphony.com%2Fcompass%2F&#038;ei=Br2fR6f-EabMgQSgrP27Bw&#038;usg=AFQjCNFWrf7kReBpKrslhJMYYfgcC03KXQ&#038;sig2=Zggi_LhkubznLIr6dGQwzA">Compass</a>) using the <a href="http://www.terracotta.org/confluence/display/integrations/Lucene">Lucene RAMDirectory</a> approach.  Incidentally, my first attempt failed miserably.</p>
<p>As a quick confidence booster before setting out again, I <a href="http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/">successfully clustered the Grails Searchable Plugin using a JDBCDirectory store</a> for the index.  Since my last attempt I received some <a href="http://www.nabble.com/Compass%2C-Lucene-and-Grails-Searchable-Plugin-td15021230.html">guidance from the guys at Terracotta</a> and learned that <a href="http://www.kimchy.org/">Shay Banon</a> is working with Terrocotta to develop a Compass module for Terracotta.  Good stuff&#8230; check out the details of that <a href="http://www.nabble.com/FYI-on-Compass---Lucene-Integration-td15094091.html">here</a>. </p>
<p>The first hurdle I needed to overcome was the classloader error:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
Classloader name not set, instances defined from this
loader not supported in Terracotta
(loader: org.codehaus.groovy.grails.cli.support.GrailsRootLoader)
</pre>
<p>Before an object can be shared by Terracotta, the ClassLoader that loaded the object&#8217;s class has to be known to Terracotta. For core java and supported frameworks/container Terracotta takes care of registering relevant classloaders.  For the GrailsRootLoader I can do this one of two ways: </p>
<ol>
<li>hack the grails source where the class loader is instantiated, registering it with Terracotta</li>
<li>this can be converted into a config module that will inject the proper byte code at runtime so as to avoid any code tweaking.  </li>
</ol>
<p>The guys at Terracotta offered to help with #2 if I could get #1 working.</p>
<p>So I checked out the Grail trunk from SVN, and added these lines after the GrailsRootLoader is created:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
 // create loader and execute main class
GrailsRootLoader loader = new GrailsRootLoader(lc);
((com.tc.object.loaders.NamedClassLoader) loader).__tc_setClassLoaderName("Grail Classloader");
com.tc.object.bytecode.hook.impl.ClassProcessorHelper.registerGlobalLoader((com.tc.object.loaders.NamedClassLoader) loader);
</pre>
<p>I built the Grails jars and replaced them in my grails-1.0-final-SNAPSHOT/dist directory.  That resolved my classloader error!  Next I went through about 100 iterations of root and lock configuration for my tc-config.xml as I dug and spun my way around the Compass source.  I finally ended up with this for my tc-config.xml (keep in mind this can surely be optimized and is pretty brute force):</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
&lt;?xml version="1.0" encoding="UTF-8" ?&gt;

&lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&gt;
  &lt;system&gt;
    &lt;configuration-model&gt;development&lt;/configuration-model&gt;
  &lt;/system&gt;

  &lt;servers&gt;
    &lt;server name="localhost" /&gt;
  &lt;/servers&gt;

  &lt;clients&gt;
    &lt;logs&gt;%d/client-logs-%h&lt;/logs&gt;
    &lt;dso&gt;

       &lt;debugging&gt;
        &lt;runtime-logging&gt;
          &lt;lock-debug&gt;true&lt;/lock-debug&gt;
        &lt;/runtime-logging&gt;
        &lt;runtime-output-options&gt;
          &lt;full-stack&gt;true&lt;/full-stack&gt;
        &lt;/runtime-output-options&gt;
      &lt;/debugging&gt;

    &lt;/dso&gt;
    &lt;modules&gt;
      &lt;module name="clustered-lucene-2.0.0" version="2.5.0"/&gt;
    &lt;/modules&gt;
  &lt;/clients&gt;

  &lt;application&gt;
    &lt;dso&gt;
      &lt;instrumented-classes&gt;
        &lt;include&gt;
          &lt;class-expression&gt;org.compass.core.lucene.engine..*&lt;/class-expression&gt;
        &lt;/include&gt;
        &lt;include&gt;
          &lt;class-expression&gt;org.apache.lucene..*&lt;/class-expression&gt;
        &lt;/include&gt;
      &lt;/instrumented-classes&gt;
      &lt;roots&gt;
        &lt;root&gt;
          &lt;field-name&gt;org.compass.core.lucene.engine.store.RAMLuceneSearchEngineStore.ramIndexes&lt;/field-name&gt;
        &lt;/root&gt;
      &lt;/roots&gt;
      &lt;locks&gt;
	&lt;named-lock&gt;
          &lt;method-expression&gt;* org.compass.core.lucene.engine.manager.DefaultLuceneSearchEngineIndexManager.*(..)&lt;/method-expression&gt;
          &lt;lock-level&gt;write&lt;/lock-level&gt;
          &lt;lock-name&gt;theLockName&lt;/lock-name&gt;
        &lt;/named-lock&gt;
        &lt;/locks&gt;
     &lt;/dso&gt;
  &lt;/application&gt;
&lt;/tc:tc-config&gt;
</pre>
<p>It worked!  I was able to test with the Terracotta server running, and two Grails apps running in separate JVMs that all of the Domain class data that the first JVM indexed, could be searched by the second JVM and they both returned identical results.  I also verified the existence of the objects under the root in the Terracotta Admin GUI.  And finally, I shut both Grails app JVMs down and brought them back up and my index was still available.  </p>
<p>What&#8217;s next?  Work to get a config module for Terracotta and optimize my root and locking configuration.  I&#8217;m very interested in what will come of the promised Compass/Terracotta integration.  Also Clustering Grails is a much taller mountain.  I was told that past attempts to cluster Groovy with Terracotta had not been too successful.  For now I&#8217;m happy just to have climbed my little hill&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Using JDBCDirectory with the Grails Searable Plugin</title>
		<link>http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/</link>
		<comments>http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/#comments</comments>
		<pubDate>Fri, 25 Jan 2008 04:05:34 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Technology]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[compass]]></category>

		<category><![CDATA[lucene]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/</guid>
		<description><![CDATA[In my last post I mentioned that one of the options I was considering for clustering the Grails Searchable plugin, though not the preferred option, was to use the JDBCDirectory implementation of Lucene.  I had this working in just 15 minutes and though it&#8217;s probably not the optimal approach, it is by far the [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://mike.brevoort.com/2008/01/22/terracotta-1-grails-searchable-pluginme-0/">last post</a> I mentioned that one of the options I was considering for clustering the Grails Searchable plugin, though not the preferred option, was to use the <a href="http://www.opensymphony.com/compass/versions/0.9.0/api/org/apache/lucene/store/jdbc/JdbcDirectory.html">JDBCDirectory</a> implementation of Lucene.  I had this working in just 15 minutes and though it&#8217;s probably not the optimal approach, it is by far the simplest.</p>
<p>Just to set the stage, I&#8217;m running Grails RC3, Groovy 1.5.1, JDK 1.6, grails-searchable-0.4-SNAPSHOT and MySQL 5.0.45.  I will configure the <a href="http://www.opensymphony.com/compass/">Compass</a> to use the JdbcDirectory connection instead of file or ram and test that it can be updated and read by two instances of my Grails application.</p>
<p>First I created compass.cfg.xml in grails-app/conf (just needs to be somewhere in the classpath) with jdbc connection details:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
&lt;compass-core-config xmlns="http://www.opensymphony.com/compass/schema/core-config"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.opensymphony.com/compass/schema/core-config
          http://www.opensymphony.com/compass/schema/compass-core-config.xsd"&gt;
   &lt;compass name="default"&gt;
     &lt;connection&gt;
         &lt;jdbc dialect="org.apache.lucene.store.jdbc.dialect.MySQLDialect"&gt;
             &lt;dataSourceProvider&gt;
                 &lt;driverManager url="jdbc:mysql://localhost/search?emulateLocators=true"
                                      username="root" password="password"
                                      driverClass="com.mysql.jdbc.Driver" /&gt;
             &lt;/dataSourceProvider&gt;
             &lt;fileEntries&gt;
                 &lt;fileEntry name="__default__"&gt;
                     &lt;indexInput bufferSize="4096" /&gt;
                     &lt;indexOutput bufferSize="4096" /&gt;
                 &lt;/fileEntry&gt;
             &lt;/fileEntries&gt;
         &lt;/jdbc&gt;
     &lt;/connection&gt;
   &lt;/compass&gt;
&lt;/compass-core-config&gt;
</pre>
<p>One thing I missed at first was the dialect setting in the jdbc tag.  Make sure you select the correct dialect for your database.  I used <a href="http://static.compassframework.org/docs/latest/jdbcdirectory.html">this as a reference</a>.<br />
In SearchableConfiguration.groovy I set compassConnection to null</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
String compassConnection = null
</pre>
<p>I started my grails app and hit just one more snag, I got a &#8220;packet too large&#8221; error while it was building the index.  Turns out the default max_allowed_packet in MySQL on the server is 1M and since Lucene stores parts of the index in BLOBs I needed to up the max.  I found <a href="http://dev.mysql.com/doc/refman/5.0/en/packet-too-large.html">this article</a> and set the max_allowed_packet setting to 16M.  I did this in my.ini:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
[mysqld]
max_allowed_packet=16M
</pre>
<p>That was it!  I tested by running two instances of my Grails application simultaneously and I modified one of my Domain class instances and executed a search on the other instance and within a few seconds, the new value was returned in my search.</p>
<p>The last thing I considered was configuring a <a href="http://www.opensymphony.com/compass/versions/1.2/html/core-connection.html#core-connection-localcache">Local Directory Cache</a> in Compass.  This seemed like it could offer some good optimization though it was unclear from the documentation how much control you have over the size of the cache, what gets cached, the TTL, etc.  Also, I soon realized that this was introduced in the latest version of Compass (1.2) and isn&#8217;t  the version that is bundled in the Searchable plugin.  </p>
]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/01/24/using-jdbcdirectory-with-the-grails-searable-plugin/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Terracotta: 1, Grails Searchable Plugin+Me: 0</title>
		<link>http://mike.brevoort.com/2008/01/22/terracotta-1-grails-searchable-pluginme-0/</link>
		<comments>http://mike.brevoort.com/2008/01/22/terracotta-1-grails-searchable-pluginme-0/#comments</comments>
		<pubDate>Wed, 23 Jan 2008 04:46:53 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Technology]]></category>

		<category><![CDATA[compass]]></category>

		<category><![CDATA[terracotta]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2008/01/22/terracotta-1-grails-searchable-pluginme-0/</guid>
		<description><![CDATA[I&#8217;m on a quest to figure out how to cluster the Grails Searchable plugin that&#8217;s based on Lucene/Compass across multiple nodes with as little intrusion and in a way that&#8217;s as turnkey as possible.  I&#8217;m in immediate need of a solution, and I think it would be a good contribution to the Searchable plugin.
To [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m on a quest to figure out how to cluster the <a href="http://grails.org/Searchable+Plugin">Grails Searchable plugin</a> that&#8217;s based on<a href="http://lucene.apache.org/"> Lucene</a>/<a href="http://www.opensymphony.com/compass/">Compass</a> across multiple nodes with as little intrusion and in a way that&#8217;s as turnkey as possible.  I&#8217;m in immediate need of a solution, and I think it would be a good contribution to the Searchable plugin.</p>
<p>To start here&#8217;s what I&#8217;m considering:</p>
<ol>
<li> Manage a local index per node.  Probably disable mirrorChanges via Compass::GPS and rebuild the index on someinterval. <i>This is not very desirable since it would eliminate the Compass:GPS capability, and there just must be a more elegant way&#8230;</i></li>
<li>Use the <a href="http://www.opensymphony.com/compass/versions/0.9.0/api/org/apache/lucene/store/jdbc/JdbcDirectory.html">JDBCDirectory</a> implementation of Lucene and store the index in a sql database. <i>This option is viable but has obvious performance implications that somewhat defeat the purpose.  The configuration would be fairly clean using the <a href="http://www.opensymphony.com/compass/versions/1.1/html/core-configuration.html#core-configuration-xml">native Compass XML config</a>.  This maybe a good fall back option to do some A/B testing against. </i></li>
<li>Use <a href="http://www.terracotta.org/confluence/display/integrations/Lucene">Terracotta and RAMDirectory</a> to handle synchronization of the index across nodes. <i>This has a lot of promise and will be the path I head down first.  Though I have no experience whatsoever with Terracotta</i></li>
</ol>
<p>Another possibility is to look at <a href="http://www.kimchy.org/compasslucene-and-datagrids/">Compass&#8217; new support for Gigaspaces</a>.   Thanks <a href="http://marcospereira.wordpress.com">Marcos</a> for passing that on.  This sounds interesting but &#8220;feels&#8221; fairly heavy compared to the others, though I know nothing about <a href="http://www.gigaspaces.com/">GigaSpaces</a> or <a href="http://www.oracle.com/technology/products/coherence/">Coherence</a> so I&#8217;m just talking out of my arse at this point!</p>
<p>I made my first attempt with Terracotta and Compass today.  I dug deep enough into Compass to find that it manages the RAMDirectory objects in this class: org.compass.core.lucene.engine.store.RAMLuceneSearchEngineStore and manages each subindex RAMDirectory in a java.util.HashMap called ramIndexes.  The first issue I had to overcome was that HashMap isn&#8217;t a synchronized data structure, and I was having problems configuring the locking in Terracotta for ramIdexes.  I kept getting  UnlockedSharedObjectException exceptions not matter what I tried.</p>
<p>After a little help from the Terracotta users list I ended up with a named lock.  My tc-config.xml looked like this:</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&gt;
  &lt;system&gt;
    &lt;configuration-model&gt;development&lt;/configuration-model&gt;
  &lt;/system&gt;

  &lt;servers&gt;
    &lt;server name="localhost" /&gt;
  &lt;/servers&gt;

  &lt;clients&gt;
    &lt;logs&gt;%d/client-logs-%h&lt;/logs&gt;
    &lt;dso&gt;
      &lt;debugging&gt;
        &lt;runtime-logging&gt;
          &lt;lock-debug&gt;true&lt;/lock-debug&gt;
        &lt;/runtime-logging&gt;
        &lt;runtime-output-options&gt;
          &lt;full-stack&gt;true&lt;/full-stack&gt;
        &lt;/runtime-output-options&gt;
      &lt;/debugging&gt;
    &lt;/dso&gt;
    &lt;modules&gt;
      &lt;module name="clustered-lucene-2.0.0" version="2.5.0"/&gt;
    &lt;/modules&gt;
  &lt;/clients&gt;

  &lt;application&gt;
    &lt;dso&gt;
      &lt;instrumented-classes&gt;
        &lt;include&gt;
          &lt;class-expression&gt;org.compass.core.lucene.engine.store.RAMLuceneSearchEngineStore&lt;/class-expression&gt;
        &lt;/include&gt;
      &lt;/instrumented-classes&gt;
      &lt;roots&gt;
        &lt;root&gt;
          &lt;field-name&gt;org.compass.core.lucene.engine.store.RAMLuceneSearchEngineStore.ramIndexes&lt;/field-name&gt;
        &lt;/root&gt;
      &lt;/roots&gt;
      &lt;locks&gt;
	&lt;named-lock&gt;
          &lt;method-expression&gt;* org.compass.core.lucene.engine.store.RAMLuceneSearchEngineStore.*(..)&lt;/method-expression&gt;
          &lt;lock-level&gt;write&lt;/lock-level&gt;
          &lt;lock-name&gt;theLockName&lt;/lock-name&gt;
        &lt;/named-lock&gt;
      &lt;/locks&gt;
     &lt;/dso&gt;
  &lt;/application&gt;
&lt;/tc:tc-config&gt;
</pre>
<p>That at least got me past the UnlockSharedObjectException, but tonight I hit a bigger roadblock.  Terracotta is choking on Grails custom ClassLoader.  I did a preliminary search on the error message below but came up short.  I followed up on the Terracotta users&#8217; list but I thought I&#8217;d share my progress and my intentions here in case anyone out there has any ideas&#8230;</p>
<pre class="prettyprint" style="line-height:normal;width:500px;font-size:11px;overflow:auto">
Error creating bean with name 'compassGps': Cannot resolve reference to
bean'compass' while setting bean property 'compass'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'compass': FactoryBean threw exception on object creation;
nested exception is java.lang.IllegalStateException: Classloader name not set,
instances defined from this loader not supported in Terracotta (loader:
org.codehaus.groovy.grails.cli.support.GrailsRootLoader):
java.lang.IllegalStateException: Classloader name not set, instances
defined from this loader not supported in Terracotta (loader:
org.codehaus.groovy.grails.cli.support.GrailsRootLoader)
</pre>
<p>Stay tuned&#8230;</p>
<p><b>Update (Jan 29, 2008):</b> <a href="http://mike.brevoort.com/2008/01/29/terracotta-1-grails-searchable-pluginme-1/">See part 2 here</a></p>
]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/01/22/terracotta-1-grails-searchable-pluginme-0/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Building Grails Applications with Hudson</title>
		<link>http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/</link>
		<comments>http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/#comments</comments>
		<pubDate>Mon, 21 Jan 2008 18:33:10 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<category><![CDATA[Technology]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[continuous integration]]></category>

		<category><![CDATA[hudson]]></category>

		<guid isPermaLink="false">http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/</guid>
		<description><![CDATA[I&#8217;m never surprised by the shear magnitude of stuff I don&#8217;t know about.  Last week I stumbled upon Hudson as I was searching for help to configure Cruise Control to build and execute tests for my  a Grails application.  I found this post that introduced me to Hudson and got me started.
Let [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m never surprised by the shear magnitude of stuff I don&#8217;t know about.  Last week I stumbled upon <a href="https://hudson.dev.java.net/">Hudson</a> as I was searching for help to configure <a href="http://cruisecontrol.sourceforge.net/">Cruise Control</a> to build and execute tests for my  a <a href="http://grails.codehaus.org/">Grails</a> application.  I found <a href="http://www.giolist.com/2008_01_01_giolist-archive.html">this post</a> that introduced me to Hudson and got me started.</p>
<p>Let me first say that I was off to find a free solution.  If I had the luxury of spending a little cash at this point I would have used <a href="http://www.atlassian.com/software/bamboo/">Bamboo</a>.  I&#8217;m a big fan of <a href="http://www.atlassian.com">Atlassian</a> products and love what they are doing to integrate Jira, Fisheye, Bamboo, Crucible, Clover and Confluence.  The traceability of code to issues to change sets to builds and tests is really cool.  Anyway I digress.  </p>
<p>So I found Hudson, and I was pleasantly surprised how easy it was to set up.  I&#8217;m running on Windows with Tomcat 6 and JDK1.6.  I simply deployed the Hudson WAR, and I was off to the races.  Hudson&#8217;s configuration is all done via a web interface and the interface itself is very clean, especially compared to Cruise Control.  </p>
<p>In Hudson I created a new job, selected SVN in the source code management section and entered the URL to my Grails app in the repository.  Hudson also lets you configure a repository browser (ViewSVN, Fisheye, WebSVN or Sventon).  Since I was already running Tomcat, I chose Sventon and quickly downloaded and deployed the WAR for <a href="http://www.sventon.org/">Sventon</a>.  I set Hudson to poll SVN for changes every minute and for the build itself I told Hudson to use Ant (you need to set up ANT first in Hudsson) and pointed to the Grails build.xml.  </p>
<p>I created two new targets in the build.xml: &#8216;all&#8217; and &#8216;deploy&#8217;.  The all target chains the depended targets together.  I had originally had Hudson call test, war, deploy and doc separately but each invoked a compile separately.</p>
<pre class="prettyprint" style="width:500px;font-size:11px;overflow:auto">
&lt;target name="all" depends="war, test, deploy, doc"
  description="build, test, deploy and build the javadoc"/&gt;
</pre>
<p>I also created a deploy target that takes the war and deploys to Tomcat and property to specify the grails_env.</p>
<p>Under Post-build Actions I set the following properties:</p>
<ul>
<li>Files to Archive = &#8220;**/*.war&#8221;</li>
<li>Javadoc Directory = &#8220;GRAILS-APP/docs/gapi&#8221;</li>
<li>Test Reports XMLs = &#8220;GRAILS-APP/test/reports/*.xml&#8221;</li>
</ul>
<p>So in about an hour I had Hudson continually building, running my test cases, generating javadoc and deploying my WAR to Tomcat, and it was all relatively painless.  Here&#8217;s what the job status screen looks like:<br />
<img src='http://mike.brevoort.com/wp-content/uploads/2008/01/hudson_sh.png' alt='Hudson Screenshot' /></p>
<p>Going forward I&#8217;ll probably investigate using <a href="http://weblogs.java.net/blog/kohsuke/archive/2007/07/hudson_gant_plu.html">GANT instead of ANT</a>, otherwise it&#8217;s serving the purpose.</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.brevoort.com/2008/01/21/building-grails-applications-with-hudson/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
