This is the second installment of my What Grooves You? series of posts, this time discussing how to modularize your Grails application. While Grails does an awesome job of enforcing MVC once your application reaches a certain size, or you have multiple applications which may have shared components, you’re going to have to start thinking about how your going to modularize the reusable parts of your code.
I encountered this pretty quickly because the application I am working on is broken out into two distinct parts, a public facing web form for submitting data (the “Front End”) and a private back office application for managing those user submissions (the “Back End”). These two parts of the application (for compliance reasons) cannot run on the same internet facing system, and the “Back End” must only be available on the internal network. Of course, both of these applications are going to work with the same database and therefore the same Domain classes. It would be dangerous and tedious to try to keep the separate domain classes in each project synchronized with one another.
What won’t work
The RESTful JSON Service
My first thought was to deploy a 3rd application which would be internet visible and act as a proxy for all the database requests. I could then query that application with REST and handle a JSON payload which would be my domain object. This actually seemed pretty elegant since I wouldn’t have to actually share any code between the Front End and Back End applications and I still got a well defined object on either end. The problem of course is that all I get is the data for my domain class, and I don’t have access to any of the functionality that GORM gives me “for free”. I’d have to duplicate search functionality, limits, grouping, sorting, and all sorts of other querying tools in my service. That seemed like an awful lot of work for functionality that is offered by GORM and works very well!
Just JAR it man
The next obvious conclusion is to just toss my domain classes into a library JAR file and reference that library in both of my other applications. This way I actually have the whole domain class and access to the dynamic find methods and all that other good stuff. But, how do you package these? Do you compile the Groovy classes then package the .class files? Will the data source information have to be set for the domain class(es) in the JAR, or will the data source of the application referencing the library be used?
Now some more seasoned Java and Hibernate developers might simply laugh at that barrage of questions, but for me it presented a serious barrier to entry. Fortunately there is a better way.
Just plug it in!
It didn’t take me long to discover that putting my reusable code into a Grails Plugin was the best and most scalable approach. For the sake of demonstration I’m going to take you through an example comment submission and administration application, kinda like blog comments.
The plugin project
First, let’s go ahead and create our plugin project.
grails create-plugin Modular-DAL
Once you’ve got your shiny new plugin created, open it up with your favorite IDE (I use Spring Source Tool Suite) and add a new domain class that you’re going to be sharing.
grails create-domain-class com.nslms.modular.domain.Comment
Now we specify some properties for our new shared domain class.
Comment.groovy
package com.nslms.modular.domain
class Comment {
static constraints = {
name(blank:false)
email(blank:false)
comment(blank:false)
}
String name
String email
String website
String comment
Boolean isApproved = false
}
With our new shared domain class created, we want to package up our plugin so we can load it into the other projects which we’ll be creating in a moment.
grails package-plugin
That’s it, you’ve just created a (very small) module of your application which contains a shared domain class. This could, of course, contain any number of domain classes, controllers, or services, views, javascript, css, etc. that would be used by other parts of your application, or by other applications.
The Front End
Now, lets create an application which will serve as the “front end” or externally facing form for collecting data.
grails create-app Modular-FrontEnd
Then the very important part of installing the plugin we just created
grails install-plugin ../Modular-DAL/grails-modular-dal-0.1.zip
Because you can download the project I created, I’m not going to go into excruciating detail about the controller and view(s) I setup in my front end, but sufficed to say I am accessing the “Comment” domain class that is supplied by the Modular-DAL plugin project!
CommentsController.groovy (snippet)
import com.nslms.modular.domain.*
class CommentsController {
def index = { [comments: Comment.findAllByisApproved(true)] }
}
The result of the front end app should be a list of comments which are approved (by the backend) and a submission form to allow you to submit new comments. Kinda like this.
The Back End
Now we need to create the system which will allow you as the administrator to approve the comments submitted by the unwashed masses.
grails create-app Modular-BackEnd
And install the plugin with the shared domain class.
grails install-plugin ../Modular-DAL/grails-modular-dal-0.1.zip
Again because you can download the project I created, here’s just a snippet of the admin controller showing the juicy bits where we use the shared domain class
AdminController.groovy (snippet)
import com.nslms.modular.domain.*;
class AdminController {
def comments = { [comments: Comment.findAllByisApproved(false)] }
}
The back end app should have a list of all unapproved comments, and a method to approve them. Kinda like this.
Trying it out
Now if you’ve followed along and created your own controllers and views, or downloaded my basic project, you’re going to want to try running both the front end and back end at the same time, persisting data to a common datasource so that you can see the whole thing in action. If you just use the grails run-app command, you’ll find very quickly that you can only run one or the other project, but not both at the same time. This is because they’ll both be trying to run on the common Tomcat port (8080). To overcome this, and run both apps at the same time, try the following starting from the Modular-FrontEnd directory.
grails -Dserver.port=8081 run-app cd ../Modular-BackEnd grails -Dserver.port=8082 run-app
Now you should be able to access both applications at http://localhost:8081/FrontEnd and http://localhost:8082/BackEnd respectively.
Download The Project(s)
If you want to download the project(s) and follow along, fire up your favorite subversion client and export everything at svn://linode.nslms.com/blog/grails/Modular or download it here. A couple things to note if you’re grabbing my project, it’s currently setup to use a MySQL database named “modular” running on the same system as the application. If you don’t already have MySQL setup, give XAMPP a look to get you started quickly. Also, I didn’t include the JDBC driver, go fetch it here and drop it into the “lib” directory of both the FrontEnd and BackEnd applications. Lastly, these projects are all written with Grails 1.2.1 so you’ll have to be using 1.2.1 or newer.
* UPDATE: The example apps have a new home..
Grab the projects at
git clone git://ec2.nslms.com/grails/blog_example_modular
Pingback: Modularizando tu aplicación Grails: clases del dominio (inglés) - Observatorio de Grails
Pingback: What's a plugin-oriented architecture? | SpringSource Team Blog
Pingback: An Army of Solipsists » Blog Archive » This Week in Grails (2011-12)
Pingback: Grails cette semaine (2011-12) – Traduction de l’article original
Pingback: How to implement a “remote” Domain? | PHP Developer Resource