Getting Groovy on the Web And Desktop - No Fluff Just Stuff

Getting Groovy on the Web And Desktop

Posted by: Andres Almiray on March 10, 2011

This article originally appeared in an special edition of the No Fluff Just Stuff magazine published for SpringOne 2GX 2010.

Getting Groovy on the Web And Desktop

Andres Almiray

Have you ever had the need to build a Grails powered RIA but couldn't find the perfect Ajax solution? Perhaps a solution rooted on the desktop would be good, if only there was a good framework that could talk to Grails while successfully helping you sort out the challenges of desktop development. Well, good news. It turns out there is one: Griffon. Inspired by Grails and other Groovy tools, Griffon brings the ease of use of Grails to the desktop arena. Discover how both frameworks bring back the fun to web and desktop application development.

It’s hard to find a web developer these days that has not come across an Ajax or RIA powered website. These technologies have become so ubiquitous that we can’t simply go back to the times when Web 2.0 did not exist. There are literally myriad options for building a web application that have Ajax built-in or present a rich interface, both at the frontend and backend tiers. Grails happens to be one of the front runners when dealing with the JVM.

A Few Words about Grails and Groovy

If you do not know Grails yet and you’re a Java developer then let me say that you’re missing out on a great deal, both in terms of productivity and fun. Grails is a full stack web development platform whose foundations lay with Spring and Hibernate, and as such it shouldn’t be that hard for any Java developer to pick it up and get to work. However, what really makes it revolutionary is its choice of default development language: Groovy.

Grails has another ace up its sleeve: a ready-for-business command tool that’s also extensible via plugins. It is thanks to the plugin system that building a Grails application is a breeze. Need a way to search over your data? Install the Searchable plugin. You’re requirements ask for CouchDB instead of a traditional SQL store? No problem, install the couchdb plugin. What’s that? Protect certain parts of the application using security realms? The shiro plugin is here to help. You can get the idea by now.

Out of the immense set of Grails plugins (by the team’s current count it’s over 400) you’ll find a good number for dealing with Ajax and RIAs. They are pretty good actually. No matter which one you pick there will be times when a requirement asks for a feature that can’t be implemented because of a browser limitation. It’s time to look outside of the browser window and look at the space that allows you to run said browser. Yes, that’s your computer’s desktop environment. If only there was a way to build a desktop application in a similar fashion as you do web apps with Grails. There is one and its name is Griffon.

Enter Griffon

In the early days of Groovy its creators recognized that the dynamic nature of the language helped a lot when implementing the builder pattern. One of the first of such builders was SwingBuilder, a rather simple class with satellite helper classes that allowed a developer to build a Java Swing based application using a declarative syntax. Time passed by until SwingBuilder was joined by a pair of siblings, builders capable of creating more complex applications using Swing components provided by third party libraries. It was right after this moment when the notion of Griffon was conceived with exactly the same question we asked ourselves in the previous section.

The power of Grails for building web applications was evident, so what if there was a framework that did the same for the desktop? The seed was sown after that thought. A few months later and a fork of the Grails 1.1 codebase was reborn as Griffon 0.0. This was September 10th of 2008 which means that by the time you read this Griffon will be a bit more than 2 years old. Happy Birthday!

Founded as a fork of the Grails codebase means that Griffon shares a lot of traits with it, however it also has a spirit of its own. For example, the build and plugin systems are almost identical but the runtime aspects are exclusive to the desktop. You’ll find a good number of Griffon plugins (over 100 at this moment) that enhance your application and the development experience in several ways.

If building an application with Groovy (and some Java) end to end, from web to desktop, sounds like an exciting prospect for the next hour then let’s write some code!

The Starting Point

We’ll commence this journey by building the backend side of the application using Grails. Any domain is good at this point, we’ll pick the familiar Book/Author domain for its simplicity. Assuming you’ve got the latest stable Grails release installed already (1.3.4 at the time of writing) creating the application is done with a simple step

grails create-app bookstore

This command will create the application’s structure and download a minimum set of plugins if you’re running Grails fort he first time. You can run the application at this moment, but because it’s empty you won’t see anything. Let’s fill it up a bit. First create two domain classes: Book and Author.

grails create-domain-class Author
grails create-domain-class Book

These commands will generate a pair of Groovy classes located under grails-app/domains/bookstore. Open them up in your favorite editor, of if you prefer, in your favorite IDE; Grails is not picky and will gladly work with any IDE or editor you throw at it. Make sure that the contents of the Author and Book domain classes match the ones found in Listing ALM-1 and Listing ALM-2 respectively.

Listing ALM-1: Author domain class
Listing ALM-2: Book domain class

Without going into much detail the Author and Book classes define a pair of entities that can be persisted to the default datastore. If this is the first time you have encountered a Grails domain class, don’t worry, they don’t bite. Beside the simple properties on each class you’ll notice that there is a one-to-many relationship from Author to Book. We could have certainly made it a many-to-many in order to reflect the real world in a much closer way but let’s keep things simple for the moment.

There’s another step that must be performed before we actually attempt to run the application for the first time. We must expose the domain classes to the user in some way. This means, of course, writing HTML or using some other templating mechanism, at least when it comes to other frameworks. With Grails we can let the framework take over as long as we stick to the conventions. If we only create a pair of controller classes, one per domain class, then there’s nothing else that needs to be done. Hurray for scaffolding!

Go back to your command prompt and type the following:

grails create-controller Author
grails create-controller Book

Locate each controller under grails-app/controllers/bookstore and edit them. Make sure each one matches Listing ALM-3 and Listing ALM-4.

Listing ALM-3: Controller for Authors
Listing ALM-3: Controller for Books

Yes, that’s all we need for now. Don’t be fooled though, there’s a full blown, Spring MVC powered controller behind each controller we wrote. Perfect. We’re good to go. Run the application with the following command

grails run-app

After a few seconds, during which the command compiles and packages the application, you’ll be instructed to visit the following address http://localhost:8080/bookstore. Use your favorite browser to navigate to that URL. You’ll notice a default page listing some internal details of the application, like the currently installed plugins and its versions. You’ll also notice a pair of links that point to the controller we wrote. Click on the AuthorController link. You’re now on the starting page for all CRUD operations that affect an Author. How is this possible? This is the power of conventions. When we instructed each controller that a domain class should be scaffolded it immediately (well more exactly at compile time) generated the minimum required code and templates to achieve basic CRUD on that specific domain class. You can play around with Authors and Books now, try creating and removing some. Figure ALM-1 shows how the application looks like after two authors have been added.


Figure ALM-1

To REST or Not

There’s no shortage of options for exposing data to the wild. However I would argue that a REST style is perhaps the simplest one. It doesn’t hurt that many Web 2.0 sites have chosen this style (or variants) to let developers have access to the services they provide. As you will see in just a few moments, exposing domain classes in a RESTful way with Grails is a piece of cake.

Love it or hate, XML is a popular choice among Java developers for externalizing data. Another format that gained mommntum during the Web 2.0 is JSON. There are a couple of ways to produce and consume both formats in Grails, but let’s pick JSON for its simplicity.

What we want to do is expose each domain class with 3 operations: list, show and search. The first should return a collection of all instances of said domain available in the datastore. The second should return a single instance that can be found with a specific identifier. Lastly, the third choice should return a collection of all domain instances that match a certain criteria. All the results will be returned in JSON format.

Go back to AuthorController and make the necessary edits so that it looks like Listing ALM-5.

Listing ALM-5: Updated Author controller

Gone is the default scaffolding, which has been replaced by specific actions that match each one of the operations that we want to expose to the outside world. The code is pretty straight forward, however you’ll notice that there are calls to static methods on the Author class that we did not define. These methods are added by the framework. Remember we spoke about Groovy’s meta-programming capabilities? Well, here’s proof that they are put to good use. All domain classes posess the ability to invoke dynamic finder methods that magically match their own properties. For example, in the search action we can lookup all Authors using a like query on its name or lastname property. These dynamic finder methods follow closely the operators and rules that you find in SQL. One last point to remark here is that all results are return in JSON format by using a type conversion. Grails will figure out the proper content type to send to the client by inspecting the format and data.

The updated BookController class looks very similar to the Author one, as shown by Listing ALM-6.

Listing ALM-6: Updated Book Controller

Here too we’ll find a dynamic finder on the Book class. This one operates on the Books title property. Summarizing the added behavior, we can search Authors by name and lastname,while Books can be searched by title. Both domain instances can be listed in their entirety and looked up by a particular identifier.

We must perform one final change before we can test the application once more. The REST style states that resources should be available following a naming convention on the URL that points to them. There are many variations of the original guidelines as REST does not impose strict rules on the conventions so we’ll pick one that’s easily recognizable. The root of the URL path must be the application name; Grails takes care of that. The next element in the path will be the name of the domain class, followed by the action we want to invoke, with optional parameters. Here’s some examples for the Author domain.

/author -> points to the default action, which in our case lists all entities
/author/search -> calls the search action on authors
/author/42 -> fetches the author with id = 42

With these examples in mind, look for a file named UrlMappings.groovy located in grails-app/conf. Copy the contents of Listing ALM-7 to this file.

Listing ALM-7: REST like URL mappings

Given that we’ll use the application as data provider for the desktop application it makes sense to start with some predefined domain instances don’t you think? Locate BootStrap.groovy, also in grails-app/conf. Create some domain instances and save them to the data store.

Listing ALM-8: Startup data

You can appreciate a pair of new methods (addToBooks and save) that we needn’t write but the compiler and the Grails framework can inject for us. You can run the application now but don’t use your browser to navigate to the various URLs, use a command line browser like curl or lynx, it makes for quicker debugging. For example

curl http://localhost:8080/bookstore/author/1

Results in the following output

{"class":"bookstore.Author","id":1,"books":[{"class":"Book","id":1}],"lastname":"Paz","name":"Octavio"}

While this one

curl http://localhost:8080/bookstore/book/search?q=Solitude

Yeilds the following results

[{"class":"bookstore.Book","id":1,"author":{"class":"Author","id":1},"title":"The Labyrinth of Solitude"},{"class":"bookstore.Book","id":4,"author":{"class":"Author","id":2},"title":"One Hundred Years of Solitude"}]

We’re done with the server side of the application. Time to look at the other half.

Griffon, A Quick Start

Alright, so what we know of Griffon so far is that it produces Java Swing applications. Don’t worry if you do not know Swing, the declarative nature of Griffon views makes it very easy to grasp the concepts and continue forward. Let’s create the application first. We will do it in a similar fashion as we did it for the Grails one: by invoking a create command. For this you must have the latest Griffon release installed (0.9 at the time of writing) which can be obtained from the Griffon download page. Just follow the instructions found on that page and you’re good to go. Ok, ready? Type the following on your command prompt:

griffon create-app bookstoreclient

This command will bootstrap the application’s structure too. It also generates the minimum set of artifacts so that you can run the application right away. Go ahead, type the following command to test it out

griffon run-app

Notice a trend here? The commands are pretty much identical to the Grails ones! OK, so the compiler does its job with the codebase and after a few seconds you will see a small window appearing on your desktop that resembles Figure ALM-2.


Figure ALM-2

Granted, it doesn’t look like much yet but hey, it works and we didn’t touch a single line of code yet. Before we dive into changing the code let me say that you can run this application in three different modes. We just tried one of them, the standalone mode. The other two modes are applet and webstart, which can be invoked with the following commands

griffon run-applet
griffon run-webstart

Good. As opposed to Grails that starts with an empty application, Griffon creates an initial set of artifacts that conform to what we call an MVC group. This set has one member per type found in the MVC pattern, in other words, a Model, a Controller and a View.

Models are typically used as communication hubs between controllers and views, not to be mistaken with domain classes. Models normally hold observable properties that can be bound at will using the JavaBean’s PropertyChangeListener mechanism.

Controllers contain either public methods or closure properties (like they do in Grails) that define the behavior of the group. Controllers are also able to listen to application events by default. Oh yes, every Griffon application comes with a built-in, lightweight event bus, which simplifies communication between artifacts. We’ll see a sample usage in just a moment.

Then we have the Views. This is where you’ll find the SwingBuilder DSL. Every MVC member has access to the other two but it is in the views where this relationship is more tangible. Views will bind UI elements to model properties. These properties in turn are read from or written to a controller. This is how both members communicate with each other. A view can also bind a UI event to a controller action, for example when a button is pressed or text is entered into an input field.

Curious to know how the UI looks in code? Good. Locate BookstoreclientView.groovy inside griffon-app/views/bookstoreclient. You’ll notice another similarity with Grails. Artifacts are stored by convention in directories that spell out their type. The files typically have a suffix that identifies them too. Listing ALM-9 shows the contents of the View as created by default.

Listing ALM-9: Default View template

A quick survey of the code results in two nodes defined on this View script. The first being the application node, which you can expect resolves to some class of a UI container depending on the running mode: a JFrame on standalone/webstart and a JApplet subclass on applet mode. Inside this node we find the second one: label. This node will create a JLabel instance. The rule of thumb for finding out the name of a node for a particular Swing class is as follows: drop the first J from the class name then uncapitalize the next character. JButton becomes button, JTabbedPane becomes tabbedPane and so forth. Properties on nodes will be set as properties on the UI components. We’ll cover the controller and the model in the next section as they are practically empty at the moment.

Swing is a vast toolkit.

You can do many things with it. It’s also true that you can frustrate yourself by using it. The Swing classes found in the JDK are good enough as a starting point but certainly fall short of providing a modern user experience. And let’s not talk about layouts, especially GridBagLayout. For this matter we will install a few plugins right away. MigLayout is the first on this list. It’s been said that using this layout is like using CSS to position elements on a page. I have limited experience with CSS, however, I can honestly tell you that working with MigLayout is a delight. Next in the list is GlazedLists which simplifies working with lists, tables and trees. It does so by providing a missing key from the JDK’s List class: a List that produces events whenever its contents change.

What would a modern application be without a nice looking strobbing icon used when a long running task is being executed. The JBusyComponent project brings together both SwingX’s JBusyLabel and JXLayer to provide a nicely animated strobe? We can install all of these plugins with the following commands:

griffon install-plugin miglayout
griffon install-plugin glazedlists
griffon install-plugin jbusycomponent
griffon install-plugin jxlayer

Though the jbusycomponent plugin depends on the jxlayer one, it will install an outdated jxlayer version due to a misshap with the latter when it was released for the first time. That’s why we must manually upgrade the plugin to it’s latter version. This problem will be corrected in future releases of the plugins. update: this problem has been fixed.

Now that we’re on the plugin install business let’s install one that will allow us to query the server side using a REST client. The plugin is aptly named rest.

griffon install-plugin rest

Excellent. We can turn back to the View script and modify it. This is what we’re going to do. Figure ALM-3 shows how the application will look like once we finish it.


Figure ALM-3

There are three tabs on the main window. The first shows a list of authors. We can infer that the second tab will show the lists of books and that the third tab will contain some controls that will allow us to search books and authors alike, exactly as shown by Figure ALM-4.


Figure ALM-4

Listing ALM-10 depicts all the code that we need to write to get the UI working.

Listing ALM-10: Finished View

We can define any Groovy construct within a View script, because a View script is also a valid Groovy script. That’s why you’ll spot a closure at the beginning (name makeTableTab). This closure will be used to build tabs number #1 and #2 as their construction is identical, they only differ on the data source that feeds them. Tab #3 is a bit more elaborate than the othe two. I trust the code is not that hard to understand. Let’s start with the tabbedPane node, shall we?

Every child node of a tabbedPane must have a title property; that’s how the tabbedPane knows what name should be used for the tab. We can clearly spot the title properties on each tab and their values (Authors, Books and Search). Tabs #1 and #2 make use of nodes provided by the GlazedLists plugin. These nodes build a TableModel out of some sort of data source (which will be revealed to be a List that produces events, also from GlazedLists). The model is then added to its parent table. Finally a sorting element is added to the table. Clicking on the table headers will sort the data accordingly.

On to the third tab. The main node is a busyComponent that wraps another one, a panel. Inside the panel there’s a migLayout definition. All elements inside this panel will be attached to it using MigLayout’s settings. There are 6 visible elements inside this panel:

  • A textfield whose text property will be bound to a model property named query.
  • A button which triggers the controller’s search action.
  • Two radio buttons that define on which domain the search should be performed.
  • A label whose text is bound to a model property named status.
  • A table wrapped in a scrollPane. It will be used to display the search results.
There are several flavors of binding to be found in Griffon views. Let’s just say for the moment that the binding used in the textfield property is how you specify a binding from the UI to the model, while the binding on the label is how you specify on the other way around: from the model to the UI element.

We can’t run the application just now. We’re missing a few properties on the model and the definition of the search action on the controller. You’ll get a nasty runtime exception if you attempt running the application at this stage. Let’s continue with the Model, shown in Listing ALM-11.

Listing ALM-11: Full Model implementation

The Model contains three lists as expected. They will hold authors, books and the search results. There are also other properties needed for the bindings we saw. Each of the observable properties are annotated with @Bindable. This is a special annotation that serves as the entry point for an AST transformation. The compiler is instructed to generate special bytecode whenever it sees the @Bindable annotation on a class or property. It basically generates all the boilerplate code required to make a class observable, complete with firing PropertyChangeEvents whenever a property changes value.

The @Listener annotation is another handy AST transformation that generates a PropertyChangeListener around a closure or a closure field. In our case it turns out to be a private field found on the same class. Whenever the query property changes value the enabler listener will be called.

Filling up the Logic

We now turn our gaze to the Controller, the last member of the MVC group to be visited. We must define a single closure property: the search action. However, the controller must communicate with the view somehow, so we’ll require a reference to the model at the very least. The search mechanism can certainly be contained in the controller class alone, however I’ll take the opportunity to show you one more feature of Griffon: service classes.

Service classes in Griffon are similar to their Grails counterparts. They are treated as Singletons but do not require a transactional state. The reason for this is that Griffon does not depend on Spring at all at runtime. It is possible to use Spring with Griffon but you’ll need to install a plugin for that.

It is within a service that we’ll define the searching and querying algorithms needed for this application. Without further ado, type the following on your command prompt.

griffon create-service bookstore

This will create griffon-app/services/bookstoreclient/BookstoreService.groovy and related test classes. Now open that file and copy the contents of Listing ALM-12 in it.

Listing ALM-12: BookstoreService

There are three service methods on this class. The first two will be used to search each one of the domains given certain criteria stored in the model, precisely what the user typed in the textfield. This is thanks to the binding we defined on the view. There’s a method named withRest that we have not defined. This method is provided by the REST plugin and it’s the one responsible for executing REST calls. The contents of this method are bound to an instance of HTTPBuilder, another handy builder that provides a higher level API over Apache’s HTTPClient. The third method will be used to populate the initial data during application startup.

You’ll notice a pair of exotic calls when the model is updated. The golden rule of Swing is that a long running computation must be performed outside of the Event Dispatch Thread. This special thread is used by the UI toolkit to process any events that are related to painting. If the UI thread is busy with a long computation it won‘t be able to process any input from the UI. This is the main reason why Swing applications are usually regarded as slow or bad, because breaking this rule is fairly easy. A companion to this rule is that every access to a UI property, be it read or write, must be done inside the UI thread. This is why writing to the Model is done with a synchronous call inside the UI thread, because those model properties are bound to TableModels.

We can have a look at the controller now. It is in Listing ALM-13.

Listing ALM-13: Controller implementation

The Controller not only has a reference to the Model as we expected but also to a bookService instance. This service instance will be injected automatically by the Griffon runtime. We can observe the search action is finally implemented. Following the golden Swing rule, it calls the service outside of the UI thread (that’s what execOutside is for) then updates the model’s results property back inside the UI thread.

There’s another closure property on this class, onStartupEnd. This property is actually an event handler. Remember we spoke about an event bus? Well this is how you can react to events. Event handlers follow a naming convention, their names must start with ’on’ and the rest of the name should match the event they can handle. This particular event is triggered after all MVC groups have been instantiated. By the way, I should mention that as an application framework, Griffon defines an application lifecycle that every application shares. These are the phases

  • Initalize – configuration is read and plugins are initialized.
  • Startup – MVC groups are initialized.
  • Ready – called after all pending UI events have been consumed. Shows the main window afterwards.
  • Main – the application’s main loop.
  • Shutdown – called at any time. Instructs the application to quit.

One more step and we can run this puppy. Locate the Config.groovy file inside griffon-app/conf. We must tweak a configuration flag to enable the REST methods on a service. By default, the REST plugin enables its metamethods on controller classes only, but because we use them on a service we must alter the setting. This is as simple as making sure that Config.groovy has the following line:

griffon.rest.injectInto = ['controller', 'service']

Voilá! Run the application once more. You should be able to see the list of authors and books. You should also be able to query authors by name and lastname.

We must stop here but hey, that was quite the whirlwind ride, wasn’t it?

Conclusion

Grails is by far the best option to build web applications in the JVM using features that can be found in popular Java libraries and features only found in the Groovy language. Griffon follows in its steps and aims to provide the same productivity gains but in the desktop space. Both can be combined to build applications that touch desktop and server with the same approach to development: one of high productivity and making programming fun again.

REST APIs are but one of the many options you can pick to have both sides collaborate with each other. Grails has other plugins that can expose domain objects and services via SOAP or remoting. Guess what, Griffon has plugins that can consume SOAP and remoting too.

I hope you have enjoyed the quick trip. Keep on Groovying!


About the Author

Andres is a Java/Groovy developer with more than 10 years of experience in software design and development. He has been involved in web and desktop application development since the early days of Java. He is a true believer in open source and has participated on popular projects like Groovy, Griffon, and DbUnit, as well as starting his own projects (Json-lib, EZMorph, GraphicsBuilder, JideBuilder). Andres is a founding member of the Griffon framework. He maintains a blog at http://jroller.com/aalmiray and tweets regularly on Groovy and Griffon (@aalmiray)


UPDATE: There were a couple of errors in the code snippets which have been corrected already.
  1. The Book domain class had a property named belongsto (lowercase 't'), but in reality it must be belongsTo (capital case 'T').
  2. I cannot be 100% sure but apparently recent versions of Grails require a matching JSP file for an action that simply did a redirection (probably combined with the particular UrlMappings of this application). Decided to remove the redirect from index to list and specif a value for the defaultAction on each controller.
  3. The GlazedLists plugin verison 0.8 had a bug in the constructor of the DefaultTableFormat class. This has been fixed in version 0.8.2
Andres Almiray

About Andres Almiray

Andres is a Java/Groovy developer and a Java Champion with more than 20 years of experience in software design and development. He has been involved in web and desktop application development since the early days of Java. Andres is a true believer in open source and has participated on popular projects like Groovy, Griffon, and DbUnit, as well as starting his own projects (Json-lib, EZMorph, GraphicsBuilder, JideBuilder). Founding member of the Griffon framework and Hackergarten community event. https://ch.linkedin.com/in/aalmiray

Why Attend the NFJS Tour?

  • » Cutting-Edge Technologies
  • » Agile Practices
  • » Peer Exchange

Current Topics:

  • Languages on the JVM: Scala, Groovy, Clojure
  • Enterprise Java
  • Core Java, Java 8
  • Agility
  • Testing: Geb, Spock, Easyb
  • REST
  • NoSQL: MongoDB, Cassandra
  • Hadoop
  • Spring 4
  • Cloud
  • Automation Tools: Gradle, Git, Jenkins, Sonar
  • HTML5, CSS3, AngularJS, jQuery, Usability
  • Mobile Apps - iPhone and Android
  • More...
Learn More »