Cool Web Apps with Grails, Groovy and Next-Gen Scripting
LanguagesWilliam Grosso
Twofish
The rise of next-generation languages that run on top of the JVM is probably the most interesting thing to happen in the Java universe since the combination of the Spring framework and the EJB 2 specification signaled the complete implosion of the Enterprise Software Stack
In this talk, I'll cover, in sequence:
•A brief overview of the state of the art of web application development•A brief overview of Groovy, one of the most interesting of the next-gen languages available on the JVM.•A brief overview of Grails, the best web-application framework currently available (where "best" is, of course, highly idiosyncratic)•The source code to an actual working web application written in Groovy/Grails.
Abstract
The rise of next-generation languages that run on top of the JVM is probably the most interesting thing to happen in the Java universe since the combination of the Spring framework and the EJB 2 specification signaled the complete implosion of the Enterprise Software Stack
In this talk, I'll cover, in sequence:
•A brief discussion of Java and the programming languages on the JVM.•A fairly lengthy overview of Groovy, one of the most interesting of the next-gen languages available on the JVM.•A brief overview of Grails, the best web-application framework currently available (where "best" is, of course, highly idiosyncratic) •The source code to an (admittedly small) actual working web application written in Groovy/Grails.
Actual Talk
Outline
• Who Am I / Standard Caveats• Java as the Foundation• “Improving” the Language: Groovy• Improving the Framework: Grails• Some Actual Code
Outline
• Who Am I / Standard Caveats• Java as the Foundation (2003 Recap)• “Improving” the Language: Groovy• Improving the Framework: Grails• Some Actual Code
Who Am I?
Opinionated Talk
• I’m not selling something– I’m talking about something that I think is going to
be big in 2010
• Goal is also to be somewhat provocative• “I would rather be vaguely correct than precisely wrong” – John
Maynard Keynes• “The references are not without merit” – George Santayana
And these are my opinions, not necessarily Twofish’s
This all started in July
• Left Engage in June • Decided to spend some time exploring new
technologies– Was impressed enough by Grails to write my
“Love Mashup”
• Took the job at Twofish and left things percolating in my brain
Up and running for >3 months without any attention from me
Outline
• Who Am I / Standard Caveats• Java as the Foundation (2003 Recap)• “Improving” the Language: Groovy• Improving the Framework: Grails• Some Actual Code
In 2003 …
• I was invited to give a colloquium talk at CSU Sonoma– Dot-com bust was still in effect; valley was deep in
recession
• Java: It's better than you think, for reasons you haven't realized you already know.– http://www.slideshare.net/wgrosso/java-and-
community-support-presentation/
That Talk Began With ….
• I want to convince you of two things– That Java, or some language like it, is inevitable
from a technological point of view– That Java itself is inevitable from a social point of
view.
• I want to avoid using the traditional technology or “computer science” based arguments
My 2003 Big Bold Claim
• In the world of the future, programs will be increasingly be written by communities
• The single best measure of whether a programming language is worth using is: how well does it support communities.– The social aspects of the language dominate the
technological aspects of the language
Supporting Communities
• New programmers must be able to get up to speed in the language
• Platforms to learn the language on must be cheap and plentiful
• Programmers must be able to use the language on whatever machine they’re using
• Programmers must be able to understand and reuse each other’s code
• Old code must survive in a useful form– And evolve and improve
I Was Right
• Take a look at the libraries out there• Take a look at Java’s market share• It’s entrenched and dominant
Outline
• Who Am I / Standard Caveats• Java as the Foundation (2003 Recap)• “Improving” the Language: Groovy• Improving the Framework: Grails• Some Actual Code
But I Wasn’t Completely Right
JVM
Platform Libraries and Application Frameworks
Your App / Your Web App
Your Libraries
Your Prototypes
Down here, Java, super clear semantics, WORA etcetera win
Hmm. Community properties probably only matter for largish things that you share or keep and reuse for a long time. Maybe we can do better than Java?
Lots of people having similar thoughts. The JVM is robust enough, and the platform is robust enough, and … that people are starting to seriously layer languages on top.
Short list of “interesting” languages:
JythonJRubyScalaGroovyKawaClojurePHPNetRexx (??)
Completely a sidenote: If you’re curious about programming language design, this is the single best site on the web
Closures have been THE hot topic in commercial language design
Odersky’s claim: closures + first class containers + super strong typing are the bees knees
Complexity is bad. Java is near the edge of the cliff.
4.5M PDF and a Tiny Thumbnail? For Generics?
Ruby has a similar problem (more later)
Desiderata for the Tiers
JVM
Platform Libraries and Application Frameworks
Your App
Your Libraries
Your Prototypes
Strong typingAbsolutely clear semanticsMinimal evolution of languageNone of the other stuff is necessary
Looks like Java Clear, readable code Non-verbose languageComplete integration with JavaFirst class containersClosuresGreat XML support Rapid Prototyping (REPL)Metaobject Protocol
Only Groovy Makes the Short List
• Start with: Jython, JRuby, Scala, Groovy, Kawa, Clojure, PHP, NetRexx – Only Scala and Groovy look even remotely like Java
• Both Scala and Groovy have first class containers, complete integration with Java, closures, rapid prototyping, and great XML support
• Groovy’s metaobject protocol, and Grails, make it the winner– Note that I’m completely avoiding the usual phrasing of
the “dynamic typing” question, since I find it annoying
Looks Like Java
Go read the code examplesIt’s easy
Let’s Look at Concurrency
Not Java
def? 1 .. 8 sleep 30
But … it’s close
Complete Integration with Java
• Need to be able to use any library or jar– Seamlessly create and invoke java objects
• Groovy adopts the Java model under the covers
• Groovy compiles to Java classes so that Java applications can use the next-gen stuff– When necessary– But if you buy the stacking diagram, not all that
often.
import groovy.swing.*;import java.awt.*;import javax.swing.*;
class Model extends Observable { static CURRENCY = ["USD", "EURO", "YEN"]
private Map rates = new HashMap() private long value
void initialize(initialRates) { (0..CURRENCY.size() - 1).each { setRate(CURRENCY[it], initialRates[it]) } }
// setting rate for currency void setRate(currency, f) { rates.put(currency, f); setChanged(); notifyObservers(currency); }
// setting new value for currency void setValue(currency, double newValue) { value = Math.round(newValue / rates[currency]); setChanged(); notifyObservers(null); }
// getter for value for particular currency def getValue(currency) { value * rates[currency] }}
class RateView extends JTextField implements Observer { private Model model; private currency;
public void setModel(Model model) { this.model?.removeObserver(this) this.model = model model.addObserver(this) }
public void update(Observable o, Object currency) { if (this.currency == currency) text = String.format("%15.2f", model.rates[currency]) }}
class ValueView extends JTextField implements Observer { private Model model private currency
public void setModel(Model model) { this.model?.removeObserver(this) this.model = model model.addObserver(this) }
public void update(Observable o, Object currency) { if (currency == null || this.currency == currency) text = String.format("%15.2f", model.getValue(this.currency)); }}
swing = new SwingBuilder()model = new Model()
frame = swing.frame(title: "Groovy SwingBuilder MVC Demo", layout: new GridLayout(4, 3), size: [300, 150], defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE) {
label("currency") label("rate") label("value")
for (c in Model.CURRENCY) { label(c) widget(new RateView(), model: model, currency: c, action: swing.action(closure: { event -> event.source.model.setRate(event.source.currency, event.source.text.toDouble()); })) widget(new ValueView(), model: model, currency: c, action: swing.action(closure: {event -> event.source.model.setValue(event.source.currency, event.source.text.toDouble()); })) } }
frame.show()model.initialize([1.0, 0.83, 0.56]);
First Class Containers
• Boils down to – Easy construction syntax – Methods that take closures and perform common
operations.• find (returns first value it finds that matches)• findAll (returns collection of all matches)• every (boolean valued check on collection)• each (iterates through collection and hands elements
to closure)• collect (changes collection)
weekMap = [ "Su" : "Sunday", "Mo" : "Monday", "Tu" : "Tuesday", "We" : "Wednesday", "Th" : "Thursday", "Fr" : "Friday", "Sa" : "Saturday" ]weekMap.each() { key, value -> println "${key} == ${value}" }
Gafter’s Def’n of Closure
• A closure is a function that refers to free variables in its lexical context
• A function is a block of code with parameters. It may produce a result value
• A free variable is an identifier used but not defined by the closure
In Practice
• A closure is a function pointer that knows all the variables that were in scope when it was defined
• Can be passed around as an argument• Can be called at any time.
def foo = { a,b,c -> bunch of code}foo(“e”, “f”, “g”)
Inner Classes are Close!
• Java solution: Define an anonymous inner class that implements a well-known interface
• But– Because they’re classes, they don’t quite behave
the same way– Involve a lot more (physical) typing
Don’t believe me? Neal likes Java a LOT more than I do
XML Support
• <interactive example with groovy console>def CAR_RECORDS = ''' <records> <car name='HSV Maloo' make='Holden' year='2006'> <country>Australia</country> <record type='speed'>Production Pickup Truck with speed of 271kph</record> </car> <car name='P50' make='Peel' year='1962'> <country>Isle of Man</country> <record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg in weight</record> </car> <car name='Royale' make='Bugatti' year='1931'> <country>France</country> <record type='price'>Most Valuable Car at $15 million</record> </car> </records>'''
def records = new XmlSlurper().parseText(CAR_RECORDS)def allRecords = records.carprintln allRecords.size()println records.car[0].name()println records.car[0].@yearprintln records.car[0].country
XML Support II
• XMLBuilder• Will be discussed in detail after MetaObject
Protocol section
Rapid Prototyping: Scripts, Shell and Console
• Scripts – groovy doesn’t need to use classes. – SwingBuilder example a few slides ago didn’t use
classes for the executable bits.
• groovysh – command line shell (seen a few slides ago)
• Groovyconsole – swing GUI for playing with scripts– Supports cut and paste better than command line
Metaobject Protocol• A metaobject protocol (MOP) is an interpreter of the semantics of a program that
is open and extensible. Therefore, a MOP determines what a program means and what its behavior is, and it is extensible in that a programmer (or metaprogrammer) can alter program behavior by extending parts of the MOP. The MOP exposes some or all internal structure of the interpreter to the programmer. The MOP may manifest as a set of classes and methods that allow a program to inspect the state of the supporting system and alter its behaviour. MOPs are implemented as object-oriented programs where all objects are metaobjects.
• Thanks Wikipedia !
MetaObject Protocols: The Point
• At runtime, can find out about, and alter, class definitions– Add or remove methods– Dynamically change implementations of methods– Handle “no such method” at the recipient, not the caller
• Groovy– invokeMethod– ExpandoMetaclass– propertyMissing– methodMissing
OPINIONS VARY AS TOWHETHER ALLOWING THIS SORT OF THING IS A GOOD IDEA!!!!
Chris will talk more about GORM later on
Builders
• Lots and lots of things are tree-like data structures– User interfaces (structure of Swing components)– HMTL Documents (XML documents)– Invoices have line items …
• Big-Ass Completely Unsupported Claim: Every DSL is a tree-like data structure + an interpretation.
» Or Should Be!
What’s Martin Fowler been doing since the refactoring book anyway?
How to Build a Builder
• Implement a (Java!) subclass of BuilderSupport
• Or just use methodMissing – It’s really what the Java’s doing anyway.
protected abstract Object createNode(Object name)protected abstract Object createNode(Object name, Map attributes)protected abstract Object createNode(Object name, Map attributes, Object value)protected abstract Object createNode(Object name, Object value) protected abstract void setParent(Object parent, Object child)
Groovy is designed to work with Java.
MarkupBuilderimport groovy.xml.MarkupBuilder
def writer = new StringWriter() def xml = new MarkupBuilder(writer)xml.records() { car(name:'HSV Maloo', make:'Holden', year:2006) { country('Australia') record(type:'speed', 'Production Pickup Truck with speed of 271kph') } car(name:'P50', make:'Peel', year:1962) { country('Isle of Man') record(type:'size', 'Smallest Street-Legal Car at 99cm wide and 59 kg in weight') } car(name:'Royale', make:'Bugatti', year:1931) { country('France') record(type:'price', 'Most Valuable Car at $15 million') } }
println writer.toString()
Outline
• Who Am I / Standard Caveats• Java as the Foundation (2003 Recap)• “Improving” the Language: Groovy• Improving the Framework: Grails• Some Actual Code
Rails as a Thunderbolt
• Convention over configuration– Kind of like design patterns, except there’s only
one pattern
• ActiveRecord simplifies DB access• Migrations simplifies DB upgrades• Capistrano simplifies deployment• Plugin architecture (framework as platform)• Ruby as the base language
The Rails guys invented the “movie to demo the framework” idea and their movies are still WOW OH WOW GOOD
1. PHP2. PHP3. Java (Coldfusion)4. PHP5. .NET6. Perl7. PHP8. Java9. .NET10. PHP11. Java12. Java13. PHP14. Java15. PHP16. Ruby17. Perl18. Java19. Java20. PHP
PHP: 8Java: 7.NET: 2Perl: 2Ruby: 1
In 4 years, Rails has made very impressive strides. Market leader in the “early stage startup” category.
Issues with Ruby
• Powerful language, currently in flux– Transition from 1.8 to 1.9 is slow and painful
• Not clear what the language definition is• Syntax is awful. Like a modified PERL with additional
incomprehensibility– Okay, that was biased.
• The standard implementation is low performance and fragile
Backwards compatibility is not a huge priority
Backwards compatibility is not a huge priority
This is scary
Of course, Java is mostly developed by Sun ….
This is from a Ruby guy who doesn’t like JRuby very much …
Issues with Rails
• Focus on CRUD– Works very well for the standard web architecture– Good for building standalone applications
• Integration scenarios not well supported• Legacy code not well supported
• Far fewer man hours of development, qa, or deployment experience than many other frameworks– Compare to Spring, for example
Grails is “Groovy on Rails”
• Adopt many, if not all, of the key ideas of Rails– Swap out Ruby for Groovy– Swap out Rails for Spring, Hibernate, SiteMesh,
and lots of glue
• Application code is written in Groovy– With “drop into Java for performance” drop-dead
easy
• Leverage JVM + Java libraries for the infrastructure
Pieces / Parts
• GSP – “Groovy Server Pages”– A lot like JSP
• GORM – “Groovy Object Relational Mapping”– Hibernate + Bionicness. Really impressive.
• Core abstractions:– Domain classes– Controllers– Views– Services
More on these later
GORM
• <<Chris– a world class expert in GORM>>
Plugins and Extensability
• Grails is a platform for extensions• Makes a lot of sense given the point is to build
a Rails that leverages Java
SWAG Estimate: About ¾ of plugins are mentioned here (BIRT, for example, is not)
Outline
• Who Am I / Standard Caveats• Java as the Foundation• “Improving” the Language: Groovy• Improving the Framework: Grails• Some Actual Code
Twofish Model
TFEL
TFELDB
TFELDB
1. JBoss 4 on Java 6.2. Everything clustered3. Everything replicated4. SOAP5. Fat client SDK
PS
1. Layered apps2. In our data center3. Customer specific4. Lightweight frameworks
rock
<<IntelliJ>>
Annoyances (Love Mashup)
• Mainly from my incompetence with HTML.• Also: imperfect prototyping environment
– Changes in controllers and views reflected immediately
– Changes in domain models often require restarting dev server
– Changes in services or supporting code almost always require a dev server restart
Plugins (Love Mashup)
• Cloud Foundry – easy deploy to Amazon• YUI – cleaner UI components
– To be honest, I used OSWD for the layout
Annoyances (Twofish)
• Oddly enough, the Java stack– JDK has an XML Parser– Grails has a copy of Xerces– Twofish Client SDK has a copy of Xerces– Endorsed directories are painful
• We can’t use the standard deployers
• Intellij not yet supporting Grails 1.1 or Groovy 1.6
Plugins (Twofish)
• Quartz plugin – Background processing• BIRT plugin – Enterprise class reports• Xfire plugin – makes handling SOAP requests
trivial
Additional Reading
This is a great series of articles. Whenever anyone tells you a technology is going to be big, ask yourself: WWTT?