Monday, February 8, 2010

Free Book on Grails

Three years ago, when I first began developing with Grails, I benefited from a book by Jason Rudolph called "Getting Started with Grails" The book was well written, short, and available as a free PDF. I recommended it to everyone interested in Grails. But, as Grails rapidly improved, the book began to become outdated.

No longer.

Jason Rudolph teamed up with Scott Davis (author of "Groovy Recipes") to update the book. It now covers Grails 1.2 and, once again, I highly recommend it.
You can download the book from:
http://www.infoq.com/minibooks/grails-getting-started
But note that InfoQ will ask you to register with their site before you can download the PDF. But it is well worth it as InfoQ is a great site with lots of technical information, in form of articles and videos, on application development.

Friday, February 5, 2010

Comment on IE

Half my work is creating Web solutions for my clients.
The other half of my work is getting it to work on Internet Explorer....

Real World Observation about Grails

In the past 3 years I've developed 7 Grails applications for a variety of customers. And I have to make an observation: Maintaining Grails applications is a breeze. It is far more easy than with any other development platform I've used. I've had to revisit Java applications that I had written. But it always takes me a while to figure out the design strategies. For instance: what MVC pattern did I use?

With Grails applications -- whether written by myself or not -- the MVC is always the same. The directory structure is always the same. It is fabulous being able, in Eclipse, to switch workspaces from one Grails project to another and have the structure look identical. They look so similar sometimes, when I come back from lunch or something, I have think "OK, what project is this."

This is an observation of the benefits of the Grails philosophy of "Convention over Configuration." This Grails feature provides a huge ROI when someone else can take over a Grails project and know where everything is. In fact, I benefited from this myself two years ago when I joined an existing Grails project team. The project was Circuit City's return system (I have some gift cards if anyone would like to buy them). The return system had been in production for a year and it was very complex (for example it had DB connections to Informix, Oracle, and DB2i.) Yet I was able to be productive in a very short time after joining the project. By the way, that Grails app is the only Grails app that I worked on that is no longer in use -- for obvious reasons....

Grails makes life easier.

Book Review: Grails: A Quick-Start Guide

It's been 5 months since my last post. I have dozens of times thought "I need to post this." But -- as I was working 12X7 on a major Grails-based order entry system and two other smaller Grails projects and authored 3 articles on Grails and delivered a multi-city seminar tour on Grails -- I simply didn't have the time. But things are slowing down now.

I recently burned through The Pragmatic Programmer's new book: "Grails: A Quick-Start Guide" by Dave Klein. I was impressed. Attendees to my seminars and Grails mentees usually ask "What's a good book to buy on Grails?" Well, "The Definitive Guide to Grails" authored by the creator of Grails, Graeme Rocher, is a bit too long for beginners. I think of it as the Grails bible. "Grails in Action," by Glen Smith and Peter Ledbrook, is fabulous as it is very written. But its 487 pages can be a bit daunting. "Grails: A Quick-Start Guide" is very approachable. It is just barely over 200 pages and it very succinctly written. It is now my recommended book for Grails beginners.

Tuesday, August 4, 2009

Dealing with Dates: Sorting Legacy Month/Day/Year Dates

Half of my Grails applications use legacy AS400 databases whose tables frequently have dates stored in 6-bytes in MMDDYY format. I map those columns to Date attributes in my domain classes using a custom Hibernate type class (written in Groovy) and everything is hunky-dory -- until I try to sort or filter values on those dates.
The solution is actually quite simple: use HSQL with an algorithm to convert the dates to YYMMDD.

The following looks for contract prices where August 14, 2009 is between the MMDDYY begin and expire dates:


def query =
ContractPrice.executeQuery(
"""FROM ContractPrice cp WHERE
? BETWEEN
MOD((cp.beginDate * 10000.01), 1000000)
AND
MOD((cp.expireDate * 10000.01), 1000000)
""",
[90814],
[max:params.max.toInteger(),
offset:params.offset.toInteger(),
sort:params.sort])


The trick is an old RPG programmers trick of multiplying the MDY date by 10000.01.
Note that the query will be fairly slow as it will have to do a table scan. But what my applications normally do is use precedes the date math with a predicate on a column that performs well with the query optimizer.

Saturday, July 11, 2009

Calling an RPG program from Groovy

I've been integrating Java applications with AS400/iSeries/Systemi RPG programs for over ten years. I've covered it in my book (Java Application Strategies for the iSeries) as well as in many of my articles. Calling RPG from Java can be complex. There are 4 or so options but I've been fairly emphatic about using JDBC callable statements as it is the simplest approach. To do that you need to create a stored produce "wrapper" for the RPG. But the Java code still can be quite verbose. Not so with Groovy.

The following shows how easy it is to call an RPG from Groovy. Note that this particular RPG returns information via a parameter; it does not return a result set.


boolean isDuplicatePO(String custNo, String poNo, String orderNo) {
def sql = new groovy.sql.Sql(sessionFactory.
getCurrentSession().connection())
boolean duplicate = false
sql.call ("call o99lib.o99epo (?,?,?,?)",
[Sql.in(Types.CHAR, custNo),
Sql.in(Types.CHAR, poNo),
Sql.out(Types.CHAR),
Sql.in(Types.CHAR, orderNo)
]) { dup -> duplicate = (dup == 'Y')}
return duplicate
}


The Groovy Sql object was built in the above code from a connection obtained from a Grails DataSource. But you could build your own with:


def sql = groovy.sql.Sql.newInstance(
"jdbc:as400://192.168.1.50/mylib",
"don", "secret",
"com.ibm.as400.access.AS400JDBCDriver")


To create the stored procedure wrapper, I used the following:


CREATE PROCEDURE O99LIB/O99EPO(
IN custNo CHAR(7),
IN poNo CHAR(25),
OUT dup CHAR(1),
IN ordNo CHAR(6))
LANGUAGE RPGLE
NOT DETERMINISTIC
NO SQL
EXTERNAL NAME O99LIB/O99EPO
PARAMETER STYLE GENERAL


Most RPG code does not make it obvious whether or not the parameters are input, output, or input/output. But it is worth the effort to figure out what is what and appropriately define the parameter usage in the create procedure statement.

Thursday, June 11, 2009

Grails custom message.properties

This really is a simple thing.... Now that I know how it works. But I was attempting to override the constraint validation messages in messages in message.properties. In the past I've either simply modified the default message or created custom validators and completely new messages. But I just wanted to override the default messages. Several documents, posts, and blogs say to follow what the Grails docs say and use {className}.{attributeName}.{errorCode} and then provide a sample. But, the thing is, the {errorCode} is not obvious as it is not the same format as what's in the default message.

Here's the thing, my 2-second tip: the Grails documentation for the contraints (http://grails.org/doc/1.1.x/) show the error code to use. For example, for min:

Error Code: className.propertyName.min.notmet

I would have never guessed that in a million years (I did guess a few others though, which is probably why I spent a half-hour guessing at this one but. come on, "min.notmet?"

So, for my ShipTo class's shipToNo attribute I used:

shipTo.shipToNo.min.notmet=Ship-To number must be greater than or equal to {3}