In this post, I will present one of my newest applications that I built using Grails and jQuery Mobile frameworks. I hope to present this as a more real world example of using Grails along with using jQuery Mobile for the client side responsible design that can scale to any sized client (phone, tablet, desktop, etc). The jQuery Mobile framework is an excellent library that simplifies that approach dramatically.
The application I am presenting here is a Budget Analyzer application. The problem with most of the financial applications and budget aware applications such as Mint.com is that they do not provide a forward looking statement. One of the things I like to know when dealing with accounts is how much money would be in my account in two weeks based on upcoming bills and budgets. This is very handy when making a payment and knowing whether you have a certain amount in your account so you do not hit any thresholds. Although forward looking balances are mere estimates, it gives you an easy way to see what bills are approaching and their approximate impact to the bottom line.
The first part of this application is the server-side stack composing of Grails. I used the latest Grails 2.2 build for this application. If you do not have Grails installed, the easiest way to install and manage the various instances of Grails on your system is the excellent GVM (Groovy enVironment Manager) Tool. I would show how to install it, but it is so simple that just visiting the site and following the couple steps is all you need.
The backend of the application is built using standard Domain objects in Grails. Domain objects in Grails are so simple its ridiculous. If you have ever built a persistence layer in Java using something like JPA or Hibernate, you know how much crud there is in defining properties, annotations (or XML files), getters/setters, proper equals/hashCode implementations, etc, not to mention trying to recall the countless annotations you need for mapping the tables, columns, joins, cascading, caching, etc. Grails provides suitable defaults in most cases following its convention over configuration principle. Combined with Groovy’s automatic getter/setter provisioning, you can create a simple Transaction class in a few lines.
class Transaction { String name int recurrence double amount Date startDate } |
That class is a valid Grails domain object that you could easily invoke Transaction.list()
to fetch all saved transactions. As I said, ridiculously easy.
Domain objects may also contain helper methods to add domain-specific business logic. Note that the business logic should be independent of any other beans or objects and should be self contained of any dependencies. One thing to keep in mind is that Grails may confuse helper methods as domain properties so you may have to add the fields to the transient declarations (ie: static transients = ['expired']
. See my domain classes for an example of how I use domain objects.
Since I was using domain objects, I needed a place to persist them. Grails provides various persistence capabilities on its GORM platform including Hibernate and NoSQL approaches. My domain model is very simple, so a traditional Hibernate SQL database worked fine. For development I used the in-memory H2 database. This works great especially when domain models are iterated upon so you don’t have to worry about merge conflicts, database destruction, etc. I used the BootStrap.groovy startup file in Grails to initialize the database with a set of transactions. For production, I used a standard MySQL installation. See DataSource.groovy for more information.
The next layer of the server-side architecture is the Grails service layer. Grails services are simplified Spring managed bean built on autowiring. They provide the business logic of the platform above the UI layer and controllers as well as shared code between controllers. Services may exist per domain class to provide functions to query the domain class or they may contain more generalized business logic that utilizes several domain classes. The organization of the services depends on your particular use cases. I prefer services to contain the queries and persists rather than within controllers so that the services act as the in-between layer. Further, services may be easily injected into any bean (controllers, other services, jobs, etc). As such, they are great at abstracting the queries from each of those components. The TransactionService.groovy is an excellent example of this. It provides business logic to rollup transactions into specific transaction items. It also provides a few different queries. However, in order to simplify the query cache and persistence, I use Transaction.list()
in both queries and then perform the query in Groovy code. Transactions in my system are only composed of a 10-30 instances, so performing a list each time is no problem.
Above the service tier is the standard controller tier used to interact with the views. Controllers provide automatic routing by a convention over configuration rule. In this application, there are multiple types of transactions: bills, budgets, deposits, etc. They are each transactions with their own impact to the underlying balance. As they are each transactions, they all share the same semantics for the views. The easiest way to do this with controllers is by passing a type
query parameter as part of the path. However, in order to be more RESTful, I put the type
parameter as part of the path and injected it as a query param into the controller via UrlMappings.groovy. The rule /transaction/$type?/$action?/$id?
accomplishes this by associating the type as a query path parameter along with the id. URL mappings in Grails are simple and effective at creating generic controllers with RESTful linking. Further, all link creation in Grails (g:link
, createLink
, etc) properly recreate the links based on the given controller, action, and parameters. This allows the URL mapping to be changed in a single location without having to update all other links in the application. Other than that, the controllers are fairly straightforward and perform UI logic to setup the UI model that gets passed into the views. One other minor note is the usage of the static allowedMethods
fields to ensure the actions are handled in only certain HTTP transactions. This is especially helpful when dealing with the RESTful style linking.
The controllers utilize the views for actual rendering. The views are fairly straightforward. In this application, there are two layouts that provide the frame around the page content: main and dialog. The main layout is the application frame around the pages. The dialog layout is used to provide a jQuery Mobile dialog frame. Both layouts provide the associated header sections that provide the meta data, including iOS headers for supporting a home screen web application, icon, and splash screen. They also provide the assets for javascript and CSS. Note that I could have used the new Grails resource plugin to inject the CSS automatically. However, as I only have a few assets most of which are on a CDN via jQuery, it was simpler to just inject in the page directly. I highly recommend the resources plugin for anything more complex.
The main layout uses two features to allow the page to pass data to the layout. The first is content sections. The main layout contains two distinct content sections that page can implement: buttons and content. The buttons provide the buttons that appear in the page header (think iOS). The content is the actual page content between the header and footer. This is achieved in the layout via the <g:pageProperty name="page.content" />
tag. In the actual page, such as the main overview page, you simply include a <content tag="content">
tag. The layout can then choose where to place each content section within its frame.
The second feature is page properties. For example, the main layout defines the common footer, but in some templates, the footer is not desired. The page can use standard HTML5 data attributes to notify the layout accordingly. For example, the create transaction template disables the footer by specifying <body data-nofooter="true">
on the main body tag. The layout can retrieve that property as an expression such as <g:if test="${pageProperty(name:'body.data-nofooter') != 'true'}">
. Note that the values are expressed as strings. Both of these features make layouts much more powerful as well as more effective at being generic.
The only other interesting aspect of the views is using sub-templates to share code between page templates. The create and edit transaction templates do this as they each provide the same form elements.
The next part of the stack is jobs. Jobs are Grails components that run periodically (either through a timeout or cron definition) that allow the application to perform background processing. Jobs are provided by the Grails Quartz plugin. Note that while 1.0-RC5 is currently out as of this post, I had issues in getting it properly running. As such, I am using compile "org.grails.plugins:quartz:0.4.2"
as my dependency. The Quartz plugin provides a Grails job component that allows the full Spring managed bean autowiring injection (similar to controllers and services). To create a new job, invoke the grails create-job
command. The jobs appear in the jobs folder. The easiest sample is a simple timeout and execution block:
class MyJob { def timeout = 60000L; // 1 minute def execute() { println "Invoke me every minute!" } } |
In this application, the BalanceRetrieveJob is used to retrieve the latest balance every hour. The job injects a balance loader automatically. The loader is just an interface that a specific implementation can be provided as defined in the Spring resources.groovy file.
Another aspect of the job is sending emails whenever a threshold is exceeded. The mail plugin (compile "org.grails.plugins:mail:1.0.1"
along with a custom repository mavenRepo "http://download.java.net/maven/2/"
) provides a very simple method for sending emails using a custom Groovy DSL. Just setup the appropriate configuration in Config.groovy to get started.
The server side aspect was extremely simple to build and the fact that it only takes a few days to construct is a testimony of the power you can build in an application leveraging Grails.
But one more thing…
I needed a place to host my newly created application so that I could load it on my iPhone and iPad as a home screen web application. After first trying to use Google AppEngine and its annoying restrictions followed by my own LAMP domain which did not have sufficient resources to run Java, I decided to use VMWare’s Cloud Foundry. I already had an account and since it is still in beta it was free to use. If you have not tried Cloud Foundry yet and are writing Grails applications, I highly recommend it! You are probably thinking I had to spend a bunch of time setting things up, changing around code, changing the domain model, etc. If so, you are heavily mistaken. All I needed to do was include the Cloud Foundry plugin (compile "org.grails.plugins:cloud-foundry:1.2.3"
and associated Maven repositories) and then run grails prod cf-push
. The plugin took care of the rest including configuring a MySQL instance in the cloud and re-configuring the data source configuration accordingly. Grails took care of auto-creating the schema, the bootstrap took care of initializing the transactions, and the job took care of downloading the initial balance on startup. Once I was ready to re-deploy, I simply had to run grails prod cf-update
. It was so extremely easy I am actually annoyed I started with my other options first. For more information including other minor setup steps, see the One-Step Deployment Guide.
The biggest aspect that impressed me with Cloud Foundry was speed and performance. When I ran on App Engine (which required all sorts of other annoying changes and setup and was no where near as simple), it took forever to load at times. When I ran in my domain, it was horrific. When I run in Cloud Foundry, it renders pages in milliseconds making the experience awesome.
Stay tuned for the next series on using jQuery Mobile and Phantom JS.
Read the next article on Client Side via jQuery Mobile.