Adding shutdown hooks to a desktop Griffon application

Technical pride prompted me to write my first Griffon application Tuesday. Griffon is a Groovy-based framework to write Java desktop applications. Groovy takes some of the sting out of writing Java Swing applications and Griffon relieves more of the burden. My pride came into the picture when Manning Publications released its daily Pop Quiz yesterday asking what technique one would use to process the shutdown of a Griffon application running on OS X. Manning posts a new question each day of September, and as of today, I'm running a perfect score. I couldn't let a little question about Griffon stop me. However, since Griffon is so new (its stable release is 0.1.2) and developers are only now starting to play with it, googling around for a simple answer didn't turn up much.

After failing to find sample Griffon code that described the application shutdown process (especially with the question's wrinkle of using OS X), I figured I'd write a simple Griffon desktop application and give the technology a spin. In the category of famous last words, "How hard could it be?" Turns out, thankfully, not that hard.

After downloading the Griffon 0.2-BETA zip file, setting my GRIFFON_HOME environment variable to point to the folder where I unzipped the files, and adding the $GRIFFON_HOME/bin directory to my PATH for convenience, I was ready to create my first Griffon application. I followed the instructions on the Griffon Quick Start page and ran the command:
griffon create-app
and typed in my project name (quiz) to create all the files needed for a basic application. The create-app command generates the application scaffolding along the lines of other modern frameworks like Rails, Grails, App Fuse and even Maven.

Once the create-app command created the skeletal the application files, I followed the sample code on the Griffon Quick Start page to augment the files with code to create a simple desktop application. The application provides a window that lets you type in and execute code in the Groovy shell. Griffon structures its files around the Model-View-Controller pattern, creating subdirectories for "models", "views" and "controllers". Here are the directories in the project's "griffon-app" folder:
$ ls griffon-app
conf/  controllers/  i18n/  lifecycle/  models/  resources/  views/
Figure 1 shows the resulting application in action, which you can build and run using the command griffon run-app. I typed the two Groovy statements into the window and clicked the Execute button.
Griffon sample application screen
Figure 1: Griffon Quick Start application window
One of my first tweaks to the sample application code was to put in place what I learned during my googling around for an answer. I followed the advice of Josh Reed, one of Griffon's six committers. Josh, who uses Griffon in his day job, wrote a blog post this month about how to intercept window closing events that proved quite helpful. I edited the file griffon-app/views/QuizView.groovy to define application properties for defaultCloseOperation and windowClosing so the top of my QuizView.groovy now looked like this:
QuizView.groovy:
import javax.swing.WindowConstants
application(
title:'quiz',
pack:true,
locationByPlatform:true,
iconImage: imageIcon('/griffon-icon-48x48.png').image,
iconImages: [imageIcon('/griffon-icon-48x48.png').image,
imageIcon('/griffon-icon-32x32.png').image,
imageIcon('/griffon-icon-16x16.png').image],
defaultCloseOperation: WindowConstants.DO_NOTHING_ON_CLOSE, // ADDED PROPERTY HERE
windowClosing: { evt ->                                     // AND HERE
println "QuizView.groovy: windowClosing event called!"
System.out.flush()
app.shutdown()
}
In addition to the println statement to tell me my shutdown hook was invoked, I needed to add the call to app.shutdown() since I was now telling Java not to end the application when its main window was closed by setting the defaultCloseOperation property to the DO_NOTHING_ON_CLOSE. I followed Josh's tip on editing the griffon-app/conf/Application.groovy file to set the autoShutdown property to false. This flag is needed so my window-closing event code would be run instead of the default auto-shutdown behavior. (Thanks for the tip, Josh.)
Application.groovy:
application {
title='Quiz'
startupGroups = ['quiz']
// Should Griffon exit when no Griffon created frames are showing?
autoShutdown = true
// If you want some non-standard application class, apply it here
//frameClass = 'javax.swing.JFrame'
}
mvcGroups {
// MVC Group for ""
'quiz' {
model = 'QuizModel'
controller = 'QuizController'
view = 'QuizView'
}
}
Now when I run the application and close the window, the console shows:
$ griffon run-app
Welcome to Griffon 0.2-BETA - http://griffon.codehaus.org/
Licensed under Apache Standard License 2.0
Griffon home is set to: /home/tom/Projects/Griffon/griffon-0.2-BETA
Base Directory: /home/tom/Projects/ManningQuiz/quiz
Running script /home/tom/Projects/Griffon/griffon-0.2-BETA/scripts/RunApp.groovy
Environment set to development
Warning, target causing name overwriting of name default
[groovyc] Compiling 3 source files to /home/tom/.griffon/0.2-BETA/projects/quiz/classes
QuizView.groovy: My windowClosing event called!
That's one way to add a shutdown hook to a Griffon application, by adding a listener to fire when the application's window closes. However, this discovery didn't answer the Manning quiz. None of the available answers showed this technique.

More searching around the web pointed me to the compellingly sounding griffon-app/lifecycle files created by the create-app scaffolding command. One of these auto-generated files is called Shutdown.groovy. It couldn't get more obvious or more easy than that, I suppose. The contents of this file show helpful comments describing how to add shutdown hooks to your application.
griffon-app/lifecycle/Shutdown.groovy
/*
* This script is executed inside the EDT, so be sure to
* call long running code in another thread.
*
* You have the following options
* - SwingBuilder.doOutside { // your code  }
* - Thread.start { // your code }
* - SwingXBuilder.withWorker( start: true ) {
*      onInit { // initialization (optional, runs in current thread) }
*      work { // your code }
*      onDone { // finish (runs inside EDT) }
*   }
*
* You have the following options to run code again inside EDT
* - SwingBuilder.doLater { // your code }
* - SwingBuilder.edt { // your code }
* - SwingUtilities.invokeLater { // your code }
*/
I thought I'd edit this file and add some custom shutdown code. I added this to the end of the above file:
import groovy.swing.SwingBuilder
def swing = new SwingBuilder()
swing.doOutside {
println "doOutside called in the Shutdown.groovy lifecycle"
}
With these few extra lines of code, running the application (griffon run-app) and closing the window resulted in these lines on the console. (I eliminated the Griffon startup information.):
QuizView.groovy: My windowClosing event called!
doOutside called in the Shutdown.groovy lifecycle
Interesting to see that the application's window-closing event occurred before the application shutdown event. That makes perfect sense.

But Wait, There's More

Unfortunately, this solution didn't seem to satisfy any of the available options in the Manning quiz. (Except for the tantalizingly tempting "None of the above" fourth option.) I didn't want to give up yet in finding a solution. The available quiz answers that seemed worthy of looking into talked about defining event handlers for the "ShutdownStart" event or the "ShutdownEnd" event. According to the Release Notes for version 0.1, runtime events may be added to the controller class. The notes list all events that may fired by the application during its life cycle:
  • BootstrapEnd
  • StartupStart
  • StartupEnd
  • ReadyStart
  • ReadyEnd
  • ShutdownStart
Since no event for ShutdownEnd is in the list, I figured the Manning quiz answer was probably defining an event handler for ShutdownStart. Since I wanted to be sure, I added a tiny event handler, with code borrowed from the sample in the Release Notes, to my controller class in griffon-app/controllers/QuizController.groovy:
def onShutdownStart = { app ->
println "Controller onShutdownDown says ${app.config.application.title} is shutting down."
}
I re-ran the application and shut it down, and the console now showed:
QuizView.groovy: My windowClosing event called!
Controller onShutdownDown says Quiz is shutting down.
doOutside called in the Shutdown.groovy lifecycle
The lines show all of my shutdown code successfully got called. So here's what I learned in my foray into Griffon:
  • There are at least THREE ways to handle events that fire when an application is shut down
  • Writing event listeners in Groovy/Griffon is a lot easier than Swing
  • There is no requirement to register the runtime event with the source of the event
  • Griffon (and Groovy) do their share to ease programming by defining conventions over requiring configuration
The nice bonus in playing with Griffon was the scaffolding-building create-app command got me started and running quickly. I was able to create a Griffon desktop Java application, add three ways to capture runtime events, compile and test the application several times -- all in less time it took me to write this blog documenting these facts. I don't know whether Griffon can win the hearts of developers who want to write desktop applications, but I sure think it can win the hearts of Java developers who would otherwise be stuck writing a straight Swing application. If you're a Swing developer, definitely check out what Groovy and now Griffon have to offer in ease of development and simpler code writing. I look forward to seeing what Griffon becomes once it reaches the 1.0 milestone.