Desktop Development - The Fun Way

Tutorial – Griffon: Building Desktop Applications with Groovy

Andres Almiray
griffon.11

Creator of Griffon, Andres Almiray takes us on a tour of the Grails-inspired application framework that is bringing fun back to desktop development.

Building desktop applications can
be an enjoyable experience if you’re willing to throw in a bit of
Groovy into the mix. Griffon is an application framework that
follows the spirit of Grails to bring back the fun to desktop
development.

Desktop
application development
, a term that
isn’t heard much these days as web development nor concurrency and
parallelism are. However that doesn’t mean it’s dead as some
proclaim. There are indeed some industry sectors where a desktop
application is the top alternative for solving a particular
problem; in some other environments it’s the only choice for
security reasons. Think of financial institutes, banks, the health
industry, biological research, chemical laboratories, satellite
operations and the military; just to name a few. All of them impose
a particular set of restrictions where desktop applications excel
over web applications, such as security, access to local resources,
devices and port communications. The other thing that they have in
common is Griffon. Yes, the Griffon framework has helped teams in
all those industries and spaces to get the job done.

You may have heard of Griffon
before but still wonder what it is. In short, it’s a desktop
application platform for the JVM. It has strong roots in the Groovy
community as the project is the brain child of the Groovy Swing
team: Danno Ferrin, James Williams and myself. That being said, you
may excuse me if I get a bit excited explaining some of Griffon’s
features, as I’m very fond of the project. A key driving force
behind the framework’s design is that it should be easy to pick up
by Java developers. It should also enable quick coding cycles while
keeping the source nice and tidy. Finally, the productivity gains
and the fun factor must be immediately perceived.

For these reasons the team decided
to follow in the steps of the Grails framework and its community.
There are a lot of similarities between both frameworks. For
instance, both have a command line interface that helps you get
around with the usual tasks of creating, building, packaging and
deploying applications. Both frameworks leverage the Groovy
language as a glue for their respective software stacks. The tool
integration is also quite good, as major IDEs and popular text
editors offer good support for dealing with this kind of
projects.

But enough of the theory, let’s get
some practice! The rest of this article will be devoted to building
a simple address book application. We will definitely not build a
full-fledged application in the few pages that we have to spare but
it’s my hope that all the things to be discussed will give you
enough pointers to get you going with the framework.

Setup and
Configuration

The first step
is to download
and configure Griffon on your computer; there are several choices
for doing so. If you pick the universal installer from the download
page it will unpack the binaries and configure the path
environments for you, particular on Windows platforms. Or if you’re
on Linux machines you can give it a try to either the RPM or
Debian-based packages. ZIP or TGZ packages may work as your last
resort. Simply download the package, uncompress it on a directory
of your choosing – preferably one without spaces. Next configure an
environment variable
GRIFFON_HOME pointing to the directory where the Griffon binary
distribution was unpacked. Lastly make sure that the PATH
environment variable contains a reference to

GRIFFON_HOME/bin. If all goes well,
invoking griffon command with the –version flag turned on should
display a similar output as the following one

$ griffon
–version

———————————————

Griffon
0.9.5

———————————————

Build:
15-Mar-2012 12:56 PM

Groovy:
1.8.6

Ant:
1.8.2

Slf4j:
1.6.4

Spring:
3.1.0.RELEASE

JVM: 1.6.0_29
(Apple Inc. 20.4-b02-402)

OS: Mac OS X
10.6.8 x86_64

 

Alright. Time to get down to business…

Initial Steps

First things first, how do we create an application? Typically
you may choose the Maven-based approach and select an appropriate
archetype to bootstrap a project. Or you just can simply create a
new directory, fetch some Ant scripts and be done with it. Or let
your trusty IDE decide. Choices, choices, choices. The griffon
command line tool is here to help. Every Griffon application starts
in the same way, by invoking the following command

$ griffon
create-app addressbook

$
cd addressbook

You’ll notice a flurry of lines
in the output. Go ahead and inspect the contents of the newly
created application if you want. The create-app command initializes
the application by creating several directories and some files. One
of these directories is of particular importance, its name is
griffon-app. Within this directory you’ll find another set of
directories that help keeping the source code organized.

Figure 1 shows the expanded content of the griffon-app directory as
created moments ago.

Figure 1:  Contents of the address book
application

As you can appreciate, Griffon makes use of the MVC pattern to
arrange the elements that comprise an application. When an
application is created, you’ll also get an initial MVC group whose
name matches the name of the application. Inside each MVC member
there’s enough code to make the application run. Yes, believe it or
not, the application is ready to be launched. Go back to the
console and execute the following command

$ griffon
run-app

This should compile the
application sources, package resources, roundup dependencies and
launch the application. In a matter of seconds you should see a
window popping up, like the one shown in
Figure
2
.

Figure 2: Addressbook application running for
the first time

Granted, it doesn’t loom like
much, but we haven’t written a single line of code yet! Listing 1
shows what you’ll find inside the file
griffon-app/views/addressbook/AddressbookView.groovy
when you open it.

Listing 1 –
AddressbookView

 

package addressbook
application(title: 'addressbook',
  preferredSize: [320, 240],
  pack: true,
  //location: [50,50], 
  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]) {
    // add content here
    label('Content Goes Here') // delete me
}

 

What we see here is a
Swing-based Domain Specific Language (or DSL for short) based on a
popular Groovy feature: builders. In our particular case we’re
dealing with SwingBuilder. Builders are but a collection of nodes
and rules that know how to build hierarchical structures. It so
happens that a Swing UI is comprised of a tree of components. In
the View we can observe a top level node named “application” and
some properties being applied to it. Next we see a child node named
“label” with a single text entry. You may recognize the code
structure with what’s shown by
Figure
2
. That’s the power of the Swing DSL.
The code and the UI resemble each other a lot, it’s quite easy to
follow how components are structured when reading the
DSL.


Building the UI

Now that we have seen a bit of code in the Views, let’s continue
with this MVC member, we’ll cover the other two in a moment. In the
spirit of keeping things simple we’ll update the UI so that it
looks like Figure 3.

Figure 3: New looks for the address
book application

Let’s decompose each section. On the left we see a white space
with a title ‘Contacts’. This will be a list that holds all the
contacts in our address book. In the middle we see a form that we
may use to edit the details of a particular contact found in
the list. Next on the right we discover a series of buttons that
will perform operations on a contact. You may also appreciate a
menu named ‘Contacts’ which contains menu items with the same names
as the buttons. Listing 2 describes the updated
AddressbookView.

Listing 2 – AddressbookView Updated

 

package addressbook
application(title: 'Addressbook',
  pack: true,
  resizable: false,
  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]) {
    menuBar {
        menu('Contacts') {
            controller.griffonClass.actionNames.each { name ->
                menuItem(getVariable(name))
            }            
        }
    }
    migLayout(layoutConstraints: 'fill')
    list(model: eventListModel(source: model.contacts), 
         constraints: 'west, w 180! ',
         border: titledBorder(title: 'Contacts'),
         selectionMode: ListSelectionModel.SINGLE_SELECTION,
         keyReleased: { e ->  // enter/return key
             if (e.keyCode != KeyEvent.VK_ENTER) return
             int index = e.source.selectedIndex
             if (index > -1) model.selectedIndex = index
         },
         mouseClicked: { e -> // double click
             if (e.clickCount != 2) return
             int index = e.source.locationToIndex(e.point)
             if (index > -1) model.selectedIndex = index
         })
    panel(constraints: 'center', border: titledBorder(title: 'Contact')) {
        migLayout(layoutConstraints: 'fill')
        for(propName in Contact.PROPERTIES) {
            label(text: GriffonNameUtils.getNaturalName(propName) + ': ',
                        constraints: 'right')
            textField(columns: 30, constraints: 'grow, wrap',
                text: bind(propName, source: model.currentContact,
                           mutual: true))
        }
    }
    panel(constraints: 'east', border: titledBorder(title: 'Actions')) {
        migLayout()
        controller.griffonClass.actionNames.each { name ->
            button(getVariable(name), constraints: 'growx, wrap')
        }
    }
}

We can see the menuBar node we mentioned earlier. We can also
see three main components: a list that will be placed on the west
side; a panel in the middle that somehow creates a pair or label
and textField for each property found in a list of properties. Then
we see the third component, a panel that holds buttons. The code
may look a bit magical at first glance but really what we’re doing
is taking advantage of the conventions laid out by Griffon. A View
MVC member has access to the other two members, that is, the Model
and the Controller. The job of the View is to lay out the UI
components. The job of the Controller is to hold the logic that
reacts to user input. The job of the Model is to serve as a
communication bridge between View and Controller. We can see
references to a model and a controller variables in the View; these
variables point to their respective MVC members.

Next we’ll update the Model
found in griffon-
app/models/addressbook/AddressbookModel.groovy.
Here we’ll make sure the Model keeps a list of contacts in memory;
it will also hold a reference to the contact currently being
edited. We’ll make use of GlazedLists (a popular choice among Swing
developers) to organize the list of contacts. Listing
3
shows all the code that’s required to build the list and
keep a reference to the currently edited contact. Now, the contacts
list has a special binding defined in relation to its elements.
Whenever an element is edited it will publish a change event that
the list will intercept; the list in turn will update whoever is
interested in lists changes. Looking back to Listing 2 you can see
that the list definition makes use of a listEventModel node. This
is exactly the component that will notify the UI whenever an update
is available, this repainting the affected region. And we only had
to connect a pair of components for this to happen! The
AddressbookModel works with two domain specific classes:

Contact and
ContactPresentationModel. The first can
be seen as a plain domain class, as it defines what a contact
should be in terms of simple properties. The latter is an
observable wrapper around the
Contact class. Presentation models are usually decorators that can
support binding operations. We’ll see these two classes in just a
moment.

Listing 3

 

package addressbook
import groovy.beans.Bindable
import ca.odell.glazedlists.*
import griffon.transform.PropertyListener
import java.beans.PropertyChangeEvent
import java.beans.PropertyChangeListener

class AddressbookModel {
    final EventList<ContactPresentationModel> contacts = 
             new ObservableElementList<ContactPresentationModel>(
        GlazedLists.threadSafeList(
        new BasicEventList<ContactPresentationModel>()),
        GlazedLists.beanConnector(ContactPresentationModel)
    )
    
    final ContactPresentationModel currentContact = new ContactPresentationModel()
    
    @PropertyListener(selectionUpdater)
    @Bindable int selectedIndex = -1
    
    private selectionUpdater = { e ->
        currentContact.contact = contacts[selectedIndex].contact
    }
    
    AddressbookModel() {
        currentContact.addPropertyChangeListener(new ModelUpdater())
    }
    
    private class ModelUpdater implements PropertyChangeListener {
        void propertyChange(PropertyChangeEvent e) {
            if(e.propertyName == ‘contact’ || selectedIndex < 0) return
            contacts[selectedIndex][e.propertyName] = e.newValue
        }
    }

    void removeContact(Contact contact) {
        currentContact.contact = null
        ContactPresentationModel toDelete = contacts.find { 
            it.contact == contact 
        }
        if(toDelete != null) contacts.remove(toDelete)
    }
}

 

But before we show the domain
let’s cover the final MVC member: the Controller. It’s the job of
the controller to react to user input and orchestrate the flow of
information. For now we only need to fill in the blanks to make the
application work again, for example by pasting the code shown in
Listing 4 into

griffon-app/controllers/addresbook/AddressbookController.groovy

Listing 4

 

package addressbook
class AddressbookController {
    def model
    void newAction(evt) { }
    void saveAction(evt) { }  
    void deleteAction(evt) { }

 

Do you remember that Models
mediate data between Controllers and Views? That’s precisely why
there’s a model property on the
controller
class. Griffon sports a basic dependency
injection mechanism that will assure each MVC member can talk to
the other two as long as certain properties are defined in their
respective classes.

          The
Domain

If you’re a Grails developer you
may have noticed we did not start by modelling the domain, which is
the usual case when working with Grails applications. There are two
reasons for making this choice. First, to show you the basics of
the MVC members and how they interact with each other. The second
is that Griffon does not support domain classes out of the box, at
least not as Grails understands it, that is, there’s no GORM API
for Griffon, yet. But we can manage ourselves by writing simple
domain classes. Listing 5 for example shows what
the
Contact domain class may
look like.

Listing 5

 

package addressbook
@groovy.transform.EqualsAndHashCode
class Contact {
    long id
    String name
    String lastname
    String address
    String company
    String email
    
    String toString() { "$name $lastname : $email" }
    
    static final List<String> PROPERTIES = ['name', 'lastname', 
         'address', 'company', 'email']

 

This class can be defined in the
file
src/main/addressbook/Contact.groovy. Next to it we’ll define the companion presentation model,
in
src/main/addressbook/ContactPresentationModel.groovy
with the code seen in Listing 6
in it.

Listing 6

 

package addressbook
import groovy.beans.Bindable
@griffon.transform.PropertyListener(propertyUpdater)
class ContactPresentationModel {
    // attributes
    @Bindable String name
    @Bindable String lastname
    @Bindable String address
    @Bindable String company
    @Bindable String email
    
    // model reference
    @Bindable Contact contact = new Contact()
    
    private propertyUpdater = { e ->
        if(e.propertyName == 'contact') {
            for(property in Contact.PROPERTIES) {
                def bean = e.newValue
                delegate[property] = bean != null ? bean[property] : null
            }
        }
    }

    String toString() { "$name $lastname" }

    void updateContact() {
        if(contact) {
            for(property in Contact.PROPERTIES) {
                contact[property] = this[property]
            }
        }
    }
}

 

As we mentioned before, the
domain class is simple in its design; it only needs to be concerned
with the data we want to keep. The presentation model on the other
hand mirrors the domain class by having the same properties but
with a slight modification: each one of them is observable. This
means that whenever the value of any of those properties changes,
an event will be fired. These events are the ones that enable
binding. Griffon makes use of the
@Bindable
annotation to instruct the Groovy compiler to
inject a set of instructions into the byte code that makes this
class an observable one.
@Bindable belongs to a set of special interfaces found in the Groovy
language that open the door for byte code manipulation. This set is
known as
AST transformations.
There’s another AST transformation found in this code, it’s

@PropertyListener. This transformation
is a fancy way to define and attach a PropertyChangeListener on a
particular class and property. In our case, we’re attaching
a
PropertyChangeListener that
reacts on all property changes. The next effect of all the code we
have in Listing 6 is that when a
Contact
instance is attached to an instance of
ContactPresentationModels, all of the
property values will be copied from the contact to the model. The
reverse operation will take effect when the

updateContact() method is
called.

Good. We’re almost ready to run the application again. But
before we do, we must install a group of plug-ins that will make
our life easier. We said we’ll make use of GlazedLists. This
library is provided by a plug-in, so we’ll install that. In the
view we make use of MigLayout, so we’ll install a plug-in for it
too. Finally we’ll install another plug-in that makes creating UI
actions based on controller methods a breeze. Go to your console
prompt and type the following commands

$ griffon
install-plugin glazedlists

$ griffon
install-plugin miglayout

$ griffon
install-plugin actions

After a few lines of output for each plug-in install we have all
that’s needed to run the application again.

Making Contacts Persistent

Time to finish up the application. We have a few tasks ahead of
us:

  • Fill the code required by each controller action
  • Save the contact list to a database
  • Make sure to load the contacts from the database when the
    application starts up

Filling up the actions is a straightforward operation, as
the bulk of the data manipulation is already taken care of by the
bindings we have put in place. Listing 7 shows the
final code for AddressbookController.

Listing 7 – AddressbookController

package addressbook
class AddressbookController {
    def model
    def storageService

    void newAction(evt) {
        model.selectedIndex = -1
        model.currentContact.contact = new Contact()
    }
    
    void saveAction(evt) {
        // push changes to domain object
        model.currentContact.updateContact()
        boolean isNew = model.currentContact.contact.id < 1
        // save to db
        storageService.store(model.currentContact.contact)
        // if is a new contact, add it to the list
        if(isNew) {
            def cpm = new ContactPresentationModel()
            cpm.contact = model.currentContact.contact
            model.contacts << cpm
        }
    }
    
    void deleteAction(evt) {
        if(model.currentContact.contact && model.currentContact.contact.id) {
            // delete from db
            storageService.remove(model.currentContact.contact)
            // remove from contact list
            execInsideUIAsync {
                model.removeContact(model.currentContact.contact)
                model.selectedIndex = -1
            }
        }
    }
    
    void dumpAction(evt) {
        storageService.dump()
    }

    void mvcGroupInit(Map args) {
        execFuture {
            List<ContactPresentationModel> list = storageService.load().collect([]) {
                new ContactPresentationModel(contact: it)
            }
            execInsideUIAsync {
                model.contacts.addAll(list)
            }
        }
    }
}

 

The first action,
newAction, is concerned by resetting
the current selection (if any) and creating an empty Contact.
The
saveAction() should push the
changes from the presentation model back to the domain object,
store the data in the database and in the case that this is a new
contact, add it to the list of contacts. Notice that when dealing
with database concerns we’ll delegate to another component called
storageService which we’ll see right after we finish describing the
Controller. The third action deletes a contact first by removing it
from the database, then removing it from the contacts list. We
added a fourth action that will be used to dump the database
contents into the console. The last piece of information found in
the code relates to loading the data from the database and filling
up the contacts list. The method name is special as it’s a hook
into the MVC lifecycle. This particular method will be called after
all MVC members have been instantiated, think of it as a member
initializer. We’re ready to have a look at the storageService
component.

Services in Griffon are nothing
more than regular classes but they receive special treatment from
the framework. For example, they are treated as singletons and will
be automatically injected into MVC members as long as the member
defines a property whose name matches the service name. Armed with
this knowledge we’ll create a
StorageService
class, like this:

$ griffon
create-service storage

This will create a file
in

griffon-app/services/addressbook/StorageService.groovy
with default content. Listing 8
shows the code that must be put inside that file for the
application to work.

Listing 8

package addressbook
class StorageService {
    List<Contact> load() {
        withSql { dsName, sql ->
            List tmpList = []
            sql.eachRow('SELECT * FROM contacts') { rs ->
                tmpList << new Contact(
                    id:       rs.id,
                    name:     rs.name,
                    lastname: rs.lastname,
                    address:  rs.address,
                    company:  rs.company,
                    email:    rs.email
                )
            }
            tmpList
        }
    }

    void store(Contact contact) {
        if(contact.id < 1) {
            // save
            withSql { dsName, sql ->
                String query = 'select max(id) max from contacts'
                contact.id = (sql.firstRow(query).max as long) + 1
                List params = [contact.id]
                for(property in Contact.PROPERTIES) {
                    params << contact[property]
                }
                String size = Contact.PROPERTIES.size()
                String columnNames = 'id, ' + Contact.PROPERTIES.join(', ')
                String placeHolders = (['?'] * size + 1)).join(',')
                sql.execute("""insert into contacts ($columnNames)
                   values ($placeHolders""", params)
            }
        } else {
            // update
            withSql { dsName, sql ->
                List params = []
                for(property in Contact.PROPERTIES) {
                    params << contact[property]
                }
                params << contact.id
                String clauses = Contact.PROPERTIES.collect([]) { prop ->
                    "$prop = ?"
                }.join(', ')
                sql.execute("""update contacts
                    set $clauses where id = ?""", params)
            }
        }
    }
    
    void remove(Contact contact) {
        withSql { dsName, sql ->
            sql.execute('delete from contacts where id = ?', [contact.id])
        }
    }
    
    void dump() {
        withSql { dsName, sql ->
            sql.eachRow('SELECT * FROM contacts') { rs ->
                println rs
            } 
        }
    }
}

 

Each one of the service methods
makes use of a method named
withSql. This method becomes
available if we install another plug-in. Let’s do that
now:

$ griffon
install-plugin gsql

Perfect. We now have enabled
Groovy
SQL support
in our little application. Groovy SQL is another
DSL on top of regular SQL. With it, you can make SQL calls using a
programmatic API that closely resembles working with objects and
object graphs. As a matter of fact, you can even apply Groovy
closures, Groovy strings, and other Groovy tricks, like those shown
in the implementation of the
StorageService
class. There are two more items we must take
care of before launching the application again. We must tell the
GSQL plug-in that the
withSql method must be
applied to services; secondly, we must define the database schema.
As we said earlier there’s no GORM API yet, database schemas must
be defined by hand.

The first task is accomplished
by editing the file
griffon-app/conf/Config.groovy
and appending the following line

griffon.datasource.injectInto
= [‘service’]

The second task gets done by
creating a file in
griffon-app/resources/schema.ddl with the following content:

 

DROP TABLE IF
EXISTS contacts;

CREATE TABLE
contacts(

id INTEGER NOT
NULL PRIMARY KEY,

name VARCHAR(30)
NOT NULL,

lastname
VARCHAR(30) NOT NULL,

address
VARCHAR(100) NOT NULL,

company
VARCHAR(50) NOT NULL,

email
VARCHAR(100) NOT NULL

);

Good, we’re done. What about seeding the
database with some initial data? In Grails this is done by editing
a file named
BootStrap.groovy, in Griffon
it’s done by editing
griffon-app/conf/BootstrapGsql.groovy.
Let’s add an entry to the contacts table, as Listing
9
shows.

 

import groovy.sql.Sql
class BootstrapGsql {
    def init = { String dataSourceName = 'default', Sql sql ->
        def contacts = sql.dataSet('contacts')
        contacts.add(
            id: 1,
            name: 'Andres',
            lastname: 'Almiray',
            address: 'Kirschgartenstrasse 5 CH-4051 Switzerland',
            company: 'Canno Engineering AG',
            email: 'andres.almiray@canoo.com'
        )
    }

    def destroy = { String dataSourceName = ‘default’, Sql sql ->
    }
} 

Phew. Now we’re really done.
Launch the application once more. You should see one entry in the
contacts list as
Figure 4 shows. Select it with the mouse and either press
enter or
double-click on it. This will make the contact the active one and
place all of its values in the middle form. Edit some of its
properties, then click on the
save button. Create a new contact and save it too. Now click on
the
dump button. You should
see as many rows in the output as entries can be found in the
contacts list.

Figure 4: Address book application with one
entry selected

The
Aftermath

We have had quite the whirlwind tour on the Griffon basics.
Granted, there are more things that meet the eye in just a few
pages and code listings. I hope this has been enough to wet your
appetite for more, or at least consider giving Griffon a try. All
of the behaviour we wrote so far fits in a mere 291 lines of code.
Don’t believe me? Run the following command:

 

$ griffon
stats

 

A table listing all sources by type will appear, similar to this
one:

 

+———————-+——-+——-+

| Name | Files |
LOC |

+———————-+——-+——-+

| Models | 1 | 32
|

| Views | 1 | 45
|

| Controllers | 1
| 39 |

| Services | 1 |
57 |

| Lifecycle | 5 |
3 |

| Groovy/Java
Sources | 2 | 40 |

| Unit Tests | 1
| 13 |

| Integration
Tests | 1 | 15 |

| Configuration |
2 | 47 |

+———————-+——-+——-+

| Totals | 15 |
291 |

+———————-+——-+——-+

Nice. The full source code for this application can
be found at GitHub. There are
more things that we could add to this application. For example,
there’s no error handling whatsoever. What if SQL is not your cup
of tea? No problem, you can pick any of the supported
NoSQL options
. Or maybe Swing is not for you. No problem
either, Griffon supports SWT and JavaFX as well. Changing UI
toolkits will mean changing the View mostly while keeping the other
components almost intact. There are definitely many choices ahead
of you.

Additional Resources

www.glazedlists.com

www.miglayout.com

 

This article originally appeared in JAX Magazine – Groovy.
Subscribe for free here.

Author
Andres Almiray
Andres Almiray is a Java/Groovy developer with more than 12 years of experience in software design and development. He has been involved in web and desktop application development since the early days of Java. His current interests include Groovy and desktop apps. He is a true believer of open source and has participated in popular projects like Groovy, Griffon, JMatter and DbUnit, as well as starting his own projects (Json-lib, EZMorph, GraphicsBuilder, JideBuilder). Andres is a founding member and current project lead of the Griffon framework. He likes to spend time with his beloved wife, Ixchel, when not hacking around.
Comments
comments powered by Disqus