Friday, October 8, 2010

Grails controllers and command objects

Hi there folks!

This is one of the days that come from time to time when one feels as if a lightning struck went down in extreme proximity :)

Well, I've been asked to implement a functionality, a very simple one. Take 2 parameters from the URL, verify if all of them are given, check if one is a valid identifier of an existing entry in the database and if so set a given property of that domain object to the value of the other parameter. Let's see how this might be done:
class CarController {
def index = { ... }

def setCarAvailability = {
def car = Car.get(params.id)
if (car && params.available) {
car.avaiable = params.available
car.save(flush: true)
redirect action: 'index'
} else {
flash.message = "Error: either no valid car id, available not given or saving failed"
redirect action: 'index'
}
}
}

Pretty easy, right?

Now somebody please tell me what's wrong with this picture?

At first, if this is a simple application with one or two controllers having one or two actions this seems completely acceptable, right? But what if there are 5 or 10 actions in 20 different controllers? The answer is simple: UNMAINTAINABLE RAVIOLI CODE!!!

To counteract this I've came across an idea of making command objects not just dumb value placeholders with validation capabilities but to actually implement the command as it should be (given its proud name).

So at the end of the day this is how I'd really code this:
class CarController {
def index = { ... }

def setCarAvailability = {
SetCarAvailabilityCommand command ->

if (command.validate()) {
command.execute()
redirect action: 'index'
} else {
flash.message =
command.errors.allErrors.collect { error ->
error -> error.field
}.join(", ")
redirect action: 'index'
}
}
}

class SetCarAvailabilityCommand {
Car car
Boolean available

static constraints = {
car nullable: false, validator: { it?.attached }
available blank: false, required: false
}

def execute() {
car.available = available
car.save(flush: true)
}
}
How about that, ha? Nice separation of concerns (actual entity that does the job separated from controller that should only care about controlling what should go next), automatic parameter validation, clean naming and if you put those two into the same file then even automatic reloading works!

The key here is that the parameter must be named "car.id" for this to work. This way the automatic binding will find the actual Car instance and put it into our command object automagically.
  <g:form action="setCarAvailability">
<g:textField name="car.id"/>
<g:checkBox name="available"/>
<br/><br/>
<g:submitButton name="action" />
</g:form>

You might have noticed the funny-looking validator for car field. This just checks that the Car instance came from the database. If one would be to specify an id that does not exists it'll fail.

Another neat thing is that all of the commands have similar interface so generally you can create a helper method that will get some parameters (where to redirect after failure for example) and have every single action be actually a one-liner! And remember: since this is a dynamic language with duck typing it does not have to be a java interface strictly speaking! Commands just have to talk and walk like commands :)

Oh, and if you'd like to delegate some code to service I rush to say that dependency injection works as expected with command objects so no worries :)

I would not be myself if a ready-to-use example would not be here :)

I wish you all some nice and well separated code!

Wednesday, October 6, 2010

Grails EasyB and Selenium

Hi there,

having EasyB in your grails project is handy. There's no question about it. However combining it with Selenium RC adds a whole new flavor to the mixture!

Let's examine a step-by-step scenario on how to include both grails-easyb and selenium-rc in a brand new application, then let's create a simple home controller with one action and let's test it using the potent mix of behaviors and remote test execution :)

Step 1: Create a new application

This one is extremely easy:
grails create-app example
Step 2: Install the grails-easyb plugin.

This one is extremely easy to:
grails install-plugin easyb
Step 3: Install selenium rc.

Well, there's 4 things to it.
a) download the Selenium RC package
b) extract the driver (selenium-java-client-driver.jar) into the lib folder of our example application
c) extract the Selenium RC server (the whole folder selenium-server-1.0.3)
d) run Selenium RC server
java -jar selenium-server.jar
Step 4: Create the home controller.

As you might have already guessed:
grails create-controller home
Step 5: Add some meat to the index action.

Let's change the default empty implementation of our index action into
[ message: "Hello, world!" ]
Step 6: Create a functional (yes! functional test at last!) in test/functional (this folder does not exist at first so you have to create it yourself). I'll call it MyFirstFunctional.story
import com.thoughtworks.selenium.*

before "start selenium", {
given "selenium is up and running", {
selenium = new DefaultSelenium(
"localhost", 4444, "*iexplore",
"http://localhost:8080/example/"
)
selenium.start()
}
}

scenario "Will show 'hello, world!' message", {
when "home/index opens", {
selenium.open("home/index")
}

then "the text 'Hello, world! appears on the page", {
selenium.isTextPresent("Hello, world!")
}
}

after "stop selenium", {
then "selenium should be shutdown", {
selenium.stop()
}
}
WARNING: you might naturally want to move the "after" section right below the "before" section. DON'T EVER DO THAT! EasyB test segments are executed in the order they have been declared so if you do that selenium will get stopped before any scenario can be executed!

Step 7: Run the test and see it fail (we have no view just yet)
grails test-app functional:easyb
Step 8: Create the view (/views/home/index.gsp).
Message: ${message}
Step 9: Execute the test and see it pass:
grails test-app functional:easyb

I hope this will cut down the time you spent implementing easyb- and selenium-enabled functional tests clearing any misunderstandings you might have after reading online docs (they suck big time!).

Do I hear "That's a lot of work, man!"??? Well if you're really that lazy grab the ready-to-run package here and enjoy the rest of the evening :)

Have fun!

Tuesday, October 5, 2010

Grails 1.3.5 Released!

Hi there all you Grails geeks!

Yesterday Grails 1.3.5 was released :) With one small addition from me:

class HomeController {

def index = { }

def save = { LoginCommand login ->
println "login.username: ${login.username}"
println "login.password: ${login.password}"
println "comment.text: ${comment.text}"

redirect action: "index"
}
}

class LoginCommand {
String username
String password
}

This is pretty basic stuff, right? We're creating a command object, giving it as the closure parameter and values from the form (named "username" and "password" get deserialized into this object.
What was missing though is the fact that not all of the form parameters need to be bound to the same command object. In fact there are times when more than one object allows for better re-use and/or separation of concerns.
The elements that need to be deserialized into multiple command objects should be prefixed with command type (by convention).

So "LoginCommand" becomes "login.", "CommentCommand" becomes "comment." and for example "VeryLongAndComplexCommand" becomes "very-long-and-complex.".
  <g:form action="save">
<label for="login.username">Username: <g:textField name="login.username"/><br/>
<label for="login.password">Password: </label>
<g:textField name="login.password"/><br/>
<label for="comment.text">Comment</label>
<g:textField name="comment.text"/><br/>
<br/>
<input type="submit"/>
</g:form>
class HomeController {

def index = { }

def save = { LoginCommand login, CommentCommand comment ->
println "login.username: ${login.username}"
println "login.password: ${login.password}"
println "comment.text: ${comment.text}"

redirect action: "index"
}
}

class LoginCommand {
String username
String password
}

class CommentCommand {
String text
}

I know this example is lame, useless and all that but hey - it's just an example :D

The actual prefix for commands is taken from the class name - not the parameter name! Bear that in mind!

I hope you'll like it!

Monday, October 4, 2010

Grails console and LDAP via JNDI

Hi folks!

I've spent over 6 hours today fiddling with LDAP from Grails console and let me tell you it's been a huuuuge disappointment! Let me explain...

I'm using LDAP (it's Active Directory but this is not really relevant) to store users with their attributes. To perform authentication other than usually (having a user that has right to read the password attribute and then query LDAP once a user logs in, verify the password, etc.) I need to login in using credentials provided by user on login page.

With that the use of grails-springsecurity-ldap is pretty much toasted and a new implementation is needed. I don't want to get into any details of spring security plugin, because it makes no sense in this context. What makes a huge difference is the way we interact with LDAP in Java.


import javax.naming.*
import javax.naming.ldap.*

try {
LdapContext context = new InitialLdapContext((Hashtable) [
(Context.INITIAL_CONTEXT_FACTORY): "com.sun.jndi.ldap.LdapCtxFactory",
(Context.PROVIDER_URL) : "ldap://ldap.localdomain.com",
(Context.SECURITY_AUTHENTICATION): "simple",
(Context.SECURITY_PRINCIPAL) : "DOMAIN\\invalid",
(Context.SECURITY_CREDENTIALS) : "invalid",
(Context.REFERRAL) : "follow",
(Context.BATCHSIZE) : "30"
], (Control[]) []);
println "Logged in!"
} catch (AuthenticationException e) {
println "NOT lOGGED IN"
}


The assumption here is of course that "DOMAIN\invalid" either does not exist or has a password other than "invalid" :)

What one would expect from this piece of code is that it tries to create the initial context and since the credentials are wrong an AuthenticationException is being thrown thus the message "NOT LOGGED IN" should appear.

Well, in Groovy console (you know, the one that you get when you install Groovy on your PC) works exactly this way but Grails console works differently. It creates the initial context without problems and presents one with "Logged in!" message.

Why is this happening? Well the CLI support stuff overrides all protocol handlers (and I mean EVERY SINGLE ONE) with Spring's org.springframework.mock.jndi.SimpleNamingContext! Grouse!

What I ended up doing was to use the LdapClient directly (even though it's an implementation detail it gave me all the methods I needed) and life is (sort of) good again...

Check the bug report here.

Wednesday, September 1, 2010

Same name - different projects...

Hi there!

Today I've faced a serious problem: branchy development in Grails. Sounds easy, right? Well... Let's examine this a little bit.

Grails store files in 4 different locations:

  1. The folder where you've unzipped the distro (GRAILS_HOME)

  2. The project's folder

  3. The project's "target" folder

  4. User's home/.grails/{version} folder

The problem is in the last one. What's bad about it while doing branchy development is that there's more than one application with the same name but different version. That causes all kind of issues ranging from random build errors, no auto-reload of artefacts to unexpected application behavior.

As usually with Grails there's an ultra-easy way of fixing this problem :) Here's the content of my grails.bat that does the trick:


@echo off

set GRAILS_HOME=C:/grails-1.3.4
set JAVA_OPTS=%JAVA_OPTS% -Divy.cache.dir=%CD%/target/libraries
set JAVA_OPTS=%JAVA_OPTS% -Dgrails.project.work.dir=target/work

%GRAILS_HOME%\bin\grails.bat %*


As you can see here everything is made project-specific. In "target/libraries" is the ivy cache (instead of home/.ivy2 which causes problems from time to time when working with other technologies such as JSF) and in "target/work" are the project's artifacts.

And live is gooooooooood again :)

Thursday, August 12, 2010

Grails,Teradata and TIME/TIMESTAMP fields

Hi there,

For a long, long time I've been searching for a solution to the incompatibility issue between Teradata server and Teradata JDBC driver in regard to TIME/TIMESTAMP fields. I've finally figured out what's the deal :)

Long story short the database has columns defined as TIME(0) and TIMESTAMP(0) which during updates from Grails (especially the lastUpdated field filled in automagically) causes a number of different errors to come back from the server (5404 for example).

The problem is that java.lang.Date instances are translated using a default precision (which is grater than zero) and the database server is dumb enough to throw an error and not truncate the incoming data.

Solution: update to the latest version of JDBC driver (tested with TeraJDBC 13.10.00.01) and add TSNANO=0,TNANO=0 to connection string and live is good again!

I hope you'll find this solution handy :)

And by all means: have fun!

Tuesday, August 10, 2010

Grails 1.3.4 Released!

Hi there all you Grails geeks!

Yesterday Grails 1.3.4 was released :) Finally some bugs (described in my previous post) were fixed along with one small addition from me.

If you had a domain class that had a generator of type "assigned" and wanted to mockDomain that class then all calls to "save" method were treated as updates. The reason for that was that the distinction was made on the value of "id" field which had to be assigned in case of the "assigned" generator.

So I've proposed a fix for that that'll make the mocked version of save be sensitive to the actual generator type and if it's the "assigned" generator then to act smart instead :)

I hope you'll like it!