Groovy and Gaelyk - Lausanne JUG 2011 - Guillaume Laforge
Groovy update
and Gaelyk,
a lightweight toolkit
for Google App Engine
Groovy update
and Gaelyk,
a lightweight toolkit
for Google App Engine
Guillaume Laforge / @glaforge
• Groovy Project Manager
• Head of Groovy Development
at SpringSource
• Initiator of the Grails framework
• Founder of the Gaelyk toolkit
• Co-author of Groovy in Action
• Member of «Les Cast Codeurs» podcast
• Speaker: JavaOne, QCon, JavaZone, Sun TechDays,
Devoxx, The Spring Experience, SpringOne2GX,
JAX, Dynamic Language World, IJTC, and more...
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 2
Agenda
•Past
– Groovy 1.6 flashback
•Present
– Groovy 1.7 novelties
– A few Groovy 1.7.x refinements
•Future
– What’s cooking for 1.8 and beyond
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 4
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000
150000
100000
50000
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000
150000
100000
50000
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000
150000
100000
50000
Groovy 1.5
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000
150000
100000
50000
Groovy 1.5
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000
150000
100000
G2One
acquisition
50000
Groovy 1.5
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000
150000
100000
G2One
acquisition
50000
Groovy 1.5
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000
Groovy 1.6
150000
100000
G2One
acquisition
50000
Groovy 1.5
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000
Groovy 1.6
150000
100000
G2One
acquisition
50000
Groovy 1.5
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000 Groovy 1.7
Groovy 1.6
150000
100000
G2One
acquisition
50000
Groovy 1.5
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
But first... some figures...
Downloads Moving Average (year)
Groovy downloads per month
200000 Groovy 1.7
Groovy 1.6
8 5 K
150000
100000
50000
Groovy 1.5
1 G2One
acquisition
0
déc.-07 févr.-08 avr.-08 juin-08 août-08 oct.-08 janv.-09 mars-09 mai-09 juil.-09 sept.-09 nov.-09 janv.-10 mars-10 mai-10 juil.-10
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5
Big highlights of Groovy 1.6
• Greater compile-time and runtime performance
• Multiple assignments
• Optional return for if/else and try/catch/finally
• Java 5 annotation definition
• AST Transformations
• The Grape module and dependency system
• Various Swing related improvements
• JMX Builder
• Metaprogramming additions
• JSR-223 scripting engine built-in
• Out-of-the-box OSGi support
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 7
Big highlights of Groovy 1.6
• Greater compile-time and runtime performance
• Multiple assignments
• Optional return for if/else and try/catch/finally
• Java 5 annotation definition
• AST Transformations
• The Grape module and dependency system
• Various Swing related improvements
• JMX Builder
• Metaprogramming additions
• JSR-223 scripting engine built-in
• Out-of-the-box OSGi support
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 8
Multiple assignement
// multiple assignment
def (a, b) = [1, 2]
assert a == 1 && b == 2
// with typed variables
def (int c, String d) = [3, "Hi"]
assert c == 3 && d == "Hi"
def geocode(String place) { [48.8, 2.3] }
def lat, lng
// assignment to existing variables
(lat, lng) = geocode('Paris')
// classical variable swaping example
(a, b) = [b, a]
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 9
More optional return
// optional return for if statements
def m1() {
if (true) 1
else 0
}
assert m1() == 1
// optional return for try/catch/finally
def m2(bool) {
try {
if (bool) throw new Exception()
1
} catch (any) { 2 }
finally { 3 }
}
assert m2(true) == 2 && m2(false) == 1
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 10
AST Transformation (1/2)
• Groovy 1.6 introduced AST Transformations
– AST: Abstract Syntax Tree
• Ability to change what’s being compiled by the
Groovy compiler... at compile time
–No runtime impact!
– Change the semantics of your programs! Even hijack the
Groovy syntax!
– Implementing recurring patterns in your code base
– Remove boiler-plate code
• Two kinds: global and local
– triggered by annotations
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 11
AST Transformations (2/2)
• Transformations introduced in 1.6
– @Singleton
– @Immutable, @Lazy, @Delegate
– @Newify
– @Category, @Mixin
– @PackageScope
– Swing’s @Bindable and @Vetoable
– Grape’s own @Grab
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 12
@Immutable
• To properly implement immutable classes
– No mutations — state musn’t change
– Private final fields
– Defensive copying of mutable components
– Proper equals() / hashCode() / toString()
for comparisons or as keys in maps
@Immutable class Coordinates {
Double lat, lng
}
def c1 = new Coordinates(lat: 48.8, lng: 2.5)
def c2 = new Coordinates(48.8, 2.5)
assert c1 == c2
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 13
Grab a grape!
• Simple distribution and sharing of Groovy scripts
• Dependencies stored locally
– Can even use your own local repositories
@Grab(group = 'org.mortbay.jetty',
module = 'jetty‐embedded',
version = '6.1.0')
def startServer() {
def srv = new Server(8080)
SIONS)
def ctx = new Context(srv , "/", SES
ctx.resourceBase = "."
ovy")
ctx.addServlet(GroovyServlet, "*.gro
srv.start()
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 14
Big highlights of Groovy 1.7
• Anonymous Inner Classes and Nested Classes
• Annotations anywhere
• Grape improvements
• Power Asserts
• AST Viewer
• AST Builder
• Customize the Groovy Truth!
• Rewrite of the GroovyScriptEngine
• Groovy Console improvements
• SQL support refinements
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 16
Big highlights of Groovy 1.7
• Anonymous Inner Classes and Nested Classes
• Annotations anywhere
• Grape improvements
• Power Asserts
• AST Viewer
• AST Builder
• Customize the Groovy Truth!
• Rewrite of the GroovyScriptEngine
• Groovy Console improvements
• SQL support refinements
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 17
AIC and NC
• Anonymous Inner Classes and Nested Classes
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 18
AIC and NC
• Anonymous Inner Classes and Nested Classes
Fo rJ ava
’n p aste
c opy
atib ility
co mp
s ake :-)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 18
Annonymous Inner Classes
bo olean called = false
Timer ti mer = new Timer()
timer.schedule(n ew TimerTask() {
void run() {
called = true
}
}, 0)
sleep 100
assert called
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 19
Annonymous Inner Classes
bo olean called = false
Timer ti mer = new Timer()
timer.schedule(n ew TimerTask() {
void run() {
called = true
}
{ called = true }
}, 0) as
TimerTask
sleep 100
assert called
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 19
Nested Classes
class Environment {
static class Production
extends Environment {}
static class Development
extends Environment {}
}
new Environment.Production()
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 20
Anotations almost anywhere
• You can put annotations
– on imports
– on packages
– on variable declarations
• Examples with @Grab following...
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 21
Grape improvements (1/4)
• @Grab on import
@Grab(group = 'net.sf.json‐lib',
module = 'json‐lib',
version = '2.3',
classifier = 'jdk15')
import net.sf.json.groovy.*
assert new JsonSlurper().parseText(
new JsonGroovyBuilder().json {
book(title: "Groovy in Action",
author: "Dierk König et al")
}.toString ()).book.title == "Groovy in Action"
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 22
Grape improvements (2/4)
• Shorter module / artifact / version parameter
– Example of an annotation on a variable declaration
@Grab('net.sf.json‐lib:json‐lib:2.3:jdk15')
()
def builder = new net.sf.json.groovy.JsonGroovyBuilder
def books = builder.books {
book(title: "Groovy in Action", author: "Dierk Koenig")
}
assert books.toString() ==
'{"books":{"book":{"title":"Groovy in Action",' +
'"author":"Dierk Koenig"}}}'
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 23
Grape improvements (3/4)
• Groovy 1.7 introduced Grab resolver
– For when you need to specify a specific repository
for a given dependency
@GrabResolver(
name = 'restlet.org',
root = 'http://maven.restlet.org')
@Grab('org.restlet:org.restlet:1.1.6')
import org.restlet.Restlet
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 24
Power Asserts (1/2)
• Much better assert statement!
– Invented and developed in the Spock framework
• Given this script...
def energy = 7200 * 10**15 + 1
def mass = 80
def celerity = 300000000
assert energy == mass * celerity ** 2
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 25
Power Asserts (2/2)
• You’ll get a more comprehensible output
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 26
Easier AST Transformations
• AST Transformations are a very powerful feature
• But are still rather hard to develop
– Need to know the AST API closely
• To help with authoring your own transformations,
we’ve introduced
– the AST Viewer in the Groovy Console
– the AST Builder
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 27
AST Viewer
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 28
AST Builder
// Ability to build AST parts
// ‐‐> from a String
new AstBui lder().buildFromString(''' "Hello" ''')
// ‐‐> from code
new AstBuilder().buildFromCode { "Hello" }
// ‐‐> from a specification
{
List<ASTNo de> nodes = new AstBuilder().buildFromSpec
block {
returnStatement {
constant "Hello"
}
}
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 29
Customize the Groovy Truth!
• Ability to customize the truth by implementing a
boolean asBoolean() method
class Predicate {
boolean value
boolean asBoolean() { value }
}
def tr uePred = new Predicate(value: true)
def fals ePred = new Predicate(value: false)
assert truePred && !falsePred
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 30
Groovy 1.7.x changes
• Since Groovy 1.7.0...
Groovy 1.7.1, 1.7.2, 1.7.3, 1.7.4, 1.7.5 and 1.7.6
have been released already!
• Here’s what’s new!
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 31
Grape improvements (4/4)
• Groovy 1.7.5 even further shrinks the grab resolver
definition:
@Gra bResolver('http://maven.restlet.org')
@Grab('org.restlet:org.restlet:1.1.6')
import org.restlet.Restlet
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 32
Map improvements (1/2)
// map auto‐vification
def m = [:].withDefault { key ‐> "Default" }
assert m['z'] == "Default"
assert m['a'] == "Default"
// default sort, sort with a comparator
m.sort()
m.sort({ a, b ‐> a <=> b } as Comparator)
// max{} and min{}
assert [a: 1, b: 2].max{ it.value }.value == 2
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 33
Map improvements (2/2)
// before Map#withDefault()
def words = "one two two three three three".split()
def freq = [:]
words.each {
if (it in freq)
freq[it] += 1
else
freq[it] = 1
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 34
Map improvements (2/2)
// after Map#withDefault()
def words = "one two two three three three".split()
def freq = [:].withDefault { k ‐> 0 }
words.each {
freq[it] += 1
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 35
XML back to String
• Ability to retrieve the XML string from a node from
an XmlSlurper GPathResult
def xml = """
<books>
<book isbn="12345">Groovy in Action</book>
</books>
"""
def root = new XmlSlurper().parseText(xml)
def someNode = root.book
def bu ilder = new StreamingMarkupBuilder()
assert build er.bindNode(someNode).toString() ==
"<book isbn='12345'>Groovy in Action</book>"
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 36
Currying improvements
// right currying
def divide = { a, b ‐> a / b }
def halver = divide.rcurry(2)
assert halver(8) == 4
// currying n‐th parameter
def jo inWithSeparator = { one, sep, two ‐>
one + sep + two
}
def joinWithComma =
jo inWithSeparator.ncurry(1, ', ')
assert joinWithComma('a', 'b') == 'a, b'
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 37
Date improvements
im port static java.util.Calendar.*
// convert to calendar
def cal = new Date().toCalendar()
// update a date (or a calendar)
cal.set(year: cal[YEAR] + 1)
cal[MONTH] = MARCH
// create a ne w date (or a calendar) from one
def nextYear = c al.updated(year: cal[YEAR] + 1)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 38
New String methods
println """ println """
def method() { |def method() {
return 'bar' | return 'bar'
} |}
""".stripIndent() """.stripMargin('|')
// string "translation" (UNIX tr)
assert 'hello'.tr('z‐a', 'Z‐A') == 'HELLO'
WAAAA!'
asse rt 'Hello World!'.tr('a‐z', 'A') == 'HAAAA
2d!'
assert 'Hell o World!'.tr('lloo', '1234') == 'He224 W4r
// capitalize the first letter
assert 'h'.capitalize() == 'H'
assert 'hello'.capitalize() == 'Hello'
rld'
asse rt 'hello world'.capitalize() == 'Hello wo
mmand)
// tab/space (un)expansion (UNIX expand co
7 8 '
assert '1234567t8t '.expand() == '123456
'
assert ' x '.unexpand() == ' xt
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 39
Map supports isCase()
def m = [a: 1, b: 2]
def val = 'a'
switch (val) {
case m: "key in map"; break
// equival ent to // case { val in m }: ...
default: "not in map"
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 40
(G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
// implicit coercion
Color b = "blue"
// with GStrings too
def g = "${'green'}" as Color
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 41
Groovy 1.8 & beyond
• Still subject to discussion
• Always evolving roadmap
• Things may change!
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 43
What we’re working on
• More runtime performance improvements
• Closures
– annotation parameters
composition, memoization, and trampoline
• Native JSON support
– builder and parser
• New AST transformations
• Gradle build
• Modularizing Groovy
• Align with JDK 7 / Java 7 / Project Coin
• Enhanced DSL support
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 45
An example, with Fibonacci
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 48
An example, with Fibonacci
• Known example of worst case
performance for Groovy
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 48
An example, with Fibonacci
• Known example of worst case
performance for Groovy
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 48
An example, with Fibonacci
• Known example of worst case
performance for Groovy
• Groovy 1.7.5 vs Java
– 25131ms / 1110ms
–22x slower!
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 48
An example, with Fibonacci
• Known example of worst case
performance for Groovy
• Groovy 1.7.5 vs Java
– 25131ms / 1110ms
–22x slower!
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 48
An example, with Fibonacci
• Known example of worst case
performance for Groovy
• Groovy 1.7.5 vs Java
– 25131ms / 1110ms
–22x slower!
• Groovy 1.8-beta-3 vs Java
– 1871ms / 1110ms
–only 68% slower
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 48
An example, with Fibonacci
• Known example of worst case
performance for Groovy
13 x • Groovy 1.7.5 vs Java
– 25131ms / 1110ms
–22x slower!
• Groovy 1.8-beta-3 vs Java
– 1871ms / 1110ms
–only 68% slower
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 48
Optimizations for int
• Currently, the optimizations cover most of native
operations on primitive ints
– Be careful, your mileage may vary
• To come next
– optimizations for doubles
– improving array accesses
– then other primitives optimizations
– and mixed cases of primitives
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 49
Closure annotation parameters
• Groovy 1.5 brought Java 5 annotations
• What if... we could go beyond what Java offered?
– In 1.7, we can put annotations on packages, imports and
variable declarations
– But annotations are still limited in terms of parameters
they allow
• Here comes closure annotation parameters!
– Groovy 1.8 will give us the ability to access annotation
with closure parameters at runtime
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 50
GContracts
• Closures are already allowed in the Groovy 1.7 Antlr
grammar
– André Steingreß created GContracts,
a «design by contract» module
// a class invariant
@Invar iant({ name.size() > 0 && age > ageLimit() })
class Person { String name; int age }
// a method pre‐condition
@Requires({ message != null })
void greet(String message) { ... }
// a method post‐condition
@Ensures({ returnResult % 2 == 0 })
int evenResult() { ... }
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 51
Closure memoization
• Memoization: remember the outcome of previous
(ideally side-effect free) invocations
def c = { a, b ‐> sleep 1000; a + b }.memoize()
assert c(1, 2) == 3 // after 1000ms
assert c(1, 2) == 3 // return immediately
// other forms:
// at least 10 invocations cached
def cAtLeast = { ... }.memoizeAtLeast(10)
// at most 10 invocations cached
def cAtMost = { ... }.memoizeAtMost(10)
// between 10 and 20 invocations cached
def cAtLeast = { ... }.memoizeBetween(10, 20)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 53
Closure trampoline
• No more infamous StackOvervlow errors for deeply
recursive algorithms
– if you use closure trampolines explicitely
def fact
fact = { int n, BigInteger accu ‐>
n > 1 ? fact.trampoline(n ‐ 1, n * accu) : accu
}.trampoline()
def factorial = { int n ‐> fact(n, 1G) }
assert factorial(1) == 1
assert factorial(3) == 6
assert factorial(1000) == 402387260077...
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 54
New AST xforms (1/2)
• Many new transformations coming up for
removing even more boiler plate code
@Log inject a logger in your classes
@Field creates a field in your scripts
@PackageScope improvements (methods & fields)
@Synchronized providing safer synchronization semantics
@InheritConstructor ex. when extending Exception
@IndexedProperties JavaBeans indexed property support
@AutoClone automatic cloning of your beans
@AutoExternalizable automatic externalization of your beans
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 55
New AST xforms (2/2)
@ThreadInterrupt makes a script interruptible
@TimedInterrupt interrupt after a period of time
@ConditionalInterrupt interrupt with a custom condition
@Canonical adds equals, hashCode, toString, ctor
- @EqualsAndHashCode just equals and hashCode
- @ToString just toString
- @TupleConstructor adds a «tuple» constructor
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 56
Java 7 / 8 / Project Coin
• Alignment with JDK 7 will come in Groovy 1.9
• JSR-292 InvokeDynamic
• Simple Closures (8)
• Proposals from Project Coin
– Strings in switch (7)
– Automatic Resource Management (7)
– Improved generics type inference (diamond <>) (7)
– Simplified varargs method invocation (7)
– Better integral literals (7)
– Language support for collections (8?)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 57
Java 7 / 8 / Project Coin
• Alignment with JDK 7 will come in Groovy 1.9
• JSR-292 InvokeDynamic
• Simple Closures (8)
• Proposals from Project Coin
– Strings in switch (7)
– Automatic Resource Management (7)
– Improved generics type inference (diamond <>) (7)
– Simplified varargs method invocation (7)
– Better integral literals (7)
– Language support for collections (8?)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 57
Java 7 / 8 / Project Coin
• Alignment with JDK 7 will come in Groovy 1.9
• JSR-292 InvokeDynamic
• Simple Closures (8)
• Proposals from Project Coin
– Strings in switch (7)
– Automatic Resource Management (7)
– Improved generics type inference (diamond <>) (7)
– Simplified varargs method invocation (7)
– Better integral literals (7)
– Language support for collections (8?)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 57
Java 7 / 8 / Project Coin
• Alignment with JDK 7 will come in Groovy 1.9
• JSR-292 InvokeDynamic
• Simple Closures (8)
• Proposals from Project Coin
– Strings in switch (7)
– Automatic Resource Management (7)
– Improved generics type inference (diamond <>) (7)
– Simplified varargs method invocation (7)
– Better integral literals (7)
– Language support for collections (8?)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 57
Java 7 / 8 / Project Coin
• Alignment with JDK 7 will come in Groovy 1.9
• JSR-292 InvokeDynamic
• Simple Closures (8)
• Proposals from Project Coin
– Strings in switch (7)
– Automatic Resource Management (7)
– Improved generics type inference (diamond <>) (7)
– Simplified varargs method invocation (7)
– Better integral literals (7)
– Language support for collections (8?)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 57
Improved DSL support
• GEP-3: an extended command expression DSL
– Groovy Extension Proposal #3
• Command expressions
– basically top-level statements without parens
– combine named and non-named arguments in the mix
•for nicer Domain-Specific Languages
– (methodName arguments)*
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 58
Before GEP-3
• The idea: extend command-expressions, beyond
top-level statements, for chained method calls
• Before
send("Hello").to("Graeme")
check(that: margherita).tastes(good)
sell(100.shares).of(MSFT)
take(2.pills).of(chloroquinine).after(6.hours)
wait(10.minutes).and(execute { })
blend(red, green).of(acrylic)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 59
With GEP-3
• The idea: extend command-expressions, beyond
top-level statements, for chained method calls
• After
send "Hello" to "Graeme"
check that: margherita tastes good
sell 100.shares of MSFT
take 2.pills of chloroquinine after 6.hours
wait 10.minutes and execute { }
blend red, green of acrylic
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 60
With GEP-3
• The idea: extend command-expressions, beyond
top-level statements, for chained method calls
• After
Less
& co pare
ns
send "Hello" to "Graeme"
check that: margherita tastes good mm
sell 100.shares of MSFT
as
take 2.pills of chloroquinine after 6.hours
wait 10.minutes and execute { }
blend red, green of acrylic
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 60
The pattern
• A repetition of
– method name
– arguments (mix of named and normal)
check that: margherita tastes good
method method
named parameter parameter
name name
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 61
Summary
• No need to wait for Java 7, 8, 9...
– closures, properties, interpolated strings, extended
annotations, metaprogramming, [YOU NAME IT]...
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 62
Summary
• No need to wait for Java 7, 8, 9...
– closures, properties, interpolated strings, extended
annotations, metaprogramming, [YOU NAME IT]...
’s s till
Gro ovy
novat ive
in
20 03!
si nce
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 62
Summary
• No need to wait for Java 7, 8, 9...
– closures, properties, interpolated strings, extended
annotations, metaprogramming, [YOU NAME IT]...
’s s till
Gro ovy
novat ive
in
20 03!
si nce
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 62
d A
a n
Q
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
IaaS, PaaS, SaaS
• Software as a Service
– Gmail, SalesForce.com SaaS
• Platform as a Service
– Google App Engine
PaaS
• Infrastructure as a Service
– Amazon EC2
IaaS
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 65
IaaS, PaaS, SaaS
• Software as a Service
– Gmail, SalesForce.com SaaS
• Platform as a Service
– Google App Engine
PaaS
• Infrastructure as a Service
– Amazon EC2
IaaS
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 65
IaaS, PaaS, SaaS
• Software as a Service
– Gmail, SalesForce.com SaaS
• Platform as a Service
– Google App Engine
PaaS
• Infrastructure as a Service
– Amazon EC2
IaaS
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 65
Google App Engine
• Google’s PaaS solution
• Run your app on Google’s infrastructure
• Initially just Python supported
• Java supported added too
– Sandboxed JVM
– Jetty servlet container
• Several JVM-compatible language supported
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 66
Key aspects
• You can use most of your usual web frameworks for
developping apps on App Engine Java
– A WAR file, basically! (an exploded war actually)
– Uploading to the cloud by sending deltas of changes
• No OS image, or software to install
– Unlike with Amazon EC2
• All the scaling aspects are handled for you
– Database / session replication, load balancing...
• There are quotas, but you need a high traffic
application to start being charged
– Free to get started
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 67
Available services
• Memcache – Send / receive Jabber
messages (GTalk)
– JCache implementation
– Save on CPU and DB • User
– Use Google’s user/
• URL Fetch authentication system
– Access remote resources – OAuth support
– HttpUrlConnection
• Cron & Task queues
• Mail – Schedule tasks at regular
– Support both incoming and intervals
outgoing emails – Queue units of work
• Images • Blobstore
– Resize, crop, rotate... – For storing large content
• XMPP • And much more...
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 68
Limitations
•Not our usual relational database
– key / value datastore
•30 seconds request duration limit
• Forbidden to
– write on the file system
– create threads
– use raw sockets
– issue system calls
– use IO / Swing / etc. directly
•There’s a whitelist of classes allowed
• Number of files and their size are limited
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 69
Quotas (1/2)
•Bandwidth •Mail
– 1,3M requests/day – 7K calls/day
– 1GB/day in/out – 2K recepients/day
– 6.5 CPU hours/day – 5K emails/day
– 2K attachments
– 100MB of attachments
•Datastore
– 10M calls
– 1GB/day •URL Fetch
– 12GB in / 115GB out – 657K calls/day
– 60 CPU hours/day – 4GB in/out /day
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 71
Quotas (2/2)
•XMPP •Memcache
– 657K calls/day – 8.6M calls/day
– 4GB data sent/day – 10GB in
– 657K recepients/day – 50GB out
– 1MB invitations/day
•Task queues
•Image manipulation – 100K calls
–864 calls/day
–1GB in / 5GB out
–2.5M transforms
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 72
Quotas (2/2)
•XMPP •Memcache
– 657K calls/day – 8.6M calls/day
– 4GB data sent/day – 10GB in
– 657K recepients/day – 50GB out
– 1MB invitations/day
•Task queues
•Image manipulation – 100K calls
–864 calls/day
ur es
–1GB in / 5GB out d fig
da te
–2.5M transforms
O ut
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 72
The datastore...
• Not your father’s relational database! «NoSQL»
• Distributed key / value store
– Based on Google’s «BigTable»
– Schema-less approach
• Supporting
– Transactions and partitioning
– Hierarchies through entity groups
• Data access APIs
– JPA and JDO
• but adds a big request load time factor
– Direct low-level APIs
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 74
...and its «limitations»
• You’re not using SQL
–No joins
– No database constraints
– No aggregation functions (count, avg...)
• In a query, you can only filter on one column
for inequality
• Transactions only available in entity groups
• You can only update an entity once in a transaction
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 75
Gaelyk 0.6 released!
• Even a 0.6.1...
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 78
• Gaelyk is a lightweight Groovy toolkit on top of
the Google App Engine Java SDK
• Gaelyk builds on Groovy’s servlet support
– Groovlets: Groovy scripts instead of raw servlets!
– Groovy templates: JSP-like template engine
– Both allow for a clean separation of views and logic
• Gaelyk provides several enhancements around the
GAE Java SDK to make life easier, thanks to
Groovy’s dynamic nature
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 79
Why Groovy?
• Groovy is a dynamic language for the JVM
– very flexible, malleable, expressive and concise syntax
– easy to learn for Java developers
• deriving from the Java 5 grammar
– provides powerful APIs to simplify the life of developers
• possibility to dynamically enrich existing APIs
– support for Groovlets and its own template engine
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 80
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 81
First steps...
• Go to http://gaelyk.appspot.com
• Download the template project
• Put your first Groovlet in /WEB-INF/groovy
• And your templates in /WEB-INF/pages
• And you’re ready to go!
• Launch dev_appserver.sh
• Go to http://localhost:8080/
The web.xml
">
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5
<listener>
/servlet-class>
<listener-class>groovyx.gaelyk.GaelykServletContextListener<
</listener>
<servlet>
<servlet-name>GroovletServlet</servlet-name>
<servlet-class>groovyx.gaelyk.GaelykServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>TemplateServlet</servlet-name>
-class>
<servlet-class>groovyx.gaelyk.GaelykTemplateServlet</servlet
</servlet>
<servlet-mapping>
<servlet-name>GroovletServlet</servlet-name>
<url-pattern>*.groovy</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>TemplateServlet</servlet-name>
<url-pattern>*.gtpl</url-pattern>
</servlet-mapping>
</web-app>
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 83
MVC: Groovlets and templates
Groovlets Templates
(controllers) (views)
Entities
(domain)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
A groovlet
• Instead of writing full-blown servlets, just write
Groovy scripts (aka Groovlets)
def numbers = [1, 2, 3, 4]
def now = new Date()
html.html {
body {
numbers.each { number -> p number }
p now
}
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 85
A groovlet
• Instead of writing full-blown servlets, just write
Groovy scripts (aka Groovlets)
def numbers = [1, 2, 3, 4]
def now = new Date()
html.html {
body {
numbers.each { number -> p number }
p now
}
di ng
oa
}
-rel
to
Au
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 85
A template
<html>
<body>
<p><%
def message = "Hello World!"
print message %>
</p>
<p><%= message %></p>
<p>${message}</p>
<ul>
<% 3.times { %>
<li>${message}</li>
<% } %>
</ul>
</body>
</html>
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 86
A template
<html>
<body>
<p><%
def message = "Hello World!"
print message %>
</p>
<p><%= message %></p>
<p>${message}</p>
<ul>
<% 3.times { %>
<li>${message}</li>
<% } %>
di ng
</ul>
el oa
</body>
to -r
Au
</html>
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 86
Shortcuts
• Google services • Variables available
–datastore –request / response
–blobstore –context / application
–memcache –sessions
–capabilities –params / headers
–images –out / sout / html
–urlFetch –localMode / app.*
–mail
–userService / user • Methods available
–defaultQueue / queues –include / forward /
–xmpp redirect
–namespace –println / print
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 87
Sending emails with Gaelyk
mail.send to: 'to@gmail.com',
from: 'other@gmail.com',
subject: 'Hello World',
htmlBody: '<bold>Hello</bold>'
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 90
...compared to Java
Properties props = new Properties();
, null);
Sessio n session = Session.getDefaultInstance(props
try {
Message msg = new MimeMessage(session);
om", "Admin"));
msg .setFrom(new InternetAddress("other@gmail.c
O,
msg.addRecipient(Message.RecipientType.T
, "Mr. User"));
new InternetAddress("to@example.com"
msg.setSubject("Hello World");
msg.setText("<bold>Hello</bold>");
Transport.send(msg);
} catch (AddressException e) {}
} catch (MessagingException e) {}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 91
Accessing the datastore
• Direct interaction with the low-level datastore API
Entity entity = new Entity("person")
map
// subscript notation, like when accessing a
entity['name'] = "Guillaume Laforge"
// normal property access notation
entity.age = 32
entity.save() // asyncSave()
entity.delete() // asyncDelete()
datastore.withTransaction {
// do stuff with your entities
// within the transaction
}
// use the asynchronous datastore service
datastore.async.put(entity)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 92
Querying to be improved...
import com.google.appengine.api.datastore.*
der.*
import static com.google.appengine.api.datastore.FetchOptions.Buil
// query the scripts stored in the datastore
def query = new Query("savedscript")
// sort results by descending order of the creation date
query.addSort("dateCreated", Query.SortDirection.DESCENDING)
author
// filters the entities so as to return only scripts by a certain
r)
query.addFilter("author", Query.FilterOperator.EQUAL, params.autho
PreparedQuery preparedQuery = datastore.prepare(query)
// return only the first 10 results
def entities = preparedQuery.asList( withLimit(10) )
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 93
...into something groovier?
def entities = datastore.query {
select all from savedscript
sort desc by dateCreated
where author == params.author
limit 10
} as List
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 94
...into something groovier?
def entities = datastore.query {
select all from savedscript
sort desc by dateCreated
where author == params.author
limit 10 te d!
} as List m en
p le
et Im
o tY
N
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 94
URL Routing system (1/4)
• You can have friendly URL mappings with the URL
routing system
all "/aboutus",
redirect: "/blog/2008/10/20/about-us"
all "/blog/@year/@month/@day/@title",
@day@title=@title"
forward: "/blog.groovy?year=@year&month=@month@day=
get "/blog/@year/@month/@day",
@day"
forward: "/blog.groovy?year=@year&month=@month@day=
get "/book/isbn/@isbn",
forward: "/book.groovy?isbn=@isbn",
validate: { isbn ==~ /d{9}(d|X)/ }
– You’ll have to configure the RouteFilter in web.xml
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 95
URL Routing system (2/4)
• You can also define caching times
get "/aboutus", cache: 24.hours,
forward: "/aboutus.gtpl"
get "/breaking-news", cache: 1.minute,
forward: "/news.groovy?last=10"
– Nice for GAE’s infamous «loading requests»
•less critical with GAE SDK 1.4
– ability to reserve 3 instances (billing)
– warmup requests
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 96
URL Routing system (3/4)
• Special routes for specifying
– incoming emails
– jabber messages
email to "/incomingMail.groovy"
jabber to "/incomingXmpp.groovy"
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 97
URL Routing system (4/4)
• Namespace awareness: nice for multitenancy
• Capability awareness: for graceful degradation
// @cust customer variable could be « acme »
post "/@cust/update", forward: "/update.groovy",
namespace: { "ns-$cust" }
es status
// different destinations depending on the GAE servic
get "/speakers", forward {
to "/speakers.groovy" // default destination
// when the datastore is not available
to "/unavailable.gtpl" on DATASTORE not ENABLED
// show some maintenance is upcoming
to "/speakers.groovy?maintenance=true" on DATASTORE
is SCHEDULED_MAINTENANCE
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 98
Capabilities
• Google App Engine allows you to know the status
and availability of the various services
– DATASTORE, DATESTORE_WRITE, MEMCACHE...
– ENABLED, DISABLED, UNKNOWN,
SCHEDULED_MAINTENANCE
– is() and not() methods
if (capabilities[DATASTORE_WRITE].is(ENABLED)) {
// write some content in the datastore
} else {
// otherwise, redirect to some maintenance page
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 99
Task queue API
// access a configured queue using the subscript notation
queues['dailyEmailQueue']
// or using the property access notation
queues.dailyEmailQueue
// you can also access the default queue with:
queues.default
defaultQueue
// add a task to the queue
queue << [
countdownMillis: 1000, url: "/task/dailyEmail",
taskName: "sendDailyEmailNewsletter",
method: 'PUT', params: [date: '20090914'],
payload: content
]
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 100
Jabber / XMPP support (1/3)
• Sending instant messages
String recipient = "someone@gmail.com"
// check if the user is online
if (xmpp.getPresence(recipient).isAvailable()) {
// send the message
def status = xmpp.send(to: recipient,
body: "Hello, how are you?")
// checks the message was successfully
// delivered to all the recipients
assert status.isSuccessful()
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 101
Jabber / XMPP support (2/3)
• Sending instant messages with an XML payload
String recipient = "service@gmail.com"
// check if the service is online
if (xmpp.getPresence(recipient).isAvailable()) {
// send the message
def status = xmpp.send(to: recipient, xml: {
customers {
customer(id: 1) {
name 'Google'
}
}
})
// checks the message was successfully delivered to the service
assert status.isSuccessful()
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 102
Jabber / XMPP support (2/3)
• Sending instant messages with an XML payload
String recipient = "service@gmail.com"
// check if the service is online
if (xmpp.getPresence(recipient).isAvailable()) {
// send the message
def status = xmpp.send(to: recipient, xml: {
customers {
customer(id: 1) { <customers>
name 'Google' <customer id=’1’>
} <name>Google</name>
} </customer>
</customers>
})
// checks the message was successfully delivered to the service
assert status.isSuccessful()
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 102
Jabber / XMPP support (3/3)
• Receving incoming instant messages
– Once you’ve configured a route for jabber messages
– Add the inbound message service in appengine-web.xml
def message = xmpp.parseMessage(request)
// get the body of the message
message.body
// get the sender Jabber ID
message.from
// get the list of recipients Jabber IDs
message.recipients
// if the message is an XML document instead of a raw string message
if (message.isXml()) {
// get the raw XML
message.stanza
// get a document parsed with XmlSlurper
message.xml
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 103
Memcache service
• Map notation access to the cache
}
class Country implements Serialzable { String name
def countryFr = new Country(name: 'France')
in the cache
// use the subscript notation to put a country object
// (you can also use non-string keys)
memcache['FR'] = countryFr
// check that a key is present in the cache
if ('FR' in memcache) {
the cache using a key
// use the subscript notation to get an entry from
def countryFromCache = memcache['FR']
}
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 104
Closure memoization
• Cache the return values for each dinstinct
invocation (for a given arguments set)
->
def countEntities = memcache.memoize { String kind
datastore.prepare( new Query(kind) )
.countEntities()
}
// first call
def totalPics = countEntityes('photos')
// second call, hitting the cache
totalPics = countEntityes('photos')
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 105
Blobstore enhancements
• The blobstore allows to store some large content
– images, videos, etc.
def blob = ...
print blob.filename // contentType, creation, size
// output the content of the blob to the response
blob.serve response
// read the content of the blob
blob.withReader { Reader r -> ... }
blob.withStream { InputStream is -> ... }
// delete the blob
blob.delete()
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 106
Images service
• Readable DSL for manipulating images
def blobKey = ...
def image = blobKey.image.transform {
resize 1600, 1200
crop 0.1, 0.1, 0.9, 0.9
horizontal flip // vertical flip too
rotate 90
feeling lucky // image corrections
}
def thumbnail = image.resize(100, 100)
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 107
Channel Service
• For Comet-style applications
def token = channel.createChannel('clientID')
channel.send 'clientID', 'Hi!'
• Then in the view, in JavaScript...
channel = new goog.appengine.Channel(token);
socket = channel.open();
socket.onmessage = function(msg) { ... }
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 108
Simple plugin system (1/3)
• Gaelyk features a simple plugin system for
extending your apps and share commonalities
• A plugin lets you
– provide additional groovlets and templates
– contribute new URL routes
– add new categories
– define variables in the binding
– override existing binding variables
– provide any static content
– add new libraries
– do any initialization
– add before/after request hooks
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 109
Simple plugin system (2/3)
• A plugin is actually just a zip file!
– Basically, just a Gaelyk application, minus...
•the Groovy / Gaelyk / GAE JARs
•the web.xml and appengine-web.xml descriptors
– But with a /WEB-INF/plugins/myplugin.groovy
descriptor
• A plugin must be referenced in /WEB-INF/
plugins.groovy with
– install myplugin
•shortcut to /WEB-INF/plugins/myplugin.groovy
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 110
Simple plugin system (3/3)
• An example plugin descriptor
– /WEB-INF/plugins/jsonPlugin.groovy
import net.sf.json.*
import net.sf.json.groovy.*
// add new variables in the binding
binding {
le
jsonLibVersion = "2.3" // a simple string variab
of a 3rd‐party JAR
json = new JsonGroovyBuilder() // an instance of a class
}
// add new routes with the usual routing system format
routes {
get "/json", forward: "/json.groovy"
}
// install a category you've developped
categories jsonlib.JsonlibCategory
before { req, resp ‐> ... } // or after
// any other initialization code you'd need
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 111
a ry
m m
S u
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited.
Summary
• Easy access to a cloud solution
–Deploying Java apps, as easily as you would with PHP
• Familiar to Java folks
–Your good old Servlet centric webapps style
• Pretty cheap
–You need a high-trafficed website to reach the quotas
• Gaelyk provides a simplified approach to
creating Servlet centric webapps in a
productive manner
–Leveraging Groovy’s servlet / template support and
dynamic capabilities
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 113
What’s coming next?
• Expect more sugar around the Datastore
– An SQL-like query DSL
– Easier relationship management (builder?)
• Perhaps pre-compiled groovlets and templates
– Less needed since SDK 1.4
• (reserve 3 hot instances, warmup requests)
• Testing facilities specific to Gaelyk
–testing utility class, Spock-specific ones...
• Anything that’ll come up in newer GAE SDK versions
Copyright 2011 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 114