<?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>Glen Smith &#187; Gravl</title>
	<atom:link href="http://blogs.bytecode.com.au/glen/category/gravl/feed" rel="self" type="application/rss+xml" />
	<link>http://blogs.bytecode.com.au/glen</link>
	<description>Java, XML and all that Jazz... from Canberra, Australia</description>
	<lastBuildDate>Wed, 25 Apr 2012 05:10:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Gravl: Funky Image Preview and Inplace Editing</title>
		<link>http://blogs.bytecode.com.au/glen/2008/01/29/gravl-funky-image-preview-and-inplace-editing.html</link>
		<comments>http://blogs.bytecode.com.au/glen/2008/01/29/gravl-funky-image-preview-and-inplace-editing.html#comments</comments>
		<pubDate>Tue, 29 Jan 2008 11:06:00 +0000</pubDate>
		<dc:creator>Glen</dc:creator>
				<category><![CDATA[Gravl]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://blogs.bytecode.com.au/glens/2008/01/29/gravl-funky-image-preview-and-inplace-editing/</guid>
		<description><![CDATA[I&#8217;ve been having fun implementing my first cut at Image/File management for Gravl, and along the way I&#8217;ve learnt about LightBox and the Scriptaculous InPlaceEditor stuff. First up, I needed a way of doing an image preview, so I could see what all of those PNGs really meant. Lightbox gives you a great way of &#8220;overlaying&#8221; the preview image as a popup without the need to refresh the page. Very snazzy. I followed the instructions [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;ve been having fun implementing my first cut at Image/File management for Gravl, and along the way I&#8217;ve learnt about <a href="http://www.huddletogether.com/projects/lightbox2/">LightBox</a> and the Scriptaculous <a href="http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor">InPlaceEditor</a> stuff.
</p>
<p>
First up, I needed a way of doing an image preview, so I could see what all of those PNGs really meant. Lightbox gives you a great way of &#8220;overlaying&#8221; the preview image as a popup without the need to refresh the page. Very snazzy. I followed the <a href="http://www.huddletogether.com/projects/lightbox2/">instructions</a> and I was up and running in a few minutes.
</p>
<p>
<img src="images/2008/gravlImagePreview.png" alt="Gravl Image Preview with Lightbox"/>
</p>
<p>
Everything will make more sense with a little <a href="images/2008/gravlImages.mov">screencast</a> (1.5mb)
</p>
<p>
Next stop was handling image renaming. I was really after a way to edit the actual filename inplace. Enter <a href="http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor">InPlaceEditor</a>. This call lets you specify the id of the object you want to edit inplace, along with the url to do the ajax call against (which will get passed the user&#8217;s updated value in a <code>params.value</code>). If all is well, you return the changed value and life continues.
</p>
<p>
<img style="border: 1px solid lightgray; margin: 1em" src="images/2008/gravlInplaceRename.png" alt="Gravl Inplace Rename with Scriptaculous"/>
</p>
<p>
Well that was quite a lunch hour. I have a basic image management solution to keep me going so I can now upload the images for this blog entry without needing an SCP client!
</p>
<p>
Happy Previewing in Grails!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.bytecode.com.au/glen/2008/01/29/gravl-funky-image-preview-and-inplace-editing.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Gravl: Autocompleting and Funky Timelines</title>
		<link>http://blogs.bytecode.com.au/glen/2008/01/23/gravl-autocompleting-and-funky-timelines.html</link>
		<comments>http://blogs.bytecode.com.au/glen/2008/01/23/gravl-autocompleting-and-funky-timelines.html#comments</comments>
		<pubDate>Wed, 23 Jan 2008 02:24:00 +0000</pubDate>
		<dc:creator>Glen</dc:creator>
				<category><![CDATA[Gravl]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://blogs.bytecode.com.au/glens/2008/01/23/gravl-autocompleting-and-funky-timelines/</guid>
		<description><![CDATA[If you haven&#8217;t had a chance to play with the RichUI plugin, you&#8217;ve got to take it for a spin &#8211; it&#8217;s just fantastic. I&#8217;ve been meaning to implement autocomplete for Gravl tags on new blog entries, and with the RichUI plugin (which uses Yahoo Autocomplete under the hood) it&#8217;s a total snack. First you declare the RichUI taglibs in your gsp file (note: I&#8217;m using the undocumented delimChar setting so that I separate multiple [...]]]></description>
			<content:encoded><![CDATA[<p>
If you haven&#8217;t had a chance to play with the <a href="http://www.grails.org/RichUI+Plugin">RichUI plugin</a>, you&#8217;ve got to take it for a spin &#8211; it&#8217;s just fantastic. I&#8217;ve been meaning to implement autocomplete for Gravl tags on new blog entries, and with the RichUI plugin (which uses <a href="http://developer.yahoo.com/yui/autocomplete">Yahoo Autocomplete</a> under the hood) it&#8217;s a total snack.
</p>
<p>
First you declare the RichUI taglibs in your gsp file (note: I&#8217;m using the undocumented <i>delimChar</i> setting so that I separate multiple tags with a space):
</p>
<pre class="prettyprint">
&lt;resource:autoComplete skin="default" /&gt;
&lt;richui:autoComplete name="tagList" delimChar=" " style="width: 100%"
    action="${createLinkTo(dir: params.blog+ '/blog/tagcomplete')}"/&gt;
</pre>
<p>
Then you add yourself a backend action that returns some xml representing the items for the list. I filter the tags by hand because I want to keep everything case insensitive, but your might be able to do the lot in a dynamic finder.
</p>
<pre class="prettyprint">
def tagcomplete = {
    Blog blogObj = Blog.findByBlogid(params.blog)
    def queryRegex = "(?i)${params.query}" // case insensitive...
    def tags = blogObj.tags.findAll { tag -> tag.name =~ queryRegex }
    render(contentType: "text/xml") {
        results() {
            tags.each {t ->
                result() {
                    name(t.name)
                }
            }
        }
    }
}
</pre>
<p>
And you&#8217;ve got yourself an autocomplete for tags&#8230;
</p>
<p>
<img src="images/2008/gravlAutocomplete.png" alt="Gravl autocomplete in action"/>
</p>
<p>
Not that we&#8217;ve got a nifty tag autocomplete, it&#8217;s time to take the timeline virtualisation tag for a spin&#8230; One the way into the timeline populate the start date for your entries&#8230;
</p>
<pre class="prettyprint">
def timeline = {
        Blog blogObj = Blog.findByBlogid(params.blog)
        def entries = BlogEntry.findAllByBlogAndStatus(blogObj, "published", [ sort: 'created', order: 'asc'])

        return [ blogObj: blogObj, startDate: entries[0]?.created  ]
    }
</pre>
<p>
Then create the tags in your page to kick things off..
</p>
<pre class="prettyprint">
&lt;resource:timeline /&gt;

&lt;richui:timeline style="height: 500px; border: 1px solid #aaa" startDate="${startDate}" datasource="${createLinkTo(dir: params.blog+ '/timelineData')}" /&gt;
        &lt;g:javascript&gt;
            initTimeline();
        &lt;/g:javascript&gt;
</pre>
<p>
Which will callback to render the data on a timeline&#8230;
</p>
<pre class="prettyprint">

def timelineData = {

        def baseUri = request.scheme + "://" + request.serverName +
                 (request.serverPort != 80 ? ":" +  request.serverPort : "") +
                 grailsAttributes.getApplicationUri(request)

        Blog blogObj = Blog.findByBlogid(params.blog)
        def entries = BlogEntry.findAllByBlogAndStatus(blogObj, "published", [ sort: 'created', order: 'asc'])

        println "Timeline rendering for ${entries.size()} entries"

        render(contentType: "text/xml") {
            SimpleDateFormat sdf = new SimpleDateFormat("MMM dd yyyy HH:mm:ss", Locale.US)

            data() {
                entries.each { entry ->
                    event(start: sdf.format(entry.created),
                            title: entry.title,
                            link: baseUri + entry.toPermalink(),
                            "" )
                    }
            }
        }
    }
</pre>
<p>
And you have one funky looking timeline&#8230; (click on the <a href="http://blogs.bytecode.com.au/glen/timeline">Timeline</a> link on the right gutter if you want to play with the live one)
</p>
<p>
<img src="images/2008/gravlTimeline.png" alt="Gravl timeline in action"/>
</p>
<p>
Well thats enough UI work for one day&#8230; Huge props to Andreas for an outstanding plugin!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.bytecode.com.au/glen/2008/01/23/gravl-autocompleting-and-funky-timelines.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Gravl: Fulltext Search Redux with Searchable</title>
		<link>http://blogs.bytecode.com.au/glen/2008/01/22/gravl-fulltext-search-redux-with-searchable.html</link>
		<comments>http://blogs.bytecode.com.au/glen/2008/01/22/gravl-fulltext-search-redux-with-searchable.html#comments</comments>
		<pubDate>Tue, 22 Jan 2008 08:54:00 +0000</pubDate>
		<dc:creator>Glen</dc:creator>
				<category><![CDATA[Gravl]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://blogs.bytecode.com.au/glens/2008/01/22/gravl-fulltext-search-redux-with-searchable/</guid>
		<description><![CDATA[Thanks to a fantastic tip from Karl on yesterday&#8217;s post, I&#8217;ve got the searchable plugin up and running on my Grails-RC3 install! Here&#8217;s the fix from Karl: i‘ve got a working Searchable-0.4-SNAPSHOT wo. npe, this is working with the RCs too. In the plugin‘s java directory u need to slightly modify the org/codehaus/groovy/grails/plugins/searchable/compass/SearchableCompassUtils.java file. Here is the “patched” version: http://rafb.net/p/prsZip92.html (nopaste url) So I patched my version, and I&#8217;m up and running. Getting Gravl converted [...]]]></description>
			<content:encoded><![CDATA[<p>
Thanks to a fantastic tip from Karl on yesterday&#8217;s post, I&#8217;ve got the searchable plugin up and running on my Grails-RC3 install! Here&#8217;s the fix from Karl:
</p>
<pre style="border: 1px dotted black; padding: 3px;">
i‘ve got a working Searchable-0.4-SNAPSHOT wo. npe, this is working with the RCs too.
In the plugin‘s java directory u need to slightly modify the
org/codehaus/groovy/grails/plugins/searchable/compass/SearchableCompassUtils.java file.

Here is the “patched” version:
<a href="http://rafb.net/p/prsZip92.html">http://rafb.net/p/prsZip92.html</a> (nopaste url)
</pre>
<p>
So I patched my version, and I&#8217;m up and running. Getting Gravl converted over was a snack. Basically, I just had to remove all my custom code! And, of course, add the magic <code>static searchable=true</code> to my <code>BlogEntry</code> object.
</p>
<p>
After I patched the plugin, I ran <code>grails install-searchable-config</code> to get a SearchableConfiguration file in my conf directory. From there I could change the <code>compassConnection</code> setting to point to the place I like to store my indexes.
</p>
<p>
My search action could then shrink to:
</p>
<pre class="prettyprint">
def search = {

        def query = params.query
        def blogid = params.blog

        def results = BlogEntry.search(query, params) 

        return [ results: results, query: query ]
    }
</pre>
<p>
The results you get back in ${results.results} are first class domain objects! So it&#8217;s pretty much just a matter of a little markup&#8230;
</p>
<pre class="prettyprint">
&lt;g:each var=&quot;result&quot; in=&quot;${results.results}&quot;&gt;

                &lt;div class='hit'&gt;

                    &lt;div class='hitEntry'&gt;
                        &lt;div class='hitTitle'&gt;
                            &lt;a href='${request.contextPath}/${result.toPermalink()}'&gt;
                                ${result.title}
                            &lt;/a&gt;
                        &lt;/div&gt;
                        &lt;div class='hitInfo'&gt;
                            &lt;g:niceDate date=&quot;${result.created}&quot;/&gt;
                        &lt;/div&gt;
                        &lt;p class='hitBody'&gt;&lt;/p&gt;
                    &lt;/div&gt;
                &lt;/div&gt;

            &lt;/g:each&gt;
</pre>
<p>
Add a g:paginate into the mix, and you&#8217;re cooking!
</p>
<p>
One thing I have lost in the conversion is the ability to do hit term highlighting. I know Compass supports it, so it might just be a matter of digging in a little deeper! I&#8217;d also like to be able to store some DynamicMetaData with the index (blogEntry.blog.blogid), but haven&#8217;t managed to get the annotations working just yet&#8230;
</p>
<p>
Anyways&#8230; a huge code saving. Give it a try on the top right. And thanks Karl, you&#8217;re a champion!
</p>
<p>
Happy searching!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.bytecode.com.au/glen/2008/01/22/gravl-fulltext-search-redux-with-searchable.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Gravl: Adding Fulltext Search</title>
		<link>http://blogs.bytecode.com.au/glen/2008/01/21/gravl-adding-fulltext-search.html</link>
		<comments>http://blogs.bytecode.com.au/glen/2008/01/21/gravl-adding-fulltext-search.html#comments</comments>
		<pubDate>Mon, 21 Jan 2008 08:54:00 +0000</pubDate>
		<dc:creator>Glen</dc:creator>
				<category><![CDATA[Gravl]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://blogs.bytecode.com.au/glens/2008/01/21/gravl-adding-fulltext-search/</guid>
		<description><![CDATA[I&#8217;ve just finished adding fulltext search to Gravl, and, while is still needs some more CSS tweaks, it&#8217;s working just great. I took the chance to have a good look at the Searchable plugin and it looks awesome! Sadly, it just kept NPEing at me and complaining that it couldn&#8217;t find java.lang.Class! Perhaps it&#8217;s a victim of the RC-flux, no doubt it will resurface as 1.0 settles in. Anyways, I ripped the SearchService out of [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;ve just finished adding fulltext search to Gravl, and, while is still needs some more CSS tweaks, it&#8217;s working just great. I took the chance to have a good look at the <a href="http://grails.codehaus.org/Searchable+Plugin">Searchable</a> plugin and it looks awesome! Sadly, it just kept NPEing at me and complaining that it couldn&#8217;t find java.lang.Class! Perhaps it&#8217;s a victim of the RC-flux, no doubt it will resurface as 1.0 settles in.
</p>
<p>
Anyways, I ripped the SearchService out of Groovyblogs, and I was up and running in an hour. I must bundle that thing into a LuceneSearch plugin someday&#8230; it&#8217;s really very handy. Feel free to have a search in that box at the top right, &#8220;Pebble&#8221; gives you a good chance to see the paginate in action.
</p>
<p style="border: 1px solid black; marking: 3px">
<img src="images/2008/gravlSearch.png" alt="gravl Search in action... searching for Gravl!"/>
</p>
<p>
So that last real piece of the Gravl puzzle is image upload and management. But right now I&#8217;ve got to get cracking on my &#8220;Grails Extreme Makeover&#8221; talk for <a href="http://www.groovygrails.com">G2X</a>.
</p>
<p>
Search on!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.bytecode.com.au/glen/2008/01/21/gravl-adding-fulltext-search.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Gravl: Referers, Geocoding, Charts</title>
		<link>http://blogs.bytecode.com.au/glen/2008/01/17/gravl-referers-geocoding-charts.html</link>
		<comments>http://blogs.bytecode.com.au/glen/2008/01/17/gravl-referers-geocoding-charts.html#comments</comments>
		<pubDate>Wed, 16 Jan 2008 19:10:00 +0000</pubDate>
		<dc:creator>Glen</dc:creator>
				<category><![CDATA[Gravl]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://blogs.bytecode.com.au/glens/2008/01/17/gravl-referers-geocoding-charts/</guid>
		<description><![CDATA[Continuing my obsession with the power of Grails filters, it was time to add some referer tracking and ipaddress Geocoding to Gravl to see where people are coming from. So I created a new RefererFilters class in conf and I was up and running. I already had a little CacheService happening, so I created a new 24 hour cache, scooped up some interesting browser header data, and squirrelled it away for later: // Scoop up [...]]]></description>
			<content:encoded><![CDATA[<p>
Continuing my obsession with the power of Grails filters, it was time to add some referer tracking and ipaddress Geocoding to Gravl to see where people are coming from. So I created a new <code>RefererFilters</code> class in <code>conf</code> and I was up and running. I already had a little CacheService happening, so I created a new 24 hour cache, scooped up some interesting browser header data, and squirrelled it away for later:
</p>
<pre class="prettyprint">
 // Scoop up Referer and User-Agent and remote IP
def userAgent = request.getHeader("User-Agent")
def referer = request.getHeader("Referer")
def ip = request.getRemoteAddr()

// Grails adds request.forwardURI to keep the orig URI
def url = request.forwardURI 

// put in the cache, not use of applicationContext to lookup service bean
CacheService cacheService = applicationContext.getBean('cacheService')
cacheService.putToCache("referers", 60*60*24, Calendar.getInstance(),
				[ userAgent: userAgent, referer: referer, ip: ip, url: url ])
</pre>
<p>
One thing to notice in the above, service injections don&#8217;t happen in the filter chain, but you are provided with an <code>applicationContext</code> that you can use to look up your services by name.
</p>
<p>
Anyways, now I&#8217;ve got some stats, it&#8217;s time to do some crunching&#8230; Referers was the first target to add to my stats page&#8230; though the css needs some work to fit the counters  in <img src='http://blogs.bytecode.com.au/glen/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />
</p>
<p>
<img src="images/2008/gravlReferers.png" alt="Gravl referers in need of some css"/>
</p>
<p>
Now what to do with those ip addresses I was gathering? Picking up on the stuff <a href="http://www.simongbrown.com/blog/">Simon</a> is doing in the latest Pebble, I thought it might be nice to add some geocoding to that referers list so I can see which country my traffic is coming from.
</p>
<p>
Turns out there&#8217;s a very simple little Java library available from MaxMind called <a href="http://www.maxmind.com/app/geoip_country">GeoLite Countries</a>. I mavenized the source into a jar, then dropped the resources file into my /src/java/resources. I already had the ip addresses I&#8217;d gathered from headers into my cache, so to convert them to a country name, it was time to create a <code>CountryLookupService</code> to wrap all the calls to the GeoLite library:
</p>
<pre class="prettyprint">
class CountryLookupService {

    LookupService lookupService

    private LookupService getLookupService() {
        if (lookupService == null) {
            // assume you put your data file in /src/java/resources
            def url = this.class.getResource("/resources/geoIp/GeoIP.dat")
            log.debug ("Looking for GeoIP database at: $url")
            lookupService = new LookupService(new File(url.toURI()),LookupService.GEOIP_MEMORY_CACHE);
        }
        return lookupService
    }

    def getCountryName(String ipAddress) {
        log.debug "Looking up address for ${ipAddress}"
        return getLookupService().getCountry(ipAddress).getName()
    }
}
</pre>
<p>
And we&#8217;re off and running. The GeoCoding API requires you to supply a current GeoIP.dat file, and the sample above shows you how to load it from your Grails /src/java/resources folder to keep everything all relative. I&#8217;m not sure where the agreed convention is on resource placement in Grails, but there is as good as any for now&#8230; After that I just needed to iterate my cache, and we have ourselves a hashmap of countryname to hitcount:
</p>
<p>
<img src="images/2008/gravlGeocoding.png" alt="Gravl Geocoding in action"/>
</p>
<p>
Once you&#8217;ve crunched all that data, it&#8217;d be nice to produce some slick charts to make it all digestable. And what quicker way to chart it than with <a href="http://www.jameswilliams.be/blog/entry/index">James Williams</a> uber cool <a href="http://www.grails.org/Google+Chart+Plugin">Google Charts Plugin</a>.
</p>
<p>
If you haven&#8217;t used <a href="http://code.google.com/apis/chart/">Google Charts</a> before, the idea is just so good and so simple. Create an <code>img</code> tag with the <code>src</code> that points off to <code>http://chart.apis.google.com/chart?</code> then add url params to tell it your chart size, type, title, etc. and Google will render a png on the fly for you.
</p>
<p>
James plugin makes that process very simple and painless. I take my hashmap of countries (which carries countryName -> hitCount) and feed it straight into his taglib:
</p>
<pre class="prettyprint">
&lt;g:pieChart type="3d" title='Hits By Country' size="${[700,300]}"
   labels="${countries.keySet()}" dataType='simple' data='${countries.values().asList()}' /&gt;
</pre>
<p>
And the result?
</p>
<p>
<img src="http://chart.apis.google.com/chart?chs=700x300&#038;chd=s:B9BBBBCCGBCABEBBDBBFBDAABCAAABABAAA&#038;chtt=Hits%20By%20Country&#038;chl=Turkey|United%20States|United%20Arab%20Emirates|Argentina|Czech%20Republic|Greece|Austria|Korea,%20Republic%20of|France|Finland|Australia|Nigeria|Poland|Ukraine|India|Spain|Panama|Indonesia|Canada|Germany|Switzerland|United%20Kingdom|Hungary|South%20Africa|Belgium|N/A|Egypt|Guam|Philippines|China|Romania|Netherlands|Jamaica|Israel|Italy&#038;cht=p3" alt="Hits by Country"/>
</p>
<p>
So perhaps a pie chart might not be the best selection&#8230; <img src='http://blogs.bytecode.com.au/glen/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />
</p>
<p>
Wow.. that was all quite an adventure in Referers, Geocoding, and Charting! I&#8217;ll be talking about some of these adventures at <a href="http://www.groovygrails.com/gg/2gexperience">G2X</a>, so if you&#8217;re in North America next month, make sure you drop over and say hi!
</p>
<p>
Happy Grails Stats crunching!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.bytecode.com.au/glen/2008/01/17/gravl-referers-geocoding-charts.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Gravl: Implementing Security on the Cheap&#8230;</title>
		<link>http://blogs.bytecode.com.au/glen/2008/01/14/gravl-implementing-security-on-the-cheap.html</link>
		<comments>http://blogs.bytecode.com.au/glen/2008/01/14/gravl-implementing-security-on-the-cheap.html#comments</comments>
		<pubDate>Sun, 13 Jan 2008 19:21:00 +0000</pubDate>
		<dc:creator>Glen</dc:creator>
				<category><![CDATA[Gravl]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://blogs.bytecode.com.au/glens/2008/01/14/gravl-implementing-security-on-the-cheap/</guid>
		<description><![CDATA[Grails Filters open up a whole new world of opportunity for jumping into the request pipeline to do your own custom processing. I&#8217;m really excited about getting Referer tracking real soon now, since I&#8217;ve learned the basics of Filters when I implemented Gravl&#8217;s very basic security model. The Grails community is working on some first class plugins for Acegi and JSecurity, but for if your security model is coarse grain (authenticated users can do this, [...]]]></description>
			<content:encoded><![CDATA[<p>
Grails Filters open up a whole new world of opportunity for jumping into the request pipeline to do your own custom processing. I&#8217;m really excited about getting Referer tracking real soon now, since I&#8217;ve learned the basics of Filters when I implemented Gravl&#8217;s very basic security model.
</p>
<p>
The Grails community is working on some first class plugins for <a href="http://grails.codehaus.org/AcegiSecurity+Plugin">Acegi</a> and <a href="http://grails.codehaus.org/JSecurity+Plugin">JSecurity</a>, but for if your security model is coarse grain (authenticated users can do this, everyone else can&#8217;t), it&#8217;s easy enough to write a simple custom filter for the task (and a good way to learn filters to boot!).
</p>
<p>
First we&#8217;ll add a <code>SecurityFilters</code> class to the conf directory. Then we&#8217;ll get busy declaring our filter logic&#8230;
</p>
<pre class="prettyprint">
def filters = {

        loginCheck(controller: '*', action: '*') {

            before = {
                      // do our security checks here, before the controller action is invoked...
            }
      }
}
</pre>
<p>
Based on some ideas I picked up from <a href="http://graemerocher.blogspot.com/">The Bishop</a> (The Grails CMS sample includes users with certain roles can do certain things, but that was overkill for Gravl), I hold the security model in an a hashmap, where I map the controller name to a list of public actions.
</p>
<pre class="prettyprint">
def publicStuff = [
    "blog" : ["archive", "homePage", "displayOneEntry"],
    "comment" : ["newComment", "preview", "save"],
    "feed": ["feeds"],
    "pdf": ["show"],
    "image" : ["display"],
    "login" : ["form", "login"]
]
</pre>
<p>
Then it&#8217;s a matter of checking whether (1) you have an account object in your session &#8211; in which case you&#8217;re in, or (2) If you aren&#8217;t authenticated, make sure the action you&#8217;re invoking is in the public list. If you&#8217;re heading for a secured page as an unauthenticated user, I send you off to login. Filters don&#8217;t seem to have a logger injected at the moment, so excuse my printlns, but I&#8217;m sure they&#8217;ll be there soon:
</p>
<pre class="prettyprint">
if (!session.account) {
	boolean allowed = false

	println "Checking access to controller [${controllerName}] with action [${actionName}] (${request.forwardURI})"

	if (publicStuff.keySet().find { it == controllerName }) {

		if (publicStuff[controllerName].find { it == actionName }) {
			println "Access ok to public controller [${controllerName}] with action [${actionName}]"
			if (controllerName != 'login') // keep last unsecured page in session for post-login return
				session.returnurl = request.forwardURI
			allowed = true
		} else {
			println "Access privileged action: ${actionName}"
			allowed = false
		}

	} else {
		allowed = false
		println "Access privileged controller: ${controllerName}"

	}

	if (!allowed) {
		session.returnurl = request.forwardURI
		println "Setting return url to " + session.returnurl
		redirect(controller: 'login', action: 'form')
	}

	return allowed
} else {
	println "Found user in session"
	return true
}
</pre>
<p>
And you&#8217;re up and running with a basic security model! Still need to implement a basic &#8220;remember me&#8221; cookie, but the sirens of referer tracking are singing&#8230; I can feel a RefererFilters class coming on&#8230;
</p>
<p>
In the meantime, have fun with the lightweight security goodness that filters open up&#8230; Can&#8217;t wait to see the next generation of plugins that use this stuff!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.bytecode.com.au/glen/2008/01/14/gravl-implementing-security-on-the-cheap.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

