<?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>Transentia &#187; Griffon</title>
	<atom:link href="http://wordpress.transentia.com.au/wordpress/tag/griffon/feed/" rel="self" type="application/rss+xml" />
	<link>http://wordpress.transentia.com.au/wordpress</link>
	<description>transentia pty. ltd.; development, consulting, training at the leading-edge of technology</description>
	<lastBuildDate>Thu, 17 Jun 2010 10:08:36 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Another GroovyMag &#8216;Masterpiece&#8217;: Gambling on Griffon And Grails Going Gangbusters</title>
		<link>http://wordpress.transentia.com.au/wordpress/2010/05/10/another-groovymag-masterpiece-gambling-on-griffon-and-grails-going-gangbusters/</link>
		<comments>http://wordpress.transentia.com.au/wordpress/2010/05/10/another-groovymag-masterpiece-gambling-on-griffon-and-grails-going-gangbusters/#comments</comments>
		<pubDate>Mon, 10 May 2010 00:03:35 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://wordpress.transentia.com.au/wordpress/?p=926</guid>
		<description><![CDATA[Another GroovyMag article. 
Should stop the other ones from feeling lonely!
Somehow, the zip bundled with the article didn&#8217;t have the full sources&#8230;don&#8217;t know what happened. My apologies to all who tried to find them.
Never mind, here they are. 
Maybe its a case of &#8220;Better Late Than Never&#8221;? Or &#8220;All Good Things Come To Those Who [...]]]></description>
			<content:encoded><![CDATA[<p>Another <a href="http://www.groovymag.com/">GroovyMag</a> article. </p>
<p>Should stop <a href="http://wordpress.transentia.com.au/wordpress/2010/01/25/solving-the-enterprise-integration-puzzle-with-spring-integration/">the</a><a> </a><a href="http://wordpress.transentia.com.au/wordpress/2010/02/03/batch-processing-with-spring-batch/">other</a> <a href="http://wordpress.transentia.com.au/wordpress/2010/02/04/the-groovy-internet-mood-meter-in-svg/">ones</a> from feeling lonely!</p>
<p>Somehow, the zip bundled with the article didn&#8217;t have the full sources&#8230;don&#8217;t know what happened. My apologies to all who tried to find them.</p>
<p>Never mind, <a href='http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/05/Gr3.zip'>here they are</a>. </p>
<p>Maybe its a case of &#8220;Better Late Than Never&#8221;? Or &#8220;All Good Things Come To Those Who Wait&#8221;?</p>
<p>Enjoy!</p>
<hr />
<p><strong>Gr3</strong></p>
<p>Gambling on Griffon and Grails Going Gangbusters</p>
<p>Bob Brown</p>
<p>bob@transentia.com.au</p>
<p>http://www.transentia.com.au</p>
<p><em>The Grails and Griffon frameworks both strive to the same end: to bring the goodness of </em>Convention over Configuration<em> to your life. Individually, they are excellent technologies but when working together using the REST architectural pattern they can enable you to achieve great things.</em></p>
<h1>A Brief Overview</h1>
<p>They go by many names: ‘Pokies’, “one-armed bandits”, “slot machines”, “fruit machines” and even “video gaming terminals.” Some call them good clean fun and harmless entertainment; others denounce them as scourges on society, preying on those members least able to afford feeding them. Governments are addicted to the tax they generate, and big business gets bigger profits from them each year. Socially-minded campaigners regularly call for them to be banned and in an attempt to minimize their negative impact on his clientele, Russell “The (Social) Gladiator” Crowe took the unusual step of removing them from the clubhouse when he invested in his favorite Australian football team—the Sydney Rabbitohs—in 2007.</p>
<p>Given all this controversy, and also given my desire to explore the wonderful REST-ful world of Griffon and Grails, what else could I do but risk the ire of Russell and the many Rabitohs supporters and build a pokie (albeit very simple and cashless) of my very own!</p>
<p>Figure 1 shows Gr3, the “Griffon, Grails and Groovy Pokie Machine.”</p>
<p><img src="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/05/figure_1.png" alt="figure_1" title="figure_1" width="330" height="750" class="alignnone size-full wp-image-933" /><br />
<em>Figure 1: The Gr3 Client Application</em></p>
<p>As the name suggests, this is a Griffon desktop application that talks to a Grails backend application. Griffon provides a REST plugin and Grails has native support for REST, so developing REST-style interactions is especially easy.</p>
<p>The Gr3 application is simple to use: select an amount to play with and press the ‘Play’ button. If lady luck deigns to smile on you, you will win. More likely, the heartless random number generator underlying things will more than happily conspire to take your ‘money’ from you. The application displays a number of regularly-updating interesting statistics, most notably the overall totalizer value which reflects the total amount of money in the server’s ‘pot’ at any instant [1]. Each instance of Gr3 will add to and take money from this single pot as gameplay continues. There is also a simple preferences configuration GUI.</p>
<p>This application uses the “hot off the press” Grails 1.2.0-RC-1 and Griffon 0.3-SNAPSHOT versions.</p>
<h1>REST-Style Interactions</h1>
<p>REST defines a set of architectural principles for designing simple HTTP-oriented Web services. These principles are:</p>
<ul>
<li>Make proper use of the various defined HTTP methods</li>
<li>Expose all services as stateless services; assume that the client best knows how to manage its own state</li>
<li>Expose directory structure-like URIs that uniquely identify interesting or useful resources</li>
<li>Transfer data in structured form amenable to further processing using technologies such as XML, JSON (JavaScript Object Notation) or YAML (YAML Ain’t Markup Language)</li>
</ul>
<p>REST is increasingly popular and is on its way to becoming a dominant technology due to its fundamental simplicity (especially when compared to the alternative [but more comprehensive] SOAP/XML-based ecosystem).</p>
<p>Figure 2 shows the REST-style interactions that take place between the Gr3Client and Gr3Server. Although the actual sequence is quite simple, there are some guiding rules that I have adopted:</p>
<ul>
<li>The register and unRegister operations are treated akin to Create and Delete and (as prescribed by REST) use the HTTP POST and DELETE methods. They return a plain text status string.</li>
<li>The play and win operations are treated as Update and so use the HTTP PUT method. They return a JSON object containing the most-up-to-date totalizer value.</li>
<li>The totalizer operation is purely idempotent [2] and so uses HTTP GET.</li>
</ul>
<p>While these principles may not be in keeping with a purist approach to REST, they are still quite appropriate and allow me to demonstrate various aspects of REST in Griffon and Grails. In any case, the pure REST approach is more focussed on CRUD [3] update of network accessible resources than dealing with the more process-oriented service such as we have with Gr3Server.</p>
<p>This may sound rather complex but you will soon see that the support built into Grails and Griffon makes it all as easy as losing your shirt in Las Vegas. Figure 2 shows that the interaction between the Gr3Client and Gr3Server is really quite simple.</p>
<p><img src="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/05/figure_2.png" alt="figure_2" title="figure_2" width="482" height="555" class="alignnone size-full wp-image-938" /><br />
<em>Figure 2: Sequence Diagram Showing the Simple Interactions between Gr3Client and Gr3Server</em></p>
<h1>The ‘Gr3Server’ Grails WebApp</h1>
<p>This is the simpler of the two applications. It is made up of a single TotalizerController class, with a little bit of supporting code thrown in.</p>
<p>Let’s get started.</p>
<p>Listing 1 shows the TotalizerController class in its entirety [4].</p>
<pre>
package gr3

class TotalizerController {
  private static final JSON_CT = "application/json"
  private static final TEXT_CT = "text/plain"
  def totalizerService
  def clientRegistryService
  static allowedMethods =
    [startAction: 'POST', stopAction: 'DELETE',
     playAction: 'PUT', winAction: 'PUT',
     totalizerAction: 'GET']
  def beforeInterceptor = {
    def remIp = request.remoteAddr
    def registered = clientRegistryService.registered(remIp)
    if (registered &amp;&amp; (actionName == 'registerAction')) {
      log.warn "Incoming register request from registered client: $remIp"
      return false
    }
    else if ((! registered) &amp;&amp; (actionName == 'unRegisterAction')) {
      log.warn "Incoming unRegister request from unregistered client: $remIp"
      return false
    }
  }
  def registerAction = {
    def remIp = request.remoteAddr
    log.debug "Register: $remIp"
    clientRegistryService.register(remIp)
    render(text: "OK", contentType: TEXT_CT)
  }
  def unRegisterAction = {
    def remIp = request.remoteAddr
    log.debug "UnRegister: $remIp"
    clientRegistryService.unRegister(remIp)
    render(text: "OK", contentType: TEXT_CT)
  }
  def totalizerAction = {
    log.debug "totalizerAction request from ${request.remoteAddr}"
    render(contentType: JSON_CT) {
      [tote: totalizerService.getCurrentValue()]
    }
  }
  def playAction = {
    def amt = params.int('amount')
    def tote = totalizerService.accumulate(amt)
    log.debug "playAction request from ${request.remoteAddr}: ${amt}; tote now: ${tote}"
    render(contentType: JSON_CT) {
      [tote: tote]
    }
  }
  def winAction = {
    def playValue = params.int('playValue')
    def winnings = params.int('winnings')
    def tote = totalizerService.accumulate(-winnings)
    log.debug
      "winAction request from ${request.remoteAddr}: *** WIN *** played: ${playValue}, won: ${winnings}; tote now: ${tote}"
    render(contentType: JSON_CT) {
      [tote: tote]
    }
  }
}
</pre>
<p><em>Listing 1: the Main TotalizerController class</em></p>
<p>This code is quite unremarkable. There are only a few points of interest, the first of these being the allowedMethods map. This is a standard facility in Grails that makes it possible to restrict how a given action closure may be invoked. I have shown it here because it also helps make the correspondence between the code and my guiding rules for the REST interactions in this application clear.</p>
<p>A second point of interest concerns TotalizerController’s reliance on two injected services. The TotalizerService (shown in Listing 2) is basically an extremely simple wrapper for an AtomicInteger, which represents the instantaneous accumulated value of the global totalizer. The use of AtomicInteger, which is inherently thread safe, keeps the coding for the shared singleton service clean and clear and free from nasty synchronized blocks.</p>
<pre>
[…elided…]

class TotalizerService {
  boolean transactional = false
  private final tote = new AtomicInteger()
  def getCurrentValue = { tote.get() }
  def accumulate = {amt -&gt; tote.addAndGet(amt) }
}
</pre>
<p><em>Listing 2: the TotalizerService class</em></p>
<p>The third major point of interest in TotalizerController is the injected ClientRegistryService (shown in Listing 3).</p>
<pre>
[…elided…]

class ClientRegistryService implements InitializingBean {
  def authorisedIPs
  def clientRegistry
  boolean transactional = false
  def register = {ip -&gt; clientRegistry[ip] = true }
  def registered = {ip -&gt; clientRegistry[ip] == true }
  def unRegister = {ip -&gt; clientRegistry[ip] = false }
  void afterPropertiesSet() {
    def authorisedMap = [:]
    for (ip in authorisedIPs)
      authorisedMap[ip] = false
    clientRegistry = authorisedMap.asSynchronized()
  }
}
</pre>
<p><em>Listing 3: the ClientRegistryService class</em></p>
<p>ClientRegistryService is concerned with providing a simple veneer of security; it maintains a list of IP addresses and enforces the rule that only one client may be present at any given IP address. As shown in Figure 2, a client registers itself at startup and unregisters at shutdown.</p>
<p>ClientRegistryService relies on having a configured list of IP address injected into it via the authorisedIPs local variable. It will restrict access to those clients only and will also maintain the connected status of these clients. To achieve this operational rule, the service is defined to be an InitializingBean. This means that the underlying Spring Framework infrastructure will call into the defined afterPropertiesSet method after it has created the service instance and subsequently injected any needed resources into that instance. The afterPropertiesSet method examines the injected authorisedIPs list and constructs a client status map according to the list’s contents.</p>
<p>The authorisedIPs list is configured externally to the service via Grails’ conf/spring/resources.groovy file, as shown in Listing 4.</p>
<pre>
beans = {
  xmlns util: "http://www.springframework.org/schema/util"

  util.list(id: 'authorisedIPs') {
    value '127.0.0.1'
  }
}
</pre>
<p><em>Listing 4: resources.groovy, showing the Configuration of the authorisedIPs List</em> </p>
<p>Note that this is a slightly ‘artificial’ example: for ‘real’ production-quality code I could (and probably should) have easily defined and initialized the actual requisite clientRegistry map instance via resources.groovy; this path gave me a chance to introduce the useful InitializingBean facility though, so please forgive my slightly roundabout coding.</p>
<p>It is important that access to the clientRegistry be synchronized to guard against wayward concurrent update. The authorisedMap.asSynchronized() expression achieves this.</p>
<p>TotalizerController generally invokes the clientRegistryService from within its beforeInterceptor closure. This gives a single point of control for the access checks and helps keep the controller code DRY [5].</p>
<h2><em>REST-Style URL Mappings</em></h2>
<p>It is slightly “bad form” to directly expose the names of the underlying controller actions to the client application; doing so results in fragile code that potentially cannot be changed without affecting the client. Since “fearless change” is one of the basic tenets of Agile development, I have established a series of indirect mappings in conf/URLMappings.groovy. This is shown in Listing 5.</p>
<pre>
class UrlMappings {
  static mappings = {
    "/totalizer/play"(controller:"totalizer",
      action: 'playAction', parseRequest:true)
    "/totalizer/win"(controller:"totalizer",
      action: 'winAction', parseRequest:true)
    "/totalizer/register"(controller:"totalizer",
      action: 'registerAction')
    "/totalizer/unRegister"(controller:"totalizer",
      action: 'unRegisterAction')
    "/totalizer/totalizer"(controller:"totalizer",
      action: 'totalizerAction')
  […elided…]
  }
}
</pre>
<p><em>Listing 5: REST URL Mappings</em></p>
<p>Of interest here is the way that the mappings for play and win also enable Grails’ automatic JSON-parsing behavior.</p>
<h1>The ‘Gr3Client’ Griffon Desktop Application</h1>
<p>The client side portion of the pokie application is quite a lot bigger than the server-side portion that we have just examined. This is to be expected: GUI handling code is often quite involved and the client contains a fair bit more functionality.</p>
<h2><em>The Main Application MVGGroup</em></h2>
<p>Every Griffon application consists of one or more groups of Model, View and Controller (called, naturally enough, an MVCGroup). In this section we’ll take a look at the main MVG group; this is what produces the portion of the GUI shown in Figure 1.</p>
<p>The underlying model is quite straightforward, as Listing 6 (excerpted) shows.</p>
<pre>
import groovy.beans.Bindable
class Gr3ClientModel {

  […elided…]

  @Bindable String playedValue = '$0'
  @Bindable Integer plays = 0
  @Bindable Boolean playButtonEnabled = true
}
</pre>
<p><em>Listing 6: the Main MVCGroup’s Model Class</em></p>
<p>There is an @Bindable property for each value displayed in the view, as well as a property defining the state of the play button. The @Bindable annotation invokes an AST transformation [6] that wraps up the PropertyChangeSupport facility that all Swing developers have learned to know and love.</p>
<p>The application’s main view (shown in part in Listing 7) makes good use of Griffon’s ‘UberBuilder’ to allow a view to be created using features from several underlying libraries (in this case, Swing and SwingX [7])</p>
<pre>
[…elided…]

def leftReelIcons = [imageIcon('/reel/card_figures_-_club_01.png'),
        imageIcon('/reel/card_figures_-_diamond_01.png'),
        imageIcon('/reel/attenzione_rotondo_archi_01.png'),
        imageIcon('/reel/card_figures_-_heart_01.png'),
        imageIcon('/reel/card_figures_-_spade_01.png')]
def middleReelIcons = (leftReelIcons[2..-1] + leftReelIcons[0..1])
def rightReelIcons = (middleReelIcons[2..-1] + middleReelIcons[0..1])
def reelIcons = [left: leftReelIcons,
                 middle: middleReelIcons, right: rightReelIcons]
application(title: 'Gr3Client',
        size: [320, 740],
        resizable: false,
        defaultCloseOperation: WindowConstants.DO_NOTHING_ON_CLOSE,
        windowClosing: controller.exitAction,
        locationByPlatform: true,
        […elided…]) {
  menuBar(mainMenuBar)
  vbox(constraints: NORTH) {
    jxheader(title: "Gr3",
            description:
              'Pokie Machine using Griffon, Grails and Groovy.',
            icon: imageIcon('/griffon-icon-48x48.png'),
            border: emptyBorder(4),
            titleForeground: Color.RED,
            backgroundPainter: new PinstripePainter(Color.LIGHT_GRAY)
    panel() {
      tableLayout(cellpadding: 4) {
        tr {
          td(align: 'left') {
            label('Plays:')
          }
          td(align: 'right') {
            label(id: 'plays', text: bind { model.plays})
          }
          td(align: 'left') {
            label('Played:')
          }
          td(align: 'right') {
            label(id: 'played', text: bind { model.playedValue})
          }
        }
        tr {
          td(align: 'left') {
            label('Earnings:')
          }
          td(align: 'right') {
            label(id: 'earnings', text: bind { model.earnings})
          }
          td(align: 'left') {
            label('Totalizer:')
          }
          td(align: 'right') {
            label(id: 'totalizer',
                  text: bind { model.totalizerValue})
          }
        }
      }
    }
  }
  panel(new Spindle(), id: 'spindle',
        border: loweredBevelBorder(), constraints: CENTER) {
    borderLayout()
    tableLayout(cellpadding: 4) {
      tr {
        for (reel in ['left', 'middle', 'right']) {
          td(align: 'center') {
            widget(id: "${reel}Reel".toString(),
                   new Reel(icons: reelIcons[reel]))
          }
        }
      }
    }
  }
  panel(constraints: SOUTH) {
    tableLayout(cellpadding: 4) {
      tr {
        buttonGroup(id: 'playValue').with {group -&gt;
          for (v in [1, 2, 5, 10, 20, 50])
            td {
              radioButton(text: "\$$v".toString(),
                          buttonGroup: group, selected: v == 20,
                          actionCommand: "$v".toString())
            }
        }
      }
      tr {
        td(colspan: 6, align: 'center') {
          label(id: 'message', text: bind { model.message })
        }
      }
      tr {
        td(colspan: 6, align: 'center') {
          button(playAction, id: 'playButton')
        }
      }
    }
  }
}
</pre>
<p><em>Listing 7: the Main MVCGroup’s View</em></p>
<p>The clean, declarative nature of Listing 7 is a thing of beauty to my eyes! For those of us who have dreams formatted into discrete pages marked up by HTML, Groovy’s tableLayout layout manager is A Good Thing indeed.</p>
<p>Of interest is the WindowClosing event handling. To allow the client to communicate with its server at shutdown time, custom exit-handling code is established in the application stanza. To allow the custom processing to work, it is important to ensure that conf/Application.groovy is edited with:</p>
<pre>
autoShutdown = false
</pre>
<p>Note the way the ‘playValue’ Button group is defined. This adopts Josh Reed’s tip for easing the creation of groups of mutually-exclusive radiobuttons. It’s worth taking a look at Josh’s site. See “Learn More” for the URL.</p>
<p>The Panel/Spindle teamup is also worth taking a look at. The documentation for the panel widget says: <em>“A javax.swing.JPanel is returned, unless the user passes in a subclass of JPanel as the value argument, in which case the value argument is returned.”</em> The Spindle class used here uses this oft-overlooked ability and is a ‘bog-standard’ class that extends JPanel so that the red ‘win’ line is painted across the panel and on top of the ‘reels.’</p>
<p>The use of SwingX painters is discussed in “A Little Gloss: SwingX Painters”, below.</p>
<p>The main MVCGroup’s controller contains very little ‘trickery’ and all the REST-related work is offloaded to an injected ServerService class, so (in the interest of saving space) it won’t be shown here. Various sections of the controller will be examined as this article continues.</p>
<h2><em>Additional Conventional Handling</em></h2>
<p>The Gr3Client application is not only comprised of models, view and controllers; there are actions, menus and services as well. Gr3Client takes advantage of Griffon’s conventional handling for these aretefacts in addition to the standard MVC conventional handling.</p>
<p>Griffon processes actions and menus if they are contained in eponymously-named directories under griffon-app. Figure 3 shows the Gr3Client’s resulting directory tree structure.</p>
<p><img src="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/05/figure_3.png" alt="figure_3" title="figure_3" width="304" height="413" class="alignnone size-full wp-image-941" /><br />
<em>Figure 3: Additional Conventional Directories</em></p>
<p>It is also necessary to modify the entry for the MVCGroup in Application.groovy to be modified appropriately. For example:</p>
<pre>
'Gr3Client' {
  model = 'Gr3ClientModel'
  controller = 'Gr3ClientController'
  actions = 'Gr3ClientActions'
  menus = 'Gr3ClientMenus'
  view = 'Gr3ClientView'
}
</pre>
<p>Ordering is important in this definition: actions and menus are required to be processed first, since they are dependencies of the view.</p>
<p>In addition to making the code clearer, this feature also makes it slightly shorter. Consider this excerpt from actions/Gr3ClientActions.groovy:</p>
<pre>
action(id: 'playAction',
       name: 'Play',
       closure: controller.playAction,
       shortDescription: 'Play',
       enabled: bind { model.playButtonEnabled }
)
</pre>
<p>Normally, the list of actions would be required to be wrapped in an actions {} stanza. By using this facility, the actions wrapper is assumed. The same is true of any menus defined by an application.</p>
<p>Services can be placed in a services directory and are recognized and injected where needed ‘automagically.’</p>
<h2><em>Scheduling Periodic Updates</em></h2>
<p>The main view displays a global totalizer value that is continually updated. To achieve this, a ‘background’ instance of javax.swing.Timer is created during MVCGroup creation to periodically poll the Gr3Server and update the associated model value. As would be expected, the code is very simple and is excerpted in Listing 8.</p>
<pre>
import java.awt.event.ActionListener
import java.text.NumberFormat

class Gr3ClientController {

  […elided…]

  def serverService

  private static final nf = NumberFormat.getCurrencyInstance()
  def totalizerAction = {evt = null -&gt;
    doOutside {
      model.totalizerValue = nf.format(serverService.totalizerAction())
    }
  }
  void mvcGroupInit(Map args) {
    def timer = new javax.swing.Timer(1500, totalizerAction as ActionListener);
    timer.setInitialDelay(500);
    timer.start();

[…elided…]
</pre>
<p><em> Listing 8: Background Timer Handling</em></p>
<p>The totalizerAction closure is periodically executed by the timer in the context of Swing’s Event Dispatching Thread (EDT). To ensure that the GUI remains responsive, the closure performs its time-consuming communications, formatting and model update operations outside of the EDT. In a traditional Swing application, threading is quite awkward but the Groovy/Griffon SwingBuilder DSL makes life much easier.</p>
<p>Further points of interest in Listing 8 include the use of the standard Java java.text.NumberFormat facility to enable currency formatting, and Groovy’s powerful capability that enables the totalizerAction closure to be coerced to an instance of java.awt.event.ActionListener, which is what the Timer instance requires.</p>
<h2><em>The ‘PrefsPanel’ MVCGroup</em></h2>
<p>In addition to the main application MVCGroup, Gr3Client has an additional PrefsPanel MVCGroup accessible via the File-&gt;Preferences menu. This simple dialog is shown in Figure 4.</p>
<p><img src="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/05/figure_4.png" alt="figure_4" title="figure_4" width="352" height="232" class="alignnone size-full wp-image-944" /><br />
<em>Figure 4: the Preferences MVCGroup Dialog</em></p>
<p>As Listing 9 shows, the model portion of the dialog’s MVC triumvirate is straightforward; the model is simply a value and associated validity flag for each textfield.</p>
<pre>
import groovy.beans.Bindable

class PrefsPanelModel {
  @Bindable String server = PrefsUtils.getServer()
  @Bindable String port = PrefsUtils.getPort()
  @Bindable Boolean serverTfValid = true
  @Bindable Boolean portTfValid = true
}
</pre>
<p><em>Listing 9: the PrefsPanel Model class</em></p>
<p>The PrefsPanel’s view (Listing 10) is similarly simple.</p>
<pre>
panel(border: loweredBevelBorder(), constraints: CENTER) {
  tableLayout(cellpadding: 2) {
    tr {
      td { label("Server:") }
      td {
        textField(id: 'server', columns: 24,
          text: bind(source: model, 'server', mutual: true,
            validator: { controller.isNonBlank(server) }))
      }
    }
    tr {
      td { label("Port:") }
      td {
        textField(id: 'port', columns: 5,
          text: bind(source: model, 'port', mutual: true,
            validator: { controller.isInteger(port) }))
      }
    }
  }
}
</pre>
<p><em>Listing 10: an Excerpt from PrefsPanelView.groovy</em></p>
<p>Of interest here is the use of mutual binding. Mutual binding allows for view interactions to update the model (as is normal in a GUI application) and also allows the model to update the view component…a less frequently undertaken activity. Given that validation is also required, almost the complete model/view binding syntax is on display here.</p>
<p>The PrefsPanelController is mostly concerned with setting up and performing validation of the textfields. What is not related to validation is concerned with persisting the various preferences values and controlling the view’s destruction.</p>
<pre>
[…elided…]

class PrefsPanelController {
  // these will be injected by Griffon
  def model
  def view

  final gb = BorderFactory.createLineBorder(Color.GRAY)
  final rb = BorderFactory.createLineBorder(Color.RED)

  def isNonBlank = {tf -&gt;
    model.serverTfValid = (tf.text ==~ /\S+/)
  }
  def isInteger = {tf -&gt;
    try {
      def n = Integer.parseInt(tf.text)
      if ( ! (0..Short.MAX_VALUE - 1).contains(n))
        throw new IllegalArgumentException("Port out of range")
      model.portTfValid = true
      return n
    } catch (x) { /* NumberFormatExn, IllegalArgumentExn*/
      model.portTfValid = false
    }
  }
  private handleSaveButton = {-&gt;
    view.saveButton.enabled =
      model.portTfValid &amp;&amp; model.serverTfValid
  }
  void mvcGroupInit(Map args) {
    // this method is called after model and view are injected
    model.addPropertyChangeListener({evt -&gt;
      handleSaveButton()
    } as PropertyChangeListener)
    model.addPropertyChangeListener("portTfValid", {evt -&gt;
      view.port.border = model.portTfValid ? gb : rb
    } as PropertyChangeListener)
    model.addPropertyChangeListener("serverTfValid", {evt -&gt;
      view.server.border = model.serverTfValid ? gb : rb
    } as PropertyChangeListener)
  }
  def postInit() {
    view.server.text = model.server = PrefsUtils.getServer()
    view.port.text = model.port = PrefsUtils.getPort()
    model.serverTfValid =  isNonBlank(view.server)
    model.portTfValid = isInteger(view.port)
  }
  def closeWithoutSavingAction = {evt = null -&gt;
    view.preferencesFrame.visible = false;
    destroyMVCGroup('PrefsPanel')
  }
  def savePreferencesAction = {evt = null -&gt;
    PrefsUtils.setServer(model.server)
    PrefsUtils.setPort(model.port)
    closeWithoutSavingAction evt
  }
}
</pre>
<p><em>Listing 11: the PrefsPanelController class</em></p>
<h3>Validation</h3>
<p>Validation is one area where Griffon is still a rookie player. The basic framework is in place, but there are still a few ‘wrinkles’ that have yet to be worked out. The mvcGroupInit closure in Listing 11 shows how to react to changes in the model properties and how to update the view appropriately. Figure 5 shows the result of this.</p>
<p><img src="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/05/figure_51.png" alt="figure_5" title="figure_5" width="352" height="232" class="alignnone size-full wp-image-949" /><br />
<em>Figure 5: Indicating an Error</em></p>
<p>The postInit closure defined in PrefsPanelController is required to work around a small problem where the initial values for a model are not validated before being bound to the view component(s). One has to ensure that the model <em>always</em> sees one change after binding so that validation can proceed [8].</p>
<p>This still provides a useful learning opportunity. The Gr3ClientController class contains this code:</p>
<pre>
def preferencesAction = {evt = null -&gt;
  def (m, v, c) = createMVCGroup('PrefsPanel')

  c.postInit()
}
</pre>
<p>This excerpt shows the use of Groovy’s multiple assignment facility to ease the processing of the list instance returned from the createMVCGroup method.</p>
<p>Griffon’s powerhouse lead developer Andres Almiray has discussed an alternative–and probably more general—approach to this issue on the griffon-user mail list:<a href="http://archive.codehaus.org/lists/org.codehaus.griffon.user/msg/001701ca7885$a4925f40$edb71dc0$@com.au">Binding and validating seems at odds&#8230;</a>.</p>
<h3>Persisting Preferences Data</h3>
<p>Since Griffon is capable of generating a standalone application, an applet and a Java WebStart application from the same codebase, preferences handling is not as straightforward as one might think initially: where to store a configuration file in the face of different operating system filesystem conventions and security schemes? Is the JNDI available? Is the Windows Registry an option? What API is most convenient? Something ostensibly so simple is actually quite a problem for portable code [9].</p>
<p>The java.util.prefs package provides a way for applications to store and retrieve user and system preference and configuration data. The data is stored persistently in an implementation-dependent backing store but is accessed in a consistent fashion regardless of type of code or underlying system.</p>
<p>The Gr3Client application wraps the Preferences API into a simple PreferenceUtils class, as shown in Listing 12.</p>
<pre>
import java.util.prefs.Preferences

class PrefsUtils {
  private static final SERVER_KEY = 'server'
  private static final DEFAULT_SERVER = 'localhost'
  private static final PORT_KEY = 'port'
  private static final DEFAULT_PORT = '8080'
  private static final prefs = Preferences.userRoot().node('/Gr3')
  static setServer = {s -&gt;
    prefs.put(SERVER_KEY, s)
    prefs.sync()
  }
  static getServer = {
    prefs.sync()
    prefs.get(SERVER_KEY, DEFAULT_SERVER)
  }
  static setPort = {p -&gt;
    prefs.put(PORT_KEY, p)
    prefs.sync()
  }
  static getPort = {
    prefs.sync()
    prefs.get(PORT_KEY, DEFAULT_PORT)
  }
}
</pre>
<p><em>Listing 12: the PreferencesUtils class</em></p>
<p>At first sight, this code seems to contain lots of unnecessary syncs (which flush changes and refreshes the local cached data from the underlying persistent store). Strictly speaking this is indeed so, but I found that the regime I have used here was very helpful when testing: I could manually ‘munge’ the preferences store [the windows registry in my case] and see those changes happen immediately. Frequent syncing actually represents quite a trivial overhead in the grand scheme of things, so I left them in.</p>
<h2><em>Using the REST Plugin</em></h2>
<p>REST support in Griffon is provided courtesy of a plugin written by Andres Almiray. Andres’ weblog (see “Learn More”) is a “must see” site for any Griffon developer. Andres has written an equivalent plugin for Grails which makes a visit to his weblog doubly rewarding.</p>
<p>Following normal Griffon practice, the REST plugin (version 0.2 at time of writing) is installed via:</p>
<pre>
griffon install-plugin rest
</pre>
<p>I have configured the REST plugin to only work its magic on services (“out of the box” it is configured to work on controllers). This line needs to be added/edited in conf/Application.groovy:</p>
<pre>
griffon.rest.injectInto = ["service"]
</pre>
<p>I have split the network-handling code into a separate service, created via the command line:</p>
<pre>
griffon create-service ServerService
</pre>
<p>ServerService is a very simple class. Listing 13 shows just one action closure from this class but the others are essentially identical.</p>
<pre>
def playAction = {value -&gt;
  withRest(id: 'play', uri: NetworkUtils.URI) {
    def resp = put(path: 'play',
            body: [amount: value],
            requestContentType: JSON,
            responseContentType: JSON)
    assert resp.status == 200
    resp.data.tote
  }
}
</pre>
<p><em>Listing 13: Excerpted ServerService Action</em></p>
<p>The REST-related code is exceptionally clear! If you walk through the invocation sequence, you will be able to see easily how the incoming request and associated response is processed.</p>
<p>Note how automatic JSON response parsing makes for clean code: there is no need for either side to marshal/unmarshal the value for tote to/ from the textual on-the-wire representation, for example.</p>
<p>One slight subtlety is concerned with the id given to the withRest method. To quote the REST plugin’s documentation:  <em>“All dynamic methods will create a new http client when invoked unless you define an id: attribute. When this attribute is supplied the client will be stored as a property on the instance&#8217;s metaClass. You will be able to access it via regular property access or using the id: again.”</em> This gives a nice ‘tuning’ ability in that it makes it possible to reduce the number of instances that are created and almost immediately destroyed. The ServerService makes use of this facility: playAction and winAction share an id (play), totalizerAction has an unique id (and thus an unique HTTPClient instance), while registerAction and unRegisterAction do not reuse connections (on the assumption that the time between register and unRegister operations could be very long and keeping an unused connection around would be counterproductive).</p>
<h3>Configuring Logging Support</h3>
<p>Even though the syntax enabled by the REST plugin is quite simple, as I developed the application I still needed to see the request-response interaction between the Gr3Client and Gr3Server. To do this, I turned to that tried and trusted standby: Log4J. Although Griffon uses Log4J internally, it does not actually make it available to an application at runtime.</p>
<p>Configuring run-time support for Log4J is not such a “no brainer” as it is for Grails, but is still a fairly simple 3-step process:</p>
<p>Step 1: Copy the log4j jar from the Griffon distribution’s lib directory into the application’s lib directory.<br />
Step 2: Create conf/Events.groovy with the contents shown in Listing 14.</p>
<pre>
import org.apache.log4j.Logger

onNewInstance = {klass, type, instance -&gt;
  instance.metaClass.logger =
    instance.metaClass.log =
      Logger.getLogger("gr3Client.${klass.name}")
}
</pre>
<p><em>Listing 14: Events.groovy Needed for Logging</em></p>
<p>This is quite a ‘shotgun’ approach: it injects a log property into everything. A more sophisticated variation of this code (“Left as an exercise for the reader”) would be better for ‘production’ use. For the current purposes, however, it is fine.</p>
<p>Step 3: Add the code shown in Listing 15 to lifecycle/Initialize.groovy. This is mostly an ‘inline’ Log4J configuration file.</p>
<pre>
import groovy.xml.DOMBuilder

def xml = """
&lt;log4j:configuration
  xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false"&gt;
     &lt;appender
              &gt;
          &lt;param value="System.out" /&gt;
          &lt;layout&gt;
              &lt;param
                      value="%d{ISO8601} %-5p  %c{1} - %m%n" /&gt;
          &lt;/layout&gt;
     &lt;/appender&gt;
     &lt;category&gt;
          &lt;priority value="DEBUG" /&gt;
     &lt;/category&gt;
     &lt;!-- Use DEBUG to see basic request/response info;
          Use TRACE to see headers for HttpURLClient. --&gt;
     &lt;category&gt;
          &lt;priority value="TRACE" /&gt;
     &lt;/category&gt;
     &lt;category&gt;
          &lt;priority value="INFO" /&gt;
     &lt;/category&gt;
     &lt;category&gt;
          &lt;priority value="INFO" /&gt;
     &lt;/category&gt;
     &lt;category&gt;
          &lt;priority value="TRACE" /&gt;
     &lt;/category&gt;
     &lt;root&gt;
          &lt;priority value="DEBUG" /&gt;
          &lt;appender-ref ref="console" /&gt;
     &lt;/root&gt;
&lt;/log4j:configuration&gt;
"""

def reader = new StringReader(xml)
def doc = DOMBuilder.parse(reader)
new org.apache.log4j.xml.DOMConfigurator().
  configure(doc.documentElement)
</pre>
<p><em>Listing 15: Inline Log4J Configuration</em></p>
<p>The above three steps will turn on some quite extensive (and very useful!) debugging output from the REST plugin, as this excerpt (Listing 16, showing a single ‘play’ interaction) illustrates:</p>
<pre>
DEBUG RESTClient - PUT http://localhost:8080/Gr3Server/totalizer/play
DEBUG wire - &gt;&gt; "PUT /Gr3Server/totalizer/play HTTP/1.1[EOL]"
DEBUG wire - &gt;&gt; "Accept: */*[EOL]"
DEBUG wire - &gt;&gt; "Content-Length: 13[EOL]"
DEBUG wire - &gt;&gt; "Content-Type: application/json[EOL]"
DEBUG wire - &gt;&gt; "Host: localhost:8080[EOL]"
DEBUG wire - &gt;&gt; "Connection: Keep-Alive[EOL]"
DEBUG wire - &gt;&gt; "User-Agent: Apache-HttpClient/4.0 (java 1.5)[EOL]"
DEBUG wire - &gt;&gt; "Expect: 100-Continue[EOL]"
DEBUG wire - &gt;&gt; "Accept-Encoding: gzip,deflate[EOL]"
DEBUG wire - &gt;&gt; "[EOL]"
DEBUG wire - &lt;&lt; "HTTP/1.1 100 Continue[EOL]"
DEBUG wire - &lt;&lt; "[EOL]"
DEBUG wire - &gt;&gt; "{"amount":20}"
DEBUG wire - &lt;&lt; "HTTP/1.1 200 OK[EOL]"
DEBUG wire - &lt;&lt; "Server: Apache-Coyote/1.1[EOL]"
DEBUG wire - &lt;&lt; "Content-Type: application/json;charset=UTF-8[EOL]"
DEBUG wire - &lt;&lt; "Transfer-Encoding: chunked[EOL]"
DEBUG wire - &lt;&lt; "Date: Sat, 12 Dec 2009 11:34:05 GMT[EOL]"
DEBUG wire - &lt;&lt; "[EOL]"
DEBUG RESTClient - Response code: 200; found handler:
  org.codehaus.groovy.runtime.MethodClosure@a4911d
DEBUG RESTClient - Parsing response as: application/json
DEBUG wire - &lt;&lt; "b[EOL]"
DEBUG wire - &lt;&lt; "{"tote":40}"
DEBUG wire - &lt;&lt; "[\r]"
DEBUG wire - &lt;&lt; "[\n]"
DEBUG wire - &lt;&lt; "0[EOL]"
DEBUG wire - &lt;&lt; "[EOL]"
DEBUG RESTClient-Parsed data to instance of: class
  net.sf.json.JSONObject
</pre>
<p><em>Listing 16: Debugging a REST Interaction</em></p>
<p>This configuration can be easily ‘tweaked’ for any purpose, of course.</p>
<p>Don’t Panic! Recall that it is <em>still</em> quite “early days” for Griffon, and I believe that there has been some discussion aimed at eventually developing a logging plugin or addon. Forthcoming Spring framework support and the new ArtefactManager will also make the sort of configuration currently being performed in onNewInstance easier and more targeted in the future.</p>
<h2><em>A Little Gloss: SwingX Painters</em></h2>
<p>For those not already familiar with the SwingX project, here is the overview blurb from the SwingX home page:</p>
<p><em>“Contains extensions to the Swing GUI toolkit, including new and enhanced components that provide functionality commonly required by rich client applications. Highlights include: </em></p>
<ul>
<li><em>Sorting, filtering, highlighting for tables, trees, and lists</em></li>
<li><em>Find/search</em></li>
<li><em>Auto-completion</em></li>
<li><em>Login/authentication framework</em></li>
<li><em>TreeTable component</em></li>
<li><em>Collapsible panel component</em></li>
<li><em>Date picker component</em></li>
<li><em>Tip-of-the-Day component</em></li>
</ul>
<p><em>Many of these features will eventually be incorporated into the Swing toolkit.”</em></p>
<p>Griffon’s SwingX plugin packages all this goodness up and makes it easy to use alongside the normal Swing components. Don’t head down to the gaming tables without these components safely packed into your kitbag.</p>
<p>The SwingX JXHeader component supports a relatively new facility called painters. Listing 7 shows how a simple PinStripePainter can be defined and passed to the jxHeader stanza in the view builder and Figure 1 shows the results of this. Not too shabby, but not particularly breathtaking, either.</p>
<p>Listing 17 shows a more ‘beautiful’ alternative using a CompoundPainter.</p>
<pre>
def gloss = new GlossPainter(
        paint: new Color(1.0f, 1.0f, 1.0f, 0.2f),
        position: GlossPainter.GlossPosition.TOP)
def stripes = new PinstripePainter(
        paint: new Color(1.0f, 1.0f, 1.0f, 0.17f),
        spacing: 5.0)
def matte = new MattePainter(fillPaint: new Color(51, 51, 51))
def cp = new CompoundPainter(matte, stripes, gloss)
[…elided…]
jxheader(title: "Gr3",
      […elided…]
      backgroundPainter: cp)
</pre>
<p><em>Listing 17: a Compound Painter</em></p>
<p>As Figure 6 shows, this is much nicer and has a distinctly more ‘modern’ feel to it.</p>
<p><img src="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/05/figure_6.png" alt="figure_6" title="figure_6" width="330" height="242" class="alignnone size-full wp-image-950" /><br />
<em>Figure 6: the Compound Painter “In Action”</em></p>
<h2><em>Win Evaluation</em></h2>
<p>To perform win evaluation, the Gr3ClientController’s playAction closure calls the injected serverService. This is shown in Listing 18.</p>
<pre>
def playAction = {evt = null -&gt;
  doOutside {
    def lr = view.leftReel
    def mr = view.middleReel
    def rr = view.rightReel
    lr.activate()
    mr.activate()
    rr.activate()
    edt {
      view.spindle.repaint()
    }
    model.plays++
    def playedAmount =
      Integer.valueOf(view.playValue.selection.actionCommand)
    def pTote = serverService.playAction(playedAmount)
    model.totalizerValue = nf.format(pTote)
    model.playedValue =
      nf.format(playedAmount + nf.parse(model.playedValue))
    def res = evaluator.evaluate(lr, mr, rr)
    switch (res) {
      case EvaluatorResult.SMALLWIN:
      case EvaluatorResult.BIGWIN:
        model.playButtonEnabled = false
        def winnings =
          winningsService.evaluate(res.multiplier, playedAmount)
        model.earnings =
          nf.format(winnings + nf.parse(model.earnings))
        def wTote = serverService.winAction(playedAmount, winnings)
        model.totalizerValue = nf.format(wTote)
        switch (res) {
          case EvaluatorResult.SMALLWIN:
            model.message = "Congratulations! You just won: ${nf.format(winnings)}."
            SoundUtils.smallWin()
            break
          case EvaluatorResult.BIGWIN:
            model.message = "Hey BIG WINNER! You just won: ${nf.format(winnings)}."
            SoundUtils.bigWin()
            break
        }
        model.playButtonEnabled = true
        break
      default:
        model.message = CondolencesUtils.condolences()
        break
    }
  }
}
</pre>
<p><em>Listing 18: Win Evaluation</em></p>
<p>Within playAction threading issues are noteworthy, in particular the use of doOutside and edt to ensure correct and responsive view behavior.</p>
<p>Separating the evaluation into a separate service is beneficial and gives flexibility. It allows for the definition of a very simple ruleset like “A win occurs if each icon under the line is the same” or for more sophisticated rules taking into account such things as diagonal or alternate arrangements and the actual icons involved.</p>
<p>Listing 19 shows one possible (very simple) evaluator.</p>
<pre>
// simple function: a win is when all icons in the
//   middle position are the same
def evaluate = {lr, mr, rr -&gt;
  // assume that all reels have the same number of icons
  def mrm = mr.model
  int mid = mrm.size() / 2
  def le = lr.model.getElementAt(mid)
  def me = mrm.getElementAt(mid)
  def re = rr.model.getElementAt(mid)
  (le == me) &amp;&amp; (me == re) ?
    EvaluatorResult.SMALLWIN : EvaluatorResult.LOSE
}
</pre>
<p><em>Listing 19: A Very Simple Win Evaluator</em></p>
<p>It is possible to easily replace this simple code with a more sophisticated evaluator with very little knock-on effect [10].</p>
<h2><em>A Little Whimsy: JFugue</em></h2>
<p>No pokie can possibly be considered playable if it doesn’t have the capability to produce at least a few ear-splitting bells and whistles! In this case, incipient deafness comes courtesy of the excellent JFugue. In its own words:<em> “JFugue is an open-source Java API for programming music without the complexities of MIDI.”</em></p>
<p>Listing 20 shows how simple adding sound to your application can be.</p>
<pre>
import org.jfugue.Pattern
import org.jfugue.Player
class SoundUtils {
  private static final player = new Player()
  private static final smallPattern =
    new Pattern("T[Presto] I[Rock_Organ] Db4minH C5majH C5majW")
  private static final bigPattern =
    new Pattern(
      "T[Presto] I[Rock_Organ] Db4minH C5majH C5majW C5majH Db4minH")
  static smallWin = {-&gt; player.play(smallPattern) }
  static bigWin = {-&gt; player.play(bigPattern) }
}
</pre>
<p><em>Listing 20: the SoundUtils class</em></p>
<p>If you look back to Listing 18, you will see how this code is used within the playAction closure.</p>
<h1>Wrapping Up</h1>
<p>I hope that I have been able to show you that it’s not a gamble to use these technologies together. Both are powerful frameworks fully capable of permitting sophisticated development. The REST support in both makes writing distributed applications simple while the ability to incorporate existing code such as Log4J and JFugue simply cannot be beat.</p>
<p>I leave you with this quote from one of the ‘greats’ of Science Fiction, writer and social commentator Robert Heinlein: <em>“There is no such thing as ‘social gambling.’ Either you are there to cut the other bloke&#8217;s heart out and eat it—or you&#8217;re a sucker. If you don&#8217;t like this choice—don&#8217;t gamble.”</em></p>
<h1>Learn More</h1>
<ul>
<li>Grails home page, <a href="http://groovy.codehaus.org/">http://groovy.codehaus.org</a></li>
<li>Griffon home page, <a href="http://griffon.codehaus.org/">http://griffon.codehaus.org</a></li>
<li>Andres Almiray’s Weblog, <a href="http://www.jroller.com/aalmiray/">http://www.jroller.com/aalmiray/</a></li>
<li>Griffon REST Plugin page, <a href="http://griffon.codehaus.org/Rest+Plugin">http://griffon.codehaus.org/Rest+Plugin</a></li>
<li>Painter Tutorial, <a href="http://swinglabs.org/docs/frameworks/painters/index.jsp">http://swinglabs.org/docs/frameworks/painters/index.jsp</a></li>
<li>JFugue, the Java API for Music Programming, <a href="http://jfugue.org/">http://jfugue.org/</a></li>
<li>Josh Reed’s ButtonGroup shortcut, <a href="http://josh-in-antarctica.blogspot.com/2009/10/griffon-tip-silly-swingbuilder-tricks.html">http://josh-in-antarctica.blogspot.com/2009/10/griffon-tip-silly-swingbuilder-tricks.html</a></li>
</ul>
<p><em>Bob Brown is the director and owner of Transentia Pty. Ltd.. Based in beautiful Brisbane, Australia, Bob is a specialist in Enterprise Java and has found his niche identifying and applying leading-edge technologies and techniques to customers’ problems.</em></p>
<p>[1] As a youngling, I lived in Macau (the “Las Vegas of the East”) for a few years. I clearly remember the astonishment I felt when I saw the Casinos totalizer boards in action for the first time. The amount displayed updates so rapidly that the last 2-3 whole-dollar figures of the value are simply a continually-changing blur. The amount shown is strictly monotonically increasing, which added to the sense of awe I experienced.<br />
[2] An idempotent operation is one that has no side-effects and so can be repeated without changing the state of the system in any way; it is a pure read operation.<br />
[3] CRUD = Create, Retrieve, Update, Delete.<br />
[4] I will not go into the ‘mechanics’ of how to drive either Grails or Griffon here. The website for each technology (see “Learn More” for the URLs) covers those aspects very nicely.<br />
[5] Don’t Repeat Yourself; a key tenet of any developer worth their stake at the table.<br />
[6] According to Groovy’s documentation:<em> “AST Transformations provides Groovy with improved compile-time metaprogramming capabilities allowing powerful flexibility at the language level, without a runtime performance penalty.”</em> They give us compile-time code generation for boilerplate patterns, in other words.<br />
[7] SwingX support is provided by the swingx-builder plugin<br />
[8] Groovy Jira GROOVY-3939 tracks this issue, for the curious.<br />
[9] And all Java developers should aspire to write good portable code!<br />
[10] Indeed, I have a version that uses JBoss Drools but that’s probably a story for another time&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://wordpress.transentia.com.au/wordpress/2010/05/10/another-groovymag-masterpiece-gambling-on-griffon-and-grails-going-gangbusters/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GroovyMag February 2010: Another Article By Yours Truly</title>
		<link>http://wordpress.transentia.com.au/wordpress/2010/02/10/groovymag-february-2010-another-article-by-yours-truly/</link>
		<comments>http://wordpress.transentia.com.au/wordpress/2010/02/10/groovymag-february-2010-another-article-by-yours-truly/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 22:58:40 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://wordpress.transentia.com.au/wordpress/?p=776</guid>
		<description><![CDATA[Another GroovyMag USD$4.99 blockbuster.
This time taking a look at the combination of Grails, Griffon and a REST-like interaction style. It&#8217;s all Good Stuff.

Worth every cent.
]]></description>
			<content:encoded><![CDATA[<p>Another <a href="http://groovymag.com">GroovyMag</a> USD$4.99 blockbuster.</p>
<p>This time taking a look at the combination of <a href="http://www.grails.org">Grails</a>, <a href="http://griffon.codehaus.org/">Griffon</a> and a <a href="http://www.infoq.com/articles/rest-introduction">REST</a>-like interaction style. It&#8217;s all Good Stuff.</p>
<p><a href="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/02/gm16_400.jpg"><img src="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2010/02/gm16_400-231x300.jpg" alt="gm16_400" title="gm16_400" width="231" height="300" class="alignnone size-medium wp-image-777" /></a></p>
<p>Worth <em>every cent</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://wordpress.transentia.com.au/wordpress/2010/02/10/groovymag-february-2010-another-article-by-yours-truly/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cascading Lists with Groovy&#8217;s SwingBuilder</title>
		<link>http://wordpress.transentia.com.au/wordpress/2009/09/12/cascading-lists-with-groovys-swingbuilder/</link>
		<comments>http://wordpress.transentia.com.au/wordpress/2009/09/12/cascading-lists-with-groovys-swingbuilder/#comments</comments>
		<pubDate>Sat, 12 Sep 2009 02:43:27 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://wordpress.transentia.com.au/wordpress/?p=477</guid>
		<description><![CDATA[At lunch yesterday, one of my ex-colleagues was telling me that he couldn&#8217;t quite get cascading lists to work when using Groovy&#8217;s SwingBuilder.
So I knocked up an example for him:

Mum told me that it is good to share my toys, so:
import groovy.swing.*
import javax.swing.*

def swing = new SwingBuilder()

def masterData = [en: ['Hello, World!', 'How are you?'], [...]]]></description>
			<content:encoded><![CDATA[<p>At lunch yesterday, one of my ex-colleagues was telling me that he couldn&#8217;t <em>quite</em> get cascading lists to work when using Groovy&#8217;s SwingBuilder.</p>
<p>So I knocked up an example for him:</p>
<p><img class="alignnone size-full wp-image-482" title="cascade-list-swingbuilder" src="http://wordpress.transentia.com.au/wordpress/wp-content/uploads/2009/09/cascade-list-swingbuilder.PNG" alt="cascade-list-swingbuilder" width="311" height="105" /></p>
<p>Mum told me that it is good to share my toys, so:</p>
<pre>import groovy.swing.*
import javax.swing.*

def swing = new SwingBuilder()

def masterData = [en: ['Hello, World!', 'How are you?'], es: ['Hola Mundo!', "Como Esta?"], can: ['Foon Ying!', 'Lei Ho Ma?']]

def detailModel = new DefaultListModel()

swing.actions() {
  action(id: 'masterAction',
          name: 'masterAction',
          closure: {e-&gt;
            def l = e.source
            if (!e.valueIsAdjusting) {
              def i = l.selectedValue
              detailModel.clear()
              masterData[i].each {
                detailModel.addElement(it)
              }
            }
          })
}
swing.frame(title: 'My Frame', pack: true, visible: true,
                 defaultCloseOperation: javax.swing.WindowConstants.EXIT_ON_CLOSE) {
  panel() {
    tableLayout() {
      tr {
        td {
          scrollPane() {
            list(valueChanged: masterAction.closure, visibleRowCount: 3, listData: masterData.collect {k, v -&gt; k })
          }
        }
        td {
          scrollPane() {
            list(visibleRowCount: 3, model: detailModel)
          }
        }
      }
    }
  }
}</pre>
<p>It may not be optimal, but it works.</p>
<p>There&#8217;s one or two little &#8216;gotchas&#8217; here.</p>
<p>First: having to pass &#8216;masterAction.closure&#8217; directly to the first list seems wrong&#8230;elsewhere when using SwingBuilder one would just have to use &#8216;masterAction&#8217; so this feels a little &#8216;off&#8217; to me.</p>
<p>Second: the code shown works fine when run under Groovy 1.6.4 via IntelliJ Maia EAP 10666. When run directly in 1.6.4&#8217;s GroovyConsole, it gives an error:</p>
<pre>
Exception thrown: Cannot cast object '[en, es, can]' with class 'java.util.ArrayList' to class 'java.util.Vector'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[en, es, can]' with class 'java.util.ArrayList' to class 'java.util.Vector'
</pre>
<p>The workaround is to use:</p>
<pre>list(..., listData: masterData.collect {k, v -> k } as Object[])</pre>
<p>This is probably more &#8216;correct&#8217; according to the API, anyway.</p>
<p>Still, something feels &#8216;off&#8217; here&#8230;why the different behaviors?</p>
<p>These are minor niggles, however.</p>
<p>It&#8217;s still a clean and clear solution.</p>
<p>Gotta love that <a href="http://groovy.codehaus.org/api/groovy/swing/impl/TableLayout.html">TableLayout</a>, as well.</p>
<p><em>[edit]</em><br />
There <em>was</em> something a bit off, but it <a href="http://jira.codehaus.org/browse/GROOVY-3734">should be sorted by now</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://wordpress.transentia.com.au/wordpress/2009/09/12/cascading-lists-with-groovys-swingbuilder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Barcamp Brisbane III: The Search for Flock</title>
		<link>http://wordpress.transentia.com.au/wordpress/2009/07/19/barcamp-brisbane-iii-the-search-for-flock/</link>
		<comments>http://wordpress.transentia.com.au/wordpress/2009/07/19/barcamp-brisbane-iii-the-search-for-flock/#comments</comments>
		<pubDate>Sun, 19 Jul 2009 16:13:18 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://wordpress.transentia.com.au/2009/07/19/barcamp-brisbane-iii-the-search-for-flock/</guid>
		<description><![CDATA[Yesterday, I attended this event: similar to CITCON but with a wider &#8220;anything goes&#8221; feel.
My thanks to everybody who attended and especially to those who presented, I learned some Good Stuff.
Good Stuff like:

the acquia Drupal &#8216;distro&#8217; and the aegir hosting system for Drupal sites

what I am doing wrong with Git! Thanks aussiegeek!

what is good about [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday, I attended this event: similar to <a href="/wordpress/2009/06/28/brisbane-citcon-2009/">CITCON</a> but with a wider &#8220;anything goes&#8221; feel.</p>
<p>My thanks to everybody who attended and especially to those who presented, I learned some Good Stuff.</p>
<p>Good Stuff like:</p>
<ul>
<li>the <a href="http://acquia.com/">acquia</a> Drupal &#8216;distro&#8217; and the <a href="http://groups.drupal.org/aegir-hosting-system">aegir hosting system</a> for Drupal sites
</li>
<li>what I am doing wrong with Git! Thanks <a href="http://www.aussiegeek.net/">aussiegeek</a>!
</li>
<li>what is good about the <a href="http://fishshell.org/index.php">fish shell</a>
</li>
<li><a href="/wordpress/prezi.com">prezi.com</a>, &#8220;the zooming editor for stunning presentations&#8221; presented by my old (read: in times of yore, not aged) colleague <a href="http://twitter.com/mrees">@mrees</a>.
</li>
<li>an excellent discussion/forum on why Agile does <strong>not</strong> mean &#8220;no documentation.&#8221;
</li>
</ul>
<p>Most of this stuff is outside my normal sphere of influence, so this was a truly mind-opening experience :-)</p>
<p>I did a couple of informal stand-ups about <a href="/wordpress/2009/06/03/riding-the-griffon/">Griffon</a> and <a href="/wordpress/2008/10/06/slide-decks-for-the-presentations-on-groovy-and-grails/">Grails</a>. Shame that I didn&#8217;t have a projector (or rather, that I had a digital PC port and only an Analog projector cable available)&#8230;made it rather hard to show code.</p>
<p>No twitter for me, but I do have an equally <a href="http://www.merriam-webster.com/dictionary/inane">inane</a> piccy or two:</p>
<p><img src="/wordpress/wp-content/uploads/2009/07/18072009047.jpg" /> <img src="/wordpress/wp-content/uploads/2009/07/18072009048.jpg" /> </p>
<p>There&#8217;s lots more &#8217;stuff&#8217; out there, search for <a href="http://www.google.com/search?q=%23barcampbne">#barcampbne</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://wordpress.transentia.com.au/wordpress/2009/07/19/barcamp-brisbane-iii-the-search-for-flock/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Few Ribbons Around The Griffon&#039;s Tail</title>
		<link>http://wordpress.transentia.com.au/wordpress/2009/06/07/a-few-ribbons-around-the-griffons-tail/</link>
		<comments>http://wordpress.transentia.com.au/wordpress/2009/06/07/a-few-ribbons-around-the-griffons-tail/#comments</comments>
		<pubDate>Sun, 07 Jun 2009 09:48:30 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://wordpress.transentia.com.au/2009/06/07/a-few-ribbons-around-the-griffons-tail/</guid>
		<description><![CDATA[Following on from my earlier experiment with Griffon, I thought I&#8217;d have a play with a few more plugins.
First ribbon to hang around the Griffon&#8217;s tail was the CodeNarc Groovy-oriented static analysis plugin.
Installation was a little rough: the usual magic invocation:
griffon&#160;install-plugin&#160;codenarc
didn&#8217;t work. I had to download the plugins&#8217;s zip by hand and install it as:
griffon&#160;install-plugin&#160;griffon-codenarc-0.1.zip
Once [...]]]></description>
			<content:encoded><![CDATA[<p>Following on from my earlier experiment with Griffon, I thought I&#8217;d have a play with a few more plugins.</p>
<p>First ribbon to hang around the Griffon&#8217;s tail was the CodeNarc Groovy-oriented static analysis plugin.</p>
<p>Installation was a little rough: the usual magic invocation:</p>
<pre>griffon&nbsp;install-plugin&nbsp;codenarc</pre>
<p>didn&#8217;t work. I had to download the <a href="http://svn.codehaus.org/griffon/plugins/griffon-codenarc/trunk/griffon-codenarc-0.1.zip">plugins&#8217;s zip</a> by hand and install it as:</p>
<pre>griffon&nbsp;install-plugin&nbsp;griffon-codenarc-0.1.zip</pre>
<p>Once that minor hurdle was overcome, however, it was a smooth as silk!</p>
<p>Running:</p>
<pre>griffon&nbsp;codenarc</pre>
<p>produced a simple report called &#8220;CodeNarcAntReport.html&#8221; in the project&#8217;s root directory:</p>
<p><img src="/wordpress/wp-content/uploads/2009/06/griffon-gt-codenarc.png" /> </p>
<p>The code looks pretty good&#8230;a few &#8220;no-no&#8217;s&#8221; there, but otherwise things are OK.</p>
<p>Although I didn&#8217;t change any options for this little investigation, it&#8217;s worthwhile noting that the plugin is configurable through a number of entries in griffon-app/conf/Config.groovy.</p>
<p>The second ribbon to adorn my increasingly-beautiful Griffon was the splashscreen plugin.</p>
<p>This time, installation went brainlessly well:</p>
<pre>griffon&nbsp;install-plugin&nbsp;splash</pre>
<p>The plugin adds a couple of lines of code to griffon-app/lifecycle/Initialize.groovy:</p>
<pre>def&nbsp;splashScreen&nbsp;=&nbsp;SplashScreen.getInstance()

//&nbsp;Setting&nbsp;a&nbsp;splash&nbsp;image
//URL&nbsp;url&nbsp;=&nbsp;this.class.getResource("mySplash.jpg")
//splashScreen.setImage(url)
//
//&nbsp;Setting&nbsp;Status&nbsp;Text
//&nbsp;SplashScreen.getInstance().showStatus("Initializing&nbsp;the&nbsp;Controller")
splashScreen.splash()
splashScreen.waitForSplash()</pre>
<p>It&#8217;s pretty clear how this works, &#8217;nuff said?</p>
<p>It&#8217;s pretty early days for Griffon, so there isn&#8217;t (yet) an extensive list of plugins. It&#8217;s a great facility, though and I am sure that people will bring more to the table as time goes by.</p>
<p>My Griffon&#8217;s a bit more beautiful now. What bells and whistles are you going to add to yours?</p>
]]></content:encoded>
			<wfw:commentRss>http://wordpress.transentia.com.au/wordpress/2009/06/07/a-few-ribbons-around-the-griffons-tail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Little Griffon Tip</title>
		<link>http://wordpress.transentia.com.au/wordpress/2009/06/03/a-little-griffon-tip/</link>
		<comments>http://wordpress.transentia.com.au/wordpress/2009/06/03/a-little-griffon-tip/#comments</comments>
		<pubDate>Wed, 03 Jun 2009 20:41:35 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://wordpress.transentia.com.au/2009/06/03/a-little-griffon-tip/</guid>
		<description><![CDATA[I just want to ensure that I remember this tip. How better to do it than to post it here&#8230;

import&#160;java.awt.Graphics
import&#160;groovy.swing.SwingBuilder
import&#160;javax.swing.JPanel
import&#160;java.awt.Color

class&#160;CanvasPanel&#160;extends&#160;JPanel&#160;{
&#160;&#160;&#160;Closure&#160;draw

&#160;&#160;&#160;@Override
&#160;&#160;&#160;protected&#160;void&#160;paintComponent(Graphics&#160;g)&#160;{
&#160;&#160;&#160;&#160;&#160;&#160;super.paintComponent(g)
&#160;&#160;&#160;&#160;&#160;&#160;if(draw)&#160;draw(this,g)
&#160;&#160;&#160;}
}

Usage is as simple as:

new&#160;SwingBuilder().edt&#160;{
&#160;&#160;frame(&#160;title:&#160;"RED",&#160;size:&#160;[200,200],&#160;visible:&#160;true&#160;)&#160;{
&#160;&#160;&#160;&#160;panel(&#160;new&#160;CanvasPanel(draw:&#160;{&#160;p,&#160;g&#160;-&#62;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;g.color&#160;=&#160;Color.RED
&#160;&#160;&#160;&#160;&#160;&#160;&#160;g.fillRect&#160;0,&#160;0,&#160;p.width,&#160;p.height
&#160;&#160;&#160;&#160;}))
&#160;&#160;}

Here&#8217;s the result:
 
I know it is extremely simple, but it&#8217;s the sort of thing that can be very useful and is also just the sort of thing that slips one&#8217;s mind!
Thanks [...]]]></description>
			<content:encoded><![CDATA[<p>I just want to ensure that I remember <a href="http://markmail.org/message/x3zkvnqh444b2ug7">this tip</a>. How better to do it than to post it here&#8230;</p>
<pre>
import&nbsp;java.awt.Graphics
import&nbsp;groovy.swing.SwingBuilder
import&nbsp;javax.swing.JPanel
import&nbsp;java.awt.Color

class&nbsp;CanvasPanel&nbsp;extends&nbsp;JPanel&nbsp;{
&nbsp;&nbsp;&nbsp;Closure&nbsp;draw

&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;paintComponent(Graphics&nbsp;g)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.paintComponent(g)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(draw)&nbsp;draw(this,g)
&nbsp;&nbsp;&nbsp;}
}
</pre>
<p>Usage is as simple as:</p>
<pre>
new&nbsp;SwingBuilder().edt&nbsp;{
&nbsp;&nbsp;frame(&nbsp;title:&nbsp;"RED",&nbsp;size:&nbsp;[200,200],&nbsp;visible:&nbsp;true&nbsp;)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;panel(&nbsp;new&nbsp;CanvasPanel(draw:&nbsp;{&nbsp;p,&nbsp;g&nbsp;-&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.color&nbsp;=&nbsp;Color.RED
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.fillRect&nbsp;0,&nbsp;0,&nbsp;p.width,&nbsp;p.height
&nbsp;&nbsp;&nbsp;&nbsp;}))
&nbsp;&nbsp;}
</pre>
<p>Here&#8217;s the result:</p>
<p><img src="/wordpress/wp-content/uploads/2009/06/griffon-red.jpg" /> </p>
<p>I know it is <em>extremely simple</em>, but it&#8217;s the sort of thing that can be very useful and is also just the sort of thing that slips one&#8217;s mind!</p>
<p>Thanks to <a href="http://www.jroller.com/aalmiray/">Andres Almiray</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://wordpress.transentia.com.au/wordpress/2009/06/03/a-little-griffon-tip/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Riding The Griffon</title>
		<link>http://wordpress.transentia.com.au/wordpress/2009/06/03/riding-the-griffon/</link>
		<comments>http://wordpress.transentia.com.au/wordpress/2009/06/03/riding-the-griffon/#comments</comments>
		<pubDate>Wed, 03 Jun 2009 11:13:07 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://wordpress.transentia.com.au/2009/06/03/riding-the-griffon/</guid>
		<description><![CDATA[Here&#8217;s a first for this website: a real, (hopefully) useful desktop application for you to take home and play with!
Here it is, all zipped up and ready to go. See the enclosed README.txt for wise words regarding how to use it.
I had the brilliant idea of using my MFC device (an HP OfficeJet 7410) to [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a first for this website: a real, (hopefully) useful desktop application for you to take home and play with!</p>
<p><a href="/wordpress/wp-content/uploads/2009/06/gt.zip">Here it is, all zipped up and ready to go</a>. See the enclosed README.txt for wise words regarding how to use it.</p>
<p>I had the brilliant idea of using my MFC device (an <a href="http://h20271.www2.hp.com/SMB-AP/cache/269982-0-0-190-121.html?jumpid=reg_R1002_SGEN&#038;pos=1">HP OfficeJet 7410</a>) to scan multiple happy snaps in one go. While this idea would undoubtedly save me scanning time, it leaves the problem of how to extract these multiple images from a single scan, such as the one shown here:</p>
<p><img src="/wordpress/wp-content/uploads/2009/06/griffon-gt-app.jpg" width="480" height="292" /> </p>
<p>You can see the major problem with this idea: the various &#8216;real&#8217; images will be placed on the scanner bed haphazardly and so will be rotated at odd angles. Processing with a &#8216;normal&#8217; application (such as the excellent <a href="http://www.getpaint.net">Paint.NET</a>) would require too much grunt work for my taste, quickly leading to boredom and possible RSI.</p>
<p>I couldn’t find anything out there in the GoogleVerse that did what I wanted so I took this as a challenge and did what any self-respecting programming nerd would do: wrote my own application. &#8216;GT&#8217;  lets me select the boundary of an embedded image within a scan file, and then extract and automatically rotate the desired image ready for saving as a PNG file.</p>
<p>Since I am quickly becoming a GR8 (Groovy/Grails/Griffon/Gant/&#8230;) tragic, Griffon was the natural choice for this little project.</p>
<p>Although it is early days yet for the project, Griffon aims to bring the same &#8220;Configuration by Convention&#8221; goodness to desktop GUI development that Grails has brought to Web development. In fact, Griffon &#8216;borrows&#8217; heavily from Grails: many of the build scripts, etc. are straight carry-overs, meaning that anybody familiar with Grails can get started easily.</p>
<p>This is all that is needed to get started: </p>
<pre>
griffon&nbsp;create-app&nbsp;GT
cd&nbsp;GT
griffon&nbsp;run-app
</pre>
<p>These three shell commands give a simple immediately runnable application:</p>
<p><img src="/wordpress/wp-content/uploads/2009/06/groffon-gt-first.png" /> </p>
<p>As with Grails, Griffon imposes a clear MVC structure for the code and also creates a standrd project filesystem heirarchy:</p>
<p><img src="/wordpress/wp-content/uploads/2009/06/griffon-gt-filesystem.png" /> </p>
<p>Simplicity is the watchword, as can be seen by looking at the code statistics for the finished application:</p>
<p><img src="/wordpress/wp-content/uploads/2009/06/griffon-gt-stats.png" /> </p>
<p>Note that the bulk of the application lies in the 3rd party Java graphics-processing code and this is what inflates the lines of code statistics.</p>
<p>While I’m here, a big “thank you” is due to <a href="http://forums.sun.com/profile.jspa?userID=550123">prometheuzz</a> for making the code for the “Rotating Calipers” algorithm <a href="http://www.iruimte.nl/calipers/RotatingCalipers.zip">available</a> (see the Java package bk.geom.rotatingcalipers). This algorithm is used to find the bounding box of a polygon, regardless of whether that polygon is absolutely aligned with the XY axes or not. There is a good demonstration applet of this at <a href="http://www.iruimte.nl/calipers/">http://www.iruimte.nl/calipers/</a>.</p>
<p>Enough background. Time to take a short ramble through (the most important parts of) the MVC triad&#8230;</p>
<p><strong>models/GTModel.groovy</strong></p>
<pre>
import&nbsp;groovy.beans.Bindable
import&nbsp;javax.swing.ImageIcon

class&nbsp;GTModel&nbsp;{
&nbsp;&nbsp;[...elided...]
&nbsp;&nbsp;@Bindable&nbsp;boolean&nbsp;saveAsEnabled&nbsp;=&nbsp;false
&nbsp;&nbsp;@Bindable&nbsp;String&nbsp;file
&nbsp;&nbsp;@Bindable&nbsp;ImageIcon&nbsp;image
&nbsp;&nbsp;@Bindable&nbsp;ImageIcon&nbsp;destinationImage
&nbsp;&nbsp;@Bindable&nbsp;String&nbsp;labelText&nbsp;=&nbsp;'Welcome!'
}
</pre>
<p>In a typical Swing application, bits of model typically get spread through various components. By bringing everything together, Griffon makes it much easier to understand what&#8217;s what.</p>
<p>This excerpt also shows one of the nicest things about Griffon: the @Bindable annotation, which encapsulates the observerable/observer pattern. We&#8217;ll come back to this in a while.</p>
<p><strong>views/GTView.groovy</strong></p>
<p>Simple! A thing of beauty&#8230;</p>
<pre>
import&nbsp;static&nbsp;java.awt.BorderLayout.*
import&nbsp;javax.swing.JSplitPane
import&nbsp;java.awt.Color

build(GTActions)

application(title:&nbsp;'GT',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pack:&nbsp;true,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;locationByPlatform:&nbsp;true,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iconImage:&nbsp;imageIcon('/griffon-icon-48x48.png').image,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iconImages:&nbsp;[imageIcon('/griffon-icon-48x48.png').image,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imageIcon('/griffon-icon-32x32.png').image,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imageIcon('/griffon-icon-16x16.png').image]
)&nbsp;{

&nbsp;&nbsp;menuBar(build(GTMenuBar))

&nbsp;&nbsp;panel(border:&nbsp;emptyBorder(6))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;borderLayout()
&nbsp;&nbsp;&nbsp;&nbsp;splitPane(id:&nbsp;"splitter",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preferredSize:&nbsp;[1024,&nbsp;768],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dividerLocation:&nbsp;512,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;orientation:&nbsp;JSplitPane.HORIZONTAL_SPLIT,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;constraints:&nbsp;CENTER,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;border:&nbsp;lineBorder(color:&nbsp;Color.BLACK,&nbsp;thickness:&nbsp;1))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;panel(id:&nbsp;'sourceImagePanel')&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;borderLayout()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;build(GTSourceImagePanel)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;panel(id:&nbsp;'destinationImagePanel')&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;borderLayout()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;build(GTDestinationImagePanel)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;label(id:&nbsp;'status',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;constraints:&nbsp;SOUTH,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;border:&nbsp;emptyBorder(4),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;text:&nbsp;bind&nbsp;{&nbsp;model.labelText&nbsp;})
&nbsp;&nbsp;}
}
</pre>
<p>For those familiar with plain Java Swing, this should be a complete breath of fresh air.</p>
<p>Very little glue code is required here; the Swing containment hierarchy is clear and the layout policies are easy to see.</p>
<p>Some may be happy to see that there are no anonymous inner classes in use: Groovy&#8217;s closures allow for much a cleaner implementation. <em>I&#8217;ve been teaching Java since about 1998 and I have observed that course participants often have trouble &#8216;trusting&#8217; anonymous inner classes. Even though they are custom-designed for the sort of glue code required to join a button and its action together, I have observed that many participants&#8217; first instinct is to avoid them. It hasn&#8217;t helped that many IDEs haven&#8217;t worked well with them, either. Hopefully, closures will be more easily comprehended and thus better accepted.</em></p>
<p>The &#8217;status&#8217; label shows how the model.labelText is &#8216;automagically&#8217; bound to the &#8216;text&#8217; property in the label component. Any changes to model.labelText (as will be seen in the controller code, later) will be reflected in the label&#8217;s text value. Once again, this substantially helps to cleans up the code.</p>
<p>Griffon allows complex code to be broken into sub-scripts that are then included via the build() method. This technique is used to isolate action definitions and menu definitions and also to &#8220;break down&#8221; the various panel content GUIs into separate files for ease of comprehension.</p>
<p>Griffon allows Swing-style action definitions to be streamlined, as shown in this excerpt from <strong>views/GTActions.groovy</strong>:</p>
<pre>
actions&nbsp;{
&nbsp;&nbsp;action(id:&nbsp;'saveAsAction',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;'Save&nbsp;As...',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mnemonic:&nbsp;'S',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;smallIcon:&nbsp;builder.imageIcon("/disk.png"),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accelerator:&nbsp;shortcut('S'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enabled:&nbsp;bind&nbsp;{&nbsp;model.saveAsEnabled&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;closure:&nbsp;controller.saveAsActionClosure
&nbsp;&nbsp;)
&nbsp;&nbsp;action(id:&nbsp;'mirrorYAction',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;'Mirror&nbsp;on&nbsp;Y&nbsp;Axis',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;smallIcon:&nbsp;builder.imageIcon('/shape_flip_vertical.png'),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enabled:&nbsp;bind&nbsp;{&nbsp;model.saveAsEnabled&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;closure:&nbsp;controller.mirrorYActionClosure
&nbsp;&nbsp;)
[...elided...]
}
</pre>
<p>It is easy to see the Griffon &#8216;goodness&#8217; here: the use of closures, the use of bindings, the use of the GUI builder facilies (to obtain an appropriate icon resource), and shortcut handling. Taken together, this gives a clean, declarative style that I find very valuable.</p>
<p>(By the way, for plain Swing, the <a href="https://sam.dev.java.net/">Swing Action Manager</a> provides somewhat similar capabilities&#8230;).</p>
<p>The use of the actions can be seen in this excerpt from <strong>views/GTMenuBar.groovy</strong>:</p>
<pre>
import&nbsp;static&nbsp;griffon.util.GriffonApplicationUtils.*

menuBar&nbsp;=&nbsp;menuBar&nbsp;{
&nbsp;&nbsp;if&nbsp;(!isMacOSX)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;menu(text:&nbsp;'File',&nbsp;mnemonic:&nbsp;'F')&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;menuItem(exitAction)
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}
&nbsp;&nbsp;menu(text:&nbsp;'Source',&nbsp;mnemonic:&nbsp;'S')&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;menuItem(openAction)
&nbsp;&nbsp;&nbsp;&nbsp;separator()
&nbsp;&nbsp;&nbsp;&nbsp;menuItem(extractAction)
&nbsp;&nbsp;&nbsp;&nbsp;menuItem(clearAction)
&nbsp;&nbsp;}
[...elided...]
}

return&nbsp;menuBar
</pre>
<p>It is also interesting to see that Griffon makes it easy to keep the various platform-specific foibles in mind.</p>
<p>To round off this tour through the view&#8217;s code, here is the <strong>views/GTDestinationImagePanel.groovy</strong> file:</p>
<pre>
import&nbsp;static&nbsp;java.awt.BorderLayout.*
import&nbsp;javax.swing.JLabel
import&nbsp;java.awt.Color
import&nbsp;org.jdesktop.swingx.painter.PinstripePainter

jxheader(title:&nbsp;"Destination",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description:&nbsp;'Display&nbsp;and&nbsp;manipulate&nbsp;the&nbsp;isolated&nbsp;portion&nbsp;of&nbsp;the&nbsp;source&nbsp;image.',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;border:&nbsp;emptyBorder(4),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;constraints:&nbsp;NORTH)
scrollPane(id:&nbsp;'scrollPane',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;constraints:&nbsp;CENTER)&nbsp;{
&nbsp;&nbsp;jxlabel(id:&nbsp;'destination',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;icon:&nbsp;bind&nbsp;{&nbsp;model.destinationImage&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;constraints:&nbsp;CENTER,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;horizontalAlignment:&nbsp;JLabel.CENTER_ALIGNMENT,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;border:&nbsp;loweredBevelBorder(),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;backgroundPainter:&nbsp;new&nbsp;PinstripePainter(Color.LIGHT_GRAY))
}
hbox(constraints:&nbsp;SOUTH,&nbsp;border:&nbsp;emptyBorder(4))&nbsp;{
&nbsp;&nbsp;button(rotate90LeftAction,&nbsp;text:&nbsp;'')
&nbsp;&nbsp;hstrut(8)
&nbsp;&nbsp;button(rotate90RightAction,&nbsp;text:&nbsp;'')
&nbsp;&nbsp;hstrut(8)
&nbsp;&nbsp;button(mirrorXAction,&nbsp;text:&nbsp;'')
&nbsp;&nbsp;hstrut(8)
&nbsp;&nbsp;button(mirrorYAction,&nbsp;text:&nbsp;'')
&nbsp;&nbsp;hglue()
&nbsp;&nbsp;button(saveAsAction)
}
</pre>
<p>The most interesting aspect of this code is the way that the facilities made available by the use of the SwingXBuilder Plugin (jxheader, jxlabel and the PinstripePainter background painter) are seamlessly incorporated into the view.</p>
<p>This is really quite pretty code; it would be beautiful but for the various import statements. I&#8217;d like Griffon (or perhaps Groovy itself: there&#8217;s <a href="http://docs.codehaus.org/display/GroovyJSR/Groovy+DevCon+5">something similar afoot</a> with respect to <a href="http://groovy.codehaus.org/Grape">Grape</a>, but this isn&#8217;t quite the same thing&#8230;) to do something about them&#8230;they seem somehow &#8216;ugly&#8217; and don&#8217;t really add much to things.</p>
<p><strong>controllers/GTController.groovy</strong></p>
<p>This is the third major part of the MVC triumvirate.</p>
<p>Here&#8217;s a fairly cut-down overview of the controller:</p>
<pre>
class&nbsp;GTController&nbsp;{

&nbsp;&nbsp;def&nbsp;model
&nbsp;&nbsp;def&nbsp;view
&nbsp;&nbsp;def&nbsp;builder

&nbsp;&nbsp;def&nbsp;saveAsActionClosure&nbsp;=&nbsp;{evt&nbsp;=&nbsp;null&nbsp;-&gt;
&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;file&nbsp;=&nbsp;selectFileForSave()
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!file)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return
&nbsp;&nbsp;&nbsp;&nbsp;ImageIO.write(view.destination.icon.image,&nbsp;"png",&nbsp;file)
&nbsp;&nbsp;&nbsp;&nbsp;model.labelText&nbsp;=&nbsp;"Saved&nbsp;as&nbsp;$file.name..."
&nbsp;&nbsp;}

&nbsp;&nbsp;def&nbsp;mirrorYActionClosure&nbsp;=&nbsp;{evt&nbsp;=&nbsp;null&nbsp;-&gt;
&nbsp;&nbsp;&nbsp;&nbsp;doOutside&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;img&nbsp;=&nbsp;toBufferedImage(model.destinationImage.image)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AffineTransform&nbsp;transform&nbsp;=&nbsp;AffineTransform.getScaleInstance(1,&nbsp;-1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transform.translate(0,&nbsp;-img.height)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AffineTransformOp&nbsp;op&nbsp;=&nbsp;new&nbsp;AffineTransformOp(transform,&nbsp;AffineTransformOp.TYPE_BILINEAR)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img&nbsp;=&nbsp;op.filter(img,&nbsp;null)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edt&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;model.destinationImage&nbsp;=&nbsp;new&nbsp;ImageIcon(img)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}

&nbsp;&nbsp;def&nbsp;exit&nbsp;=&nbsp;{evt&nbsp;=&nbsp;null&nbsp;-&gt;
&nbsp;&nbsp;&nbsp;&nbsp;app.shutdown()
&nbsp;&nbsp;}

[...elided...]
}
</pre>
<p>Things worthy of notice here include: the injection of the builder, model and view components (note that views get the builder implicitly), the action closures (that are referenced from the actions shown earlier) and the &#8216;exit&#8217; closure that directly references the implictly available &#8216;app&#8217; instance.</p>
<p>It is also worth noting the assignment to the bound property &#8216;model.labelText.&#8217;</p>
<p>Of particular note is the way that Griffon eases the burden of managing threading. Swing threading is (sadly!) probably the most misunderstood and mis-applied aspect of the whole of Java. Unfortunately, it is also the area that has the most effect on making an application &#8216;feel&#8217; good. Bob&#8217;s rule for Swing GUIs is: &#8220;GUI updates have to be on the Event Dispatch Thread (EDT), but you must never do any long-running non-GUI-related task on the EDT.&#8221; Each action is executed on the EDT, in true Swing fashion. Griffon makes it easy to follow Bob’s rule by providing the doOutside method that allows the single Swing GUI thread to remain &#8216;live&#8217; while the actual work is done in another (background) thread. Griffon also supplies the edt method for when things (like GUI updates) simply have to be done on the EDT, and doLater which allows Swing to decide when it is free enough to handle a long-running GUI-updating activity.</p>
<p>There&#8217;s more on Griffon and threading <a href="http://www.jroller.com/aalmiray/entry/revisiting_the_hidden_threading_rule">here</a>.</p>
<p><strong>Other</strong><br />
There’s a lot more Good Stuff that Griffon gives you. For example, the Griffon <a href="http://groovy.codehaus.org/Griffon+Quick+Start">Quick Start</a> says:</p>
<blockquote><p>The run-app script implies the execution of the package script. The package script creates file artifacts suitable for a Java application, a WebStart application, and an Applet, with code signed by a self-signed certificate</p>
</blockquote>
<p>That’s a significant piece of added value just there!</p>
<p>Griffon’s plugins scheme is also a Real Good Idea and there are an ever-growing number of plugins to be had, from the SwingXBuilder plugin that I have used here, through to things like a standard &#8220;splash screen&#8221; facility and various testing/code coverage tools.</p>
<p>Don’t forget the i18n support and standardized resource handling!</p>
<p>And don&#8217;t forget testing&#8230;although I haven&#8217;t actually used it in for this application (bad boy, Bob!), Griffon generates placeholders for integration/unit testing.</p>
<p>Griffon also creates an ant script (not <a href="http://gant.codehaus.org">Gant</a>, shame!) for the project.</p>
<p>I may end up eating my words in future (wouldn’t be the first time!) as Flash/Flex and Silverlight fade into obscurity, but I feel fairly safe saying that IMHO, Griffon beats the ill-conceived (and probably ill-fated) <a href="http://javafx.com/">JavaFX</a> technology hands-down. Even though JavaFX is technologically quite good, I’m not betting my house on it. In any case, the use of one doesn’t preclude the use of the other, as <a href="http://www.jroller.com/aalmiray/entry/some_javafx_java_groovy_examples">this posting</a> (to take but one simple example) shows.</p>
<p>Despite all protestations to the contrary, the <a href="http://jcp.org/en/jsr/detail?id=296">JSR 269</a> Swing <a href="https://appframework.dev.java.net/">AppFramework</a> work seems stillborn.</p>
<p>Griffon seems to me to have a much rosier future ahead of it than either JavaFX or AppFramework. If you haven’t already done so, ride the Griffon, you won’t be sorry!</p>
]]></content:encoded>
			<wfw:commentRss>http://wordpress.transentia.com.au/wordpress/2009/06/03/riding-the-griffon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The State Of The Groovy World</title>
		<link>http://wordpress.transentia.com.au/wordpress/2009/04/25/the-state-of-the-groovy-world/</link>
		<comments>http://wordpress.transentia.com.au/wordpress/2009/04/25/the-state-of-the-groovy-world/#comments</comments>
		<pubDate>Sat, 25 Apr 2009 21:29:30 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://wordpress.transentia.com.au/2009/04/25/the-state-of-the-groovy-world/</guid>
		<description><![CDATA[An overview, at least. By Scott Davis:  http://groovy.markma &#8230; age/7lsabbh2eldga4dm&#8230;
I&#8217;ll excerp the main bits:
Manning has Groovy in Action (and soon Grails in Action as well). Apress has quite a impressive cadre of titles, from DGG to Beginning Groovy and Grails, GORM, Grails + Flex, and more. The Prags have Venkat and I (Programming Groovy [...]]]></description>
			<content:encoded><![CDATA[<p>An overview, at least. By <a href="http://thirstyhead.com">Scott Davis</a>:  <a href="http://groovy.markmail.org/message/7lsabbh2eldga4dm">http://groovy.markma &hellip; age/7lsabbh2eldga4dm</a>&#8230;</p>
<p>I&#8217;ll excerp the main bits:</p>
<blockquote><p>Manning has Groovy in Action (and soon Grails in Action as well). Apress has quite a impressive cadre of titles, from DGG to Beginning Groovy and Grails, GORM, Grails + Flex, and more. The Prags have Venkat and I (Programming Groovy and Groovy Recipes, respectively), plus Dave Klein&#8217;s upcoming Grails title. Morgan Kaufmann has the tragically underrated Groovy Programming.</p>
<p>In terms of online articles, I&#8217;ve been writing <a href="http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=mastering+grails">Mastering Grails</a> for IBM developerWorks for a year and a half now.</p>
<p>I&#8217;ve rebooted Andy Glover&#8217;s old <a href="http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=practically+groovy">Practically Groovy series</a>. (BTW, I went back and rewrote every Groovy example dating back to 2004 so that they run under modern Groovy &#8212; not as hard a task as you might imagine&#8230;) That&#8217;s effectively 50-ish new pages of new material each month. (And boy are my arms tired&#8230; wink) Those articles are regularly among the most popular at IBM devWorks, FWIW. There&#8217;s also the monthly GroovyMag, JavaWorld, <a href="http://groovy.dzone.com/">http://groovy.dzone.com/</a>, SCADS of personal blogs, the Groovy/Grails podcast from Glen and Sven, and more&#8230;</p>
<p>I speak 30+ weekends a year on the NFJS tour talking about Groovy and  Grails. That&#8217;s in addition to JavaOne, TSSJS, QCON, JavaZone, and a  host of others. When I&#8217;m not speaking publicly, I&#8217;m offering private  Groovy/Grails training/mentoring/consulting through <a href="http://thirstyhead.com ">http://thirstyhead.com </a>. There are many other folks, like Ken Kousen, smokejumper,  SpringSource (natch), who do the same.</p>
<p>Andy Glover&#8217;s BDD framework <a href="http://easyb.org">easyb</a> &#8212; written in  Groovy &#8212; just won a Jolt award. Both Groovy and Grails have won JAX  awards. There&#8217;s Griffon, Gant, Gradle, GMock and many other libraries/ frameworks that leverage the power of Groovy and Grails under the  covers.</p>
<p>Companies from Wired to LinkedIn to IBM to SAP to SkyTV to Tropicana to Pepsi to Mutual of Omaha to the (US) National Cancer Institute to many many others without a public-facing website or case study have adopted Groovy and Grails.</p>
<p>The Groovy/Grails community has an embarrassment of riches to choose from. (Apologies if I missed an obvious addition to any of the informal lists I rattled off of the top of my head.) This mailing list alone should be an indication of how vibrant the community is.
</p>
</blockquote>
<p>A nice <a href="http://groovy.markmail.org/message/2jay5rwuweukgdzb">follow-up quote</a> from Dierk König:</p>
<blockquote><p>Unlike other languages, Groovy positions itself as &#8220;Java&#8217;s dynamic friend&#8221; rather than trying to be a replacement.</p>
</blockquote>
<p>And <a href="http://groovy.markmail.org/message/ieq5wd45whrmazkp">a bit more</a> from Russel Winder:</p>
<blockquote><p>&#8220;Groovy, the symbiotic partner to Java on the JVM&#8221;.  The words &#8220;partner&#8221; and &#8220;symbiotic&#8221; are crucial here!</p>
<p>&#8230;</p>
<p>Where you need static type checking and fastest execution performance use Java, as soon as you need any form of reflection or dynamism consider switching that bit of your system to Groovy. <em>This is multi-language programming in a total system context</em>.</p>
</blockquote>
<p>(My italics)</p>
<p>Time for <em>you</em>, dear reader, to jump on the Groovy bandwagon. Don&#8217;t be afraid, the horses won&#8217;t bite!</p>
]]></content:encoded>
			<wfw:commentRss>http://wordpress.transentia.com.au/wordpress/2009/04/25/the-state-of-the-groovy-world/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
