Introduction to Grails with Scott Davis at the Colorado Software Summit
According to Scott, today's Java-based web frameworks are partial solutions at best. They're only solving one piece of the puzzle - you still need to manage persistence, deployment, etc. all by yourself.
We're moving into a new era of web frameworks. The expectation now is a full-stack solution. Grails is a fully integrated modern Java web application in a box. It contains Spring, Hibernate, Quartz, Log4J, Jetty, HSQL, JUnit and Ant. You're not limited to using Jetty, you can type "grails war" and create a WAR that you can deploy to any application server. In a single zip/tar, you get the whole thing - including the database and servlet container. You get a lot of good default for free, but you're not limited to those defaults.
What does "modern" in a framework mean? It means it uses Convention over Configuration - Grails autowires components together based on naming conventions. Struts 1.x uses Configuration over Configuration - the more XML the better.
The Wisdom of Crowds - why are the many smarter than the few? What is the wisdom of crowds when it comes to web frameworks. Struts is the wisdom of crowds when it comes to web frameworks. It's based on sound principles (MVC) and was written by Craig McClanahan. He was the architect of "Catalina" Tomcat 4 and wrote Struts shortly thereafter. David Geary was contributor #2 to Struts. It has a proven track record and has a 60%-70% market share. Struts must be the perfect framework - especially since it has such a great pedigree.
So what's wrong with Struts?
- It's 7 years old
- It's verbose and overly complex (reflective of the EJB 2.x era)
- Splintered community: Craig moved on to JSF -> created Shale, then the WebWork merger
- While Struts 1.x was an unqualified success, Struts 2.x can't seem to build that critical mass - it can't seem to reach The Tipping Point like Struts 1.x did
The Recipe for a Tipping Point: Contagiousness / viral, tiny "tweaks" to a proven model can yield big, disproportionate effects, the rise is not "slow and steady" - the effect is dramatic and immediate.
Ruby on Rails won the hype award. It's largely worth the hype, but it's not revolutionary - it's evolutionary. It has tiny tweaks to the proven MVC-driven approach: Convention over Configuration, Scaffolding and Unified Technology Stack.
The one thing that Rails is lacking is Java support. Grails, on the other hand, offers the same experience using known, proven Java solutions.
- Rails => "replacement"
- Grails => "upgrade"
Scott drank the Rails Kool-Aid for a while and enjoyed it, but found it difficult to switch from Ruby in the morning to Java in the afternoon. With Grails, he doesn't have to do as much context switching, as well as all the Java libraries are available - the ones you know and love.
You can drop groovy.jar into your classpath and write Groovy code. One nice thing about Groovy is you can rename your existing .java files to .groovy and they'll work just fine. Included Ajax support: Script.aculo.us and Protoype as well as YUI. YUI is battle-tested since it's used by Yahoo and very well documented. You can use "grails install-dojo" to install the Dojo toolkit. Grails has a wealth of plugins available at http://grails.org/plugins.
Now we're going to crack our nuckles and build some code - slides are over.
grails create-app conference cd conference grails create-domain-class Speaker (add some fields) grails generate-all Speaker grails run-app
The impressive things about this set of commands is I was able to 1) download Grails and 2) run all these commands at the same time that Scott did. I was definitely impressed (I knew I would be). Auto-scaffolding - you can get the same thing as "generate-all", but it generates controllers and views at runtime in-memory. All you need to do is create a domain object (i.e. Talk) and then create a TalkController that has the following line in it:
def scaffold = Talk
As a test, I tried this at the same time that Scott did and got the following error. It looks like Grails/Jetty isn't smart enough to pick up new classes as they're added.
[263102] commons.DefaultGrailsApplication Class not found attempting to load class Talk java.lang.ClassNotFoundException: Talk at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
Grails comes with a number of environments. Dev (the default) auto-reloads changes to Controllers, Views and even the Model (this is helpful for rapid development). Prod loads all items statically for maximum performance. To change the environments - you can change DataSource.groovy.
For some reason, adding/removing some properties on my Talk object and my application hasn't been the same since. Now when I try to access my TalkController, I see the following stack trace:
org.springframework.orm.hibernate3.HibernateQueryException: could not resolve property: difficulty of: Talk; nested exception is org.hibernate.QueryException: could not resolve property: difficulty of: Talk at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:640) at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412) at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:378) at org.springframework.orm.hibernate3.HibernateTemplate.executeFind(HibernateTemplate.java:342) at org.codehaus.groovy.grails.scaffolding.DefaultScaffoldDomain.list(DefaultScaffoldDomain.java:112)
I asked Scott about this error and he proved that removing properties from domain objects should work. I told him restarting Jetty didn't fix the problem and he suggested dropping the "Talk" table and letting Grails re-create it. Unfortunately, I have no idea where this database is, so that's difficult to do. Doh - now I realize what was causing the problem. Before I dropped the "difficulty" property, I had clicked on the column and that property was still referenced in the URL. When I'd refresh the browser, the stack trace occurred. I don't know if I'd consider this a bug or not.
dbCreate = hibernate.hbm2ddl.auto is used. When in development create-drop is used. In production and test environments, it uses update and saves the data between restarts.
You can turn off Hibernate's automatic schema alteration by commenting out "dbCreate" line in DataSource.groovy.
To run your application in Tomcat instead of Jetty, you can run "grails war" and copy the WAR to Tomcat. The WAR is created with the production environment by default, so you may need to pass in arguments or set environment variables if you want the WAR created in dev mode.
At this point, my battery died. Scott continued to cover how to order form elements (when using scaffolding) with "static constraints" and how to add validation rules. It was an excellent presentation and Grails definitely looks like a really cool web framework. The best part is I learned most of what you need to know to use it - in an hour!
I might have to try Grails soon - I love the concept of Life above the Service Tier and Grails would work nicely for serving up REST. I think YUI, GWT-Ext and Flex are probably the best frameworks for developing a SOFEA client. The question is - when using YUI, how do you download all pages in the application at once?