10 August 2009
Building a Grails App in ~40 hrs (part 3)
In part 1 and part 2 of this series we introduced a challenge to build a reasonably non-trivial application in just a week. We have decided on Grails as the primary technology framework, and once we have a prototype working, we hope to deploy it to a cloud computing platform like Google’s AppEngine or Amazon’s Elastic Compute Cloud (EC2).
This longish post will primarily concern itself with some initial setup and design and the inclusion and integration of JSecurity into our application.
The Vision
We know that our application is going to be a simple task management system called ‘twodo‘– the intent of which is to allow the user to balance their work to-do’s with their personal to-do’s.
When my partner (aka Stakeholder) and I were discussing the application, he drew a simple diagram on a napkin that showed two lists presented side-by-side, the leftmost list for work tasks and the rightmost list for personal tasks. This seemed as good of a place to start with regard to general design, and this simple vision drove much of the basic site layout and internal constructs.
After a few minutes of noodling, the following simple high-level sitemap emerged and seemed reasonable:

Basic Setup
I created a new project (grails create-app blogtwodo) and configured my conf/DataSource.groovy to point at a locally running MySql instance with a newly created/empty ‘twodo’ database.
Basic Domain Model
As stated above, the basic function of the app is to manage two sets of task lists– one list for work, and one list for personal tasks. To this end I created a Profile domain class and a Task domain class.
The Profile will represent a registered user within the system, and will contain the account information and some basic configuration settings. The Profile will also hold a reference to the lists of Tasks, one list for each task type.
package com.alterlabs.twodo class Profile extends Base { String username String email String firstName String lastName int hoursInWorkWeek = 40 int hoursInPersonalWeek = 10 static hasMany = [workTasks:Task, personalTasks:Task] static constraints = { username(unique:true, size:5..15) email(email:true,nullable:false,blank:false,unique:true) firstName(nullable:true) lastName(nullable:true) } }
Similarly the Task class holds the task details, as well as a reference back to its parent Profile:
package com.alterlabs.twodo class Task extends Base { String description Date completionDate int estimate = 0 // minutes to complete task static belongsTo = Profile }
You may have noticed that the Task and Profile Domain classes inherit from a Base class. From past experience I have found it handy to have a simple Abstract Base Class from which all Domain classes inherit. For now we will use this Base class to enable auto-timestamping for our Domain classes:
package com.alterlabs.twodo abstract class Base { Date dateCreated // grails will auto timestamp Date lastUpdated // grails will auto timestamp static constraints = { dateCreated(editable:false) lastUpdated(editable:false) } }
I figured the above Domain objects were good enough to start with, and I could worry about constraints, etc. as the design progressed. I used Grails to generate the controllers and scaffolding (grails generate-all), fired up the dev server and verified my efforts via the browser. Navigating to http://localhost:8080/blogtwodo presented me the expected default Grails welcome screen and listed the Controllers for my Task and Profile classes. (These generated CRUD interfaces are handy for initial testing and once the app progresses in functionality we can remove them.)
So far so good.
Security Setup
Our application does not have any exceptional security requirements– we want users to be able to able to start using the system with a minimum of fuss immediately after a simple registration process. We won’t need any roles for this application– users are either anonymous, or registered. I have used the Grails JSecurity Plugin on past projects and knew it would be more than sufficient for our needs.
To get the ball rolling I followed the steps listed in the JSecurity Quick Start Guide to install the plugin and autogenerate some basic underlying constructs.
The quick start procedure creates a bunch of Jsec-prefixed Domain classes and an AuthController into the default package. I like things a bit more organized so I moved both the Domain classes and the Controller into a com.alterlabs.sec package. As a result of moving these classes we also need to add an import statement to the generated grails-app/realms/JsecDbRealm.groovy file (import com.alterlabs.sec.*) so that it can find the various needed JSecurity objects at runtime.
As per the quick start guide I created a simple conf/SecurityFilters.groovy file. The following code requires authorization to access anything other than the (yet to be created) public controller:
import com.at.sec.* class SecurityFilters { def filters = { // Ensure that all controllers and actions require an authenticated user, // except for the "public" controller auth(controller: "*", action: "*") { before = { // Exclude the "public" controller. if (controllerName == "public" || controllerName == null) {return true} // This just means that the user must be authenticated. He does // not need any particular role or permission accessControl { true } } } } }
For purposes of initial testing, I also added some temporary code to the BootStrap.groovy file that creates a hardcoded user (user ‘don’, password ‘twodo’). We will remove this code later as the application progresses.
import org.jsecurity.crypto.hash.Sha1Hash import com.alterlabs.sec.* class BootStrap { def init = { servletContext -> // TODO: Remove this stuff later def role = new JsecRole(name: "User").save() def user = new JsecUser(username: "don", passwordHash: new Sha1Hash("twodo").toHex()).save() new JsecUserRoleRel(user: user, role: role).save() } def destroy = { } }
To test it I fired up the app and was presented the generated list of Controllers, including an additional entry for the newly added com.alterlabs.sec.AuthController. Clicking on the Profile controller presents the Quick Start generated login page, and I can successfully login with the ‘don’ account created during the BootStrapping. Awesome.
Login and Registration UI
Recall that we want to allow for a simple registration process. Once a user has registered he/she should be able to login and start using the application. Right or wrong, I find that many agile based development efforts derive requirements from the imagined user interface, and that is the direction we will take here. I envisioned another napkin with as screen that presents the user with two basic panels, one for new user registration, one for existing users to login:

Anonymous users will only have access to the public space, and once authenticated they will be sent to a home controller, where we eventually hope to add the meat of our application logic and content. With that in mind I next created both a public and home controller (grails create-controller)
I replaced the default view/index.gsp page that Grails provides with a few simple lines that uses the JSecurity taglibs to redirect to either the home controller or the public controller depending on whether the user is authenticted.
${ response.sendRedirect("/blogtwodo/home") } ${ response.sendRedirect("/blogtwodo/public") }
Lets create a crude page, as per our napkin above that will allow the user to either register or login. We want this page to be publicly accessible so this was created in views/public/index.gsp:
<!-- #login_or_register {margin:10px;width:500px;} #login_box {border:#006DBA 1px solid;float:left;width:220px;padding: 10px;} #register_box {border:#006DBA 1px solid;float:right;width:220px;padding:10px;} --> <div class="errors"></div> <h1>Welcome to TwoDo!</h1> Register now to get started, or login if you have an account <div id="login_or_register"> <div id="login_box"> <label for="username">Username:</label> <input id="username" name="username" size="20" type="text" /> <label for="password">Password:</label> <input name="password" size="20" type="password" /> <button>Login</button></div> <div id="register_box"> <label for="username">Username:</label> <span class="value ${hasErrors(bean:profileInstance,field:'username','errors')}"> <input id="username" name="username" size="20" type="text" value="${fieldValue(bean:profileInstance,field:'username')}" /> </span> <label for="email">Email:</label> <span class="value ${hasErrors(bean:profileInstance,field:'email','errors')}"> <input id="email" name="email" size="20" type="text" value="${fieldValue(bean:profileInstance,field:'email')}" /> </span> <label for="password">Password:</label> <input name="password" size="20" type="password" /> <label for="vpassword">Confirm:</label> <input name="vpassword" size="20" type="password" /> <button>Register</button></div> </div>
Pointing our browser tohttp://localhost:8080/blogtwodo renders the above (thanks to our redirect) as shown below:

OK, so we won’t win any design awards. It’s ugly but it will serve for now– we will worry about the aesthetics later. Basically we have a page with two forms that submit to actions within two different controllers.
The login form is trivial– it’s simply configured to submit to the existing signIn action within the AuthController that was created as part of the JSecurity Quick Start. Once again easily tested via the browser.
The first thing we need to do is provide the association between the JSecurity constructs and our own Profile object. To do this we simply add an association to the JsecUserRoleRel object to our Profile. The JsecUserRoleRel holds the relationship between a JsecUser and a JsecRole and has references to both– which in turn gives our Profile object access to both. (Note: Yeah I know I said we had no need of formal roles in our application, but it seems silly to paint ourselves into a corner.)
After adding this association to the Profile class now looks like this:
package com.alterlabs.twodo import com.alterlabs.sec.JsecUserRoleRel class Profile extends Base { ... JsecUserRoleRel principle ... }
The second form in the above GSP submits to the save action of the public controller for registration. The registration process needs to take care of the following:
- Create and persist a new JSecurity
JsecUserobject - Create a new
Profileobject - Associate the
JSecUserwith theProfileand persist - Log the new user in
- Send the authenticated user on to the home page
Our public controller now looks like this:
package com.alterlabs.twodo import com.alterlabs.sec.* import org.jsecurity.crypto.hash.Sha1Hash class PublicController { def securityService def index = { } def save = { def profileInstance = new Profile(params) def role = JsecRole.findByName("User") def ju = new JsecUser(username: profileInstance.username, passwordHash: new Sha1Hash(params.password).toHex()).save() profileInstance.principle = new JsecUserRoleRel(user: ju, role: role).save() if(!profileInstance.hasErrors() && profileInstance.save()) { flash.message = "Profile ${profileInstance.id} created" // OK, lets log them in and take them to their home page... try { securityService.authenticate(params.username, params.password) redirect(controller:'home',action:'index') } catch (Exception ex){ // Authentication failed flash.message = message(code: "login.failed") def m = [ username: params.username ] redirect(action: 'index', params: m) } } else { render(view:'index',model:[profileInstance:profileInstance]) } } }
NOTE: I have encapsulated the authentication logic from the JSecurity Quick Start AuthController into a SecurityService, which is called on line 21 above. (This is left as an exercise to the reader :) )
Once again we can verify our progress by using a browser to explicitly try out the registration process (and in this case I also created a few unit tests.)
Next Steps
OK, not a bad start. At this stage I had spent perhaps 1-2 hours on the effort, with a decent amount to show for it. We have created our core Domain objects, wired in security and have created the self registration process. The next post we will look at designing the View layouts, refining the User Interface, and adding some of the core functionality into the mix.
Technorati Tags: agile, grails, groovy, jsecurity, software development
7 Comments currently posted.
Olivier Gourment says:
don says:
@Oliver…that was just a bit of artistic drama :) I have actually successfully deployed it to both GAE and EC2 and will provide the details as to what level of effort was required in subsequent posts. But, you are fundamentally correct– EC2 was a _lot_ less painful than GAE.. that being said GAE is free and EC2 is not….
ALTERthought Blogs » Grails App in ~40 hrs (part 4) says:
[...] last post covered the kickoff to the ‘twodo‘ application– where we created our Grails [...]
kp says:
I don’t understand your use of JsecUserRoleRel in the Profile object. Isn’t JsecUserRoleRel a “many-to-many” between user and role?
don says:
@kp… The JsecUserRoleRel is a construct created by the Quick Start process that holds which Role(s) a User belongs to. While there are technically no constraints on making in 1-M, M-M, etc, for our app we only need user to belong to exactly one Role… (in fact we don’t really even need a Role right now.)
Because we have no need for a Role, I could have simply had the Profile object directly reference the JsecUser object but I thought I would allow for a little leeway for any future expansion by holding a reference to the JsecUserRoleRel, which gets us access to both the JsecUser and the JsecRole object (should we ever need the Role for later stuff)
Hope this makes sense.
Rafał says:
Hi, nice job!
Is there any chance to download your code?
ALTERthought Blogs » Grails App in ~40 hrs (part 5) says:
[...] Part 3: The first ‘technical’ post. JSecurity setup, initial Domain object created. [...]


Nice post!
Just a comment about “we hope to deploy it to a cloud computing platform like Google’s AppEngine “. AppEngine has unfortunately so many limitations that most plugins don’t work, you have to use gorm-jpa (or jdo) and constraints won’t work… EC2 looks like a safer bet, considering the route you have taken so far.
Cheers