groovy update, groovy ecosystem, and gaelyk -- devoxx 2010 -- guillaume laforge

177
Groovy University Groovy update, Groovy ecosystem, and Gaelyk Guillaume Laforge Groovy Project Manager SpringSource, a divison of VMWare lundi 15 novembre 2010

Upload: guillaume-laforge

Post on 17-May-2015

2.791 views

Category:

Technology


8 download

DESCRIPTION

University (3 hours) presentation given at Devoxx 2010.

TRANSCRIPT

Page 1: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Groovy UniversityGroovy update, Groovy ecosystem, and Gaelyk

Guillaume LaforgeGroovy Project Manager

SpringSource, a divison of VMWare

lundi 15 novembre 2010

Page 2: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Guillaume Laforge• Groovy Project Manager• JSR-241 Spec Lead• Head of Groovy Development

at SpringSource• Initiator of the Grails framework• Founder of the Gaelyk toolkit• Co-author of Groovy in Action

• Speaker: JavaOne, QCon, JavaZone, Sun TechDays, Devoxx, The Spring Experience, SpringOne2GX, JAX, Dynamic Language World, IJTC, and more... 2

lundi 15 novembre 2010

Page 3: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Bug killer... real insects with legs!• Thanks to Groovy, with one hand left for coding,

I’m still more productive than with Java!

3

lundi 15 novembre 2010

Page 4: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Bug killer... real insects with legs!• Thanks to Groovy, with one hand left for coding,

I’m still more productive than with Java!

3

lundi 15 novembre 2010

Page 5: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Agenda: 3 big parts!

• Groovy Update– past / present / future

• Groovy’s Ecosystem– a rich and lively ecosystem

• Gaelyk, Groovy into the Cloud– a lightweight Groovy toolkit

for Google App Engine

4

lundi 15 novembre 2010

Page 6: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Groovy Update

Past, Present, FutureMajor features, and what’s cooking

lundi 15 novembre 2010

Page 7: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

6

lundi 15 novembre 2010

Page 8: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

looking into the Pastlundi 15 novembre 2010

Page 9: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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 8

lundi 15 novembre 2010

Page 10: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Multiple assignement

// multiple assignmentdef (a, b) = [1, 2]assert a == 1 && b == 2

// with typed variablesdef (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]

9

lundi 15 novembre 2010

Page 11: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

10

lundi 15 novembre 2010

Page 12: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

11

lundi 15 novembre 2010

Page 13: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

12

lundi 15 novembre 2010

Page 14: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

@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

13

lundi 15 novembre 2010

Page 15: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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)

    def ctx = new Context(srv , "/", SESSIONS)

    ctx.resourceBase = "."

    ctx.addServlet(GroovyServlet, "*.groovy")

    srv.start()}

14

lundi 15 novembre 2010

Page 16: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Metaprogramming additions (1/2)• ExpandoMetaClass DSL

–factoring EMC changes

Number.metaClass {    multiply { Amount amount ‐>         amount.times(delegate)     }    div { Amount amount ‐>         amount.inverse().times(delegate) 

    }}

15

lundi 15 novembre 2010

Page 17: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Metaprogramming additions (2/2)• Runtime mixins

class FlyingAbility {    def fly() { "I'm ${name} and I fly!" }

}

class JamesBondVehicle {    String getName() { "James Bond's vehicle" }

}

JamesBondVehicle.mixin FlyingAbility

assert new JamesBondVehicle().fly() ==

    "I'm James Bond's vehicle and I fly!"

16

lundi 15 novembre 2010

Page 18: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

JMX Builder• A DSL for handling JMX

–in addition of Groovy MBean

// Create a connector serverdef jmx = new JmxBuilder()jmx.connectorServer(port:9000).start()

// Create a connector clientjmx.connectorClient(port:9000).connect()

//Export a beanjmx.export { bean new MyService() }

// Defining a timerjmx.timer(name: "jmx.builder:type=Timer", 

    event: "heartbeat", period: "1s").start()

// JMX listenerjmx.listener(event: "someEvent", from: "bean", 

    call: { evt ‐> /* do something */ }) 17

lundi 15 novembre 2010

Page 19: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

into the Present...lundi 15 novembre 2010

Page 20: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

19

lundi 15 novembre 2010

Page 21: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

AIC and NC• Anonymous Inner Classes and Nested Classes

20

lundi 15 novembre 2010

Page 22: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

AIC and NC• Anonymous Inner Classes and Nested Classes

For Java

copy’n paste

compatibility

sake :-)

20

lundi 15 novembre 2010

Page 23: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Annonymous Inner Classes

boolean called = false

Timer timer = new Timer()

timer.schedule(new TimerTask() {

    void run() {

        called = true

    }}, 0)

sleep 100assert called

21

lundi 15 novembre 2010

Page 24: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Annonymous Inner Classes

boolean called = false

Timer timer = new Timer()

timer.schedule(new TimerTask() {

    void run() {

        called = true

    }}, 0)

sleep 100assert called

{ called = true } as TimerTask

21

lundi 15 novembre 2010

Page 25: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Nested Classes

class Environment {    static class Production         extends Environment {}

    static class Development         extends Environment {}

}

new Environment.Production()

22

lundi 15 novembre 2010

Page 26: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Anotations anywhere

• You can now put annotations–on imports–on packages–on variable declarations

• Examples with @Grab following...

23

lundi 15 novembre 2010

Page 27: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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"

24

lundi 15 novembre 2010

Page 28: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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"}}}'

25

lundi 15 novembre 2010

Page 29: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Grape improvements (3/4)• Groovy 1.7 introduced Grab resolver

–For when you need to specify a specific repositoryfor a given dependency

@GrabResolver(    name = 'restlet.org',    root = 'http://maven.restlet.org')

@Grab('org.restlet:org.restlet:1.1.6')

import org.restlet.Restlet

26

lundi 15 novembre 2010

Page 30: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Grape improvements (4/4)• Groovy 1.7.5 even further shrinks the grab

resolver definition:

27

@GrabResolver('http://maven.restlet.org')

@Grab('org.restlet:org.restlet:1.1.6')

import org.restlet.Restlet

lundi 15 novembre 2010

Page 31: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Power Asserts (1/2)• Much better assert statement!

–Invented and developed in the Spock framework

• Given this script...

def energy = 7200 * 10**15 + 1def mass = 80def celerity = 300000000

assert energy == mass * celerity ** 2

28

lundi 15 novembre 2010

Page 32: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Power Asserts (2/2)• You’ll get a more comprehensible output

29

lundi 15 novembre 2010

Page 33: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

30

lundi 15 novembre 2010

Page 34: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

AST Viewer

31

lundi 15 novembre 2010

Page 35: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

AST Builder

// Ability to build AST parts

// ‐‐> from a Stringnew AstBuilder().buildFromString(''' "Hello" '''

)

// ‐‐> from codenew AstBuilder().buildFromCode { "Hello" }

// ‐‐> from a specification

List<ASTNode> nodes = new AstBuilder().buildFromSpec {

    block {        returnStatement {

            constant "Hello"

        }    }}

32

lundi 15 novembre 2010

Page 36: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Customize the Groovy Truth!• Ability to customize the truth by implementing a boolean asBoolean() method

class Predicate {    boolean value    boolean asBoolean() { value }

}

def truePred  = new Predicate(value: true)

def falsePred = new Predicate(value: false)

assert truePred && !falsePred

33

lundi 15 novembre 2010

Page 37: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

SQL support refinements

// batch statementssql.withBatch { stmt ‐>

["Paul", "Jochen", "Guillaume"].each { name ‐>

 stmt.addBatch "insert into PERSON (name) values ($name)"

}}

// transaction supportdef persons = sql.dataSet("person")

sql.withTransaction {  persons.add name: "Paul"  persons.add name: "Jochen"

  persons.add name: "Guillaume"

  persons.add name: "Roshan"

}

34

lundi 15 novembre 2010

Page 38: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Groovy 1.7.x changes

• Since Groovy 1.7.0...Groovy 1.7.1, 1.7.2, 1.7.3, 1.7.4 and 1.7.5 have been released already!

• Here’s what’s new!

35

lundi 15 novembre 2010

Page 39: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Map improvements

// map auto‐vificationdef m = [:].withDefault { key ‐> "Default" }

assert m['z'] == "Default" 

assert m['a'] == "Default"

// default sortm.sort()

// sort with a comparatorm.sort({ a, b ‐> a <=> b } as Comparator)

36

lundi 15 novembre 2010

Page 40: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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.bookdef builder = new StreamingMarkupBuilder()

assert builder.bindNode(someNode).toString() ==

        "<book isbn='12345'>Groovy in Action</book>"

37

lundi 15 novembre 2010

Page 41: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Currying improvements

// right curryingdef divide = { a, b ‐> a / b }

def halver = divide.rcurry(2)

assert halver(8) == 4 // currying n‐th parameterdef joinWithSeparator = { one, sep, two ‐>

    one + sep + two}def joinWithComma =     joinWithSeparator.ncurry(1, ', ')

assert joinWithComma('a', 'b') == 'a, b'

38

lundi 15 novembre 2010

Page 42: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

New String methodsprintln """    def method() {        return 'bar'    }""".stripIndent()

println """    |def method() {    |    return 'bar'    |}""".stripMargin('|')

// string "translation" (UNIX tr)

assert 'hello'.tr('z‐a', 'Z‐A') == 'HELLO'

assert 'Hello World!'.tr('a‐z', 'A') == 'HAAAA WAAAA!'

assert 'Hello World!'.tr('lloo', '1234') == 'He224 W4r2d!'

// capitalize the first letter

assert 'h'.capitalize() == 'H'

assert 'hello'.capitalize() == 'Hello'

assert 'hello world'.capitalize() == 'Hello world'

// tab/space (un)expansion (UNIX expand command)

assert '1234567\t8\t '.expand() == '1234567 8        '

assert '    x    '.unexpand() == '    x\t '

39

lundi 15 novembre 2010

Page 43: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

...and beyond!lundi 15 novembre 2010

Page 44: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Groovy 1.8 & beyond

• Still subject to discussion• Always evolving roadmap• Things may change!

41

lundi 15 novembre 2010

Page 45: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

What’s cooking?lundi 15 novembre 2010

Page 46: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

What we’re working on• More runtime performance improvements• Closures

–annotation parameterscomposition, 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 43

lundi 15 novembre 2010

Page 47: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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 runtime44

lundi 15 novembre 2010

Page 48: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GContracts• Closures are already allowed in the Groovy 1.7

Antlr grammar–André Steingreß created GContracts,

a «design by contract» module

// a class invariant@Invariant({ 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() { ... }45

lundi 15 novembre 2010

Page 49: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Closure composition• Functional flavor!

46

def plus2  = { it + 2 }def times3 = { it * 3 } def composed1 = plus2 << times3assert composed1(3) == 11assert composed1(4) == plus2(times3(4))

 def composed2 = times3 << plus2assert composed2(3) == 15assert composed2(5) == times3(plus2(5))

 // reverse compositionassert composed1(3) == (times3 >> plus2)(3)

lundi 15 novembre 2010

Page 50: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Closure memoization• Memoization: remember the outcome of previous

(ideally side-effect free) invocations

47

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 cacheddef cAtMost = { ... }.memoizeAtMost(10)

// between 10 and 20 invocations cached

def cAtLeast = { ... }.memoizeBetween(10, 20)

lundi 15 novembre 2010

Page 51: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Closure trampoline• No more infamous StackOvervlow errors for

deeply recursive algorithms–if you use closure trampolines explicitely

48

def factfact = { int n, BigInteger accu ‐>

    n > 1 ? fact.curry(n ‐ 1, n * accu) : accu

}

def factorial = { int n ‐> fact(n, 1) }

assert factorial.trampoline(1)    == 1

assert factorial.trampoline(3)    == 6

assert factorial.trampoline(1000) == 402387260077...

lundi 15 novembre 2010

Page 52: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

New AST Transformations• Many new transformations coming up for removing even

more boiler plate code

49

@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@Canonical adding equals, hashCode, toString@EqualsAndHashCode only adding equals and hashCode@ToString only adding toString@TupleConstructor for adding a tuple constructor

lundi 15 novembre 2010

Page 53: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 54: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 55: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

More adhoc build

More modular Groovy

lundi 15 novembre 2010

Page 56: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

More modular build• «Not everybody needs everything!» ™

• A lighter Groovy-core–what’s in groovy-all?

• Modules–test, jmx, swing, xml, sql, web, template–integration (bsf, jsr-223)–tools (groovydoc, groovyc, shell, console, java2groovy)

51

lundi 15 novembre 2010

Page 57: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Java 7 / 8 / Project Coin• 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?)

52

lundi 15 novembre 2010

Page 58: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Java 7 / 8 / Project Coin• 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?)

52

lundi 15 novembre 2010

Page 59: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Java 7 / 8 / Project Coin• 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?)

52

lundi 15 novembre 2010

Page 60: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Java 7 / 8 / Project Coin• 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?)

52

lundi 15 novembre 2010

Page 61: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Java 7 / 8 / Project Coin• 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?)

52

lundi 15 novembre 2010

Page 62: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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)*

53

lundi 15 novembre 2010

Page 63: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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)

54

lundi 15 novembre 2010

Page 64: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

55

lundi 15 novembre 2010

Page 65: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

Less parens& commas

55

lundi 15 novembre 2010

Page 66: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Groovy UpdateSummary

lundi 15 novembre 2010

Page 67: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Summary

• No need to wait for Java 7, 8, 9...–closures, properties, interpolated strings, extended

annotations, metaprogramming, [YOU NAME IT]...

57

lundi 15 novembre 2010

Page 68: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Summary

• No need to wait for Java 7, 8, 9...–closures, properties, interpolated strings, extended

annotations, metaprogramming, [YOU NAME IT]...

Groovy’s still

innovative

since 2003!

57

lundi 15 novembre 2010

Page 69: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Summary

• No need to wait for Java 7, 8, 9...–closures, properties, interpolated strings, extended

annotations, metaprogramming, [YOU NAME IT]...

Groovy’s still

innovative

since 2003!

57

lundi 15 novembre 2010

Page 70: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Q&A

lundi 15 novembre 2010

Page 71: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Groovy Ecosystem

A very rich & lively ecosystemFor concurrency, for testing,

for building applications...

lundi 15 novembre 2010

Page 72: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

The Groovy Ecosystem• Many projects based on Groovy• Serve various purposes:

–build applications (ie. frameworks)• Grails (web apps), Griffon (Swing apps),Gaelyk (Google App Engine)

–tame new concurrency paradigms• GPars (actors, agents, fork/join, map/filter/reduce...)

–enhanced testing• Easyb (BDD), Spock, Gmock (mocking), SoapUI (WS)

–help building projects• Gant (ant sugar), Gradle (adhoc build system)

–web services interaction60

lundi 15 novembre 2010

Page 73: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Grails

–Don’t miss Graeme’s session on Grails!–And Christian on Eclipse tooling for Groovy and Grails

61

lundi 15 novembre 2010

Page 74: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Griffon (1/4)• Griffon is a Grails-like application framework for

developing rich desktop applications

–MVC, DRY, CoC patterns

–Easy threading,data binding and observing

–Support in IDEs

62

lundi 15 novembre 2010

Page 75: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Griffon (2/4)• Let’s create a simple demo console

for executing Groovy scripts

• A data model

63

import groovy.beans.Bindable

class DemoConsoleModel {

String scriptSource

@Bindable def scriptResult

@Bindable boolean enabled = true

}

lundi 15 novembre 2010

Page 76: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Griffon (3/4)• A controller

64

class DemoConsoleController {

GroovyShell shell = new GroovyShell()

// automatically injected by Griffon

def model, view

def executeScript(ActionEvent evt = null) {

model.enabled = false

doOutside {

def result = shell.evaluate(model.scriptSource)

edt { model.enabled = true

model.scriptResult = result

} } }}

lundi 15 novembre 2010

Page 77: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Griffon (4/4)• And a view

65

application(title: 'DemoConsole', pack: true, locationByPlatform: true) {

panel(border: emptyBorder(6)) {

borderLayout()

scrollPane(constraints: CENTER) {

textArea(text: bind(target: model, targetProperty: 'scriptSource'),

enabled: bind { model.enabled },

columns: 40, rows: 10)

}

hbox(constraints: SOUTH) {

button("Execute", actionPerformed: controller.&executeScript,

enabled: bind { model.enabled })

hstrut 5 label "Result:"

hstrut 5 label text: bind { model.scriptResu

lt }

} }}

lundi 15 novembre 2010

Page 78: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Griffon (4/4)• And a view

65

application(title: 'DemoConsole', pack: true, locationByPlatform: true) {

panel(border: emptyBorder(6)) {

borderLayout()

scrollPane(constraints: CENTER) {

textArea(text: bind(target: model, targetProperty: 'scriptSource'),

enabled: bind { model.enabled },

columns: 40, rows: 10)

}

hbox(constraints: SOUTH) {

button("Execute", actionPerformed: controller.&executeScript,

enabled: bind { model.enabled })

hstrut 5 label "Result:"

hstrut 5 label text: bind { model.scriptResu

lt }

} }}

lundi 15 novembre 2010

Page 79: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GPars (1/6)

• Actors, dataflow, concurrency, and more–for harnessing our

multicore platforms

• GPars web site:–http://gpars.codehaus.org

66

lundi 15 novembre 2010

Page 80: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GPars (2/6)• Improving over JSR-166y’s ParallelArray

• Asynchronous closures returning Futures

67

GParsPool.withPool { // using fork/join

// a map-reduce functional style

def smallestSelfPortrait =

images.parallel.filter { it.contains me }

.map { it.resize() }

.min { it.sizeInMB }

}

GParsExecutorsPool.withPool { // using JDK executors

// adds callAsync() to closures

assert 6 == { it * 2 }.callAsync(3).get()

}

lundi 15 novembre 2010

Page 81: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GPars (3/6)• Improving over JSR-166y’s Fork / Join

68

withPool(2) { pool ->

println "Number of files: " +

runForkJoin(new File("./src")) { File file ->

long count = 0

file.eachFile {

if (it.isDirectory()) {

println "Forking a child task for $it"

// fork a child task

forkOffChild(it)

} else {

count++

} } // use results of children task

s

// to calculate and store own result

return count + childrenResults.sum(0)

}}

lundi 15 novembre 2010

Page 82: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GPars (4/6)• Actors

–(see also dynamic dispatch actors, and more) 69

loop { println 'Waiting for a gift'

react { gift -> if (myWife.likes(gift)) {

reply 'Thank you!'

} else { reply 'Try again, please'

react { anotherGift ->

if (myChildren.like(anotherGift))

reply 'Thank you!'

} } }}

lundi 15 novembre 2010

Page 83: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GPars (5/6)• DataFlow concurrency

70

new DataFlows().with {

task { z = x + y println "Result: ${z.val}"

}

task { x = 10 } task { y = 5 }}

lundi 15 novembre 2010

Page 84: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GPars (6/6)• Agents

71

class Conference extends Agent<Integer> {

def Conference() { super(0) }

private register(long num) { data += num }

private unregister(long num) { data -= num }

}

final Agent conference = new Conference()

// send commands in parallel threads

final Thread t1 = Thread.start {

conference << { register 10 }

}final Thread t2 = Thread.start {

conference << { register 5 }

}final Thread t3 = Thread.start {

conference << { unregister 3 }

}

[t1, t2, t3]*.join()assert 12 == conference.val

lundi 15 novembre 2010

Page 85: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Easyb (1/4)• From the website:

–«Easyb is a behavior driven development (BDD) framework for the Java platform. By using a specification based Domain-Specific Language, Easyb aims to enable executable, yet readable documentation»

• Write specifications in Groovy• Run them from CLI, Maven, or Ant

–provides various report formats• BDD == given / when / then paradigm

72

lundi 15 novembre 2010

Page 86: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Easyb (2/4)• First, let’s write a story

73

given "an invalid zip code"

and "given the zipcodevalidator is initialized"

when "validate is invoked with the invalid zip code"

then "the validator instance should return false"

lundi 15 novembre 2010

Page 87: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Easyb (3/4)• Let’s write the test itself

74

given "an invalid zip code", { invalidzipcode = "221o1"}

and "given the zipcodevalidator is initialized", {

zipvalidate = new ZipCodeValidator()

}

when "validate is invoked with the invalid zip code", {

value = zipvalidate.validate(invalidzipcode)

}

then "the validator instance should return false", {

value.shouldBe false}

lundi 15 novembre 2010

Page 88: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Easyb (4/4)• There’s also the specification format

75

before "initialize zipcodevalidator instance", {

zipvalidate = new ZipCodeValidator()

}

it "should deny invalid zip codes", {

["221o1", "2210", "22010-121o"].each { zip ->

zipvalidate.validate(zip).is false

}}

it "should accept valid zip codes", {

["22101", "22100", "22010-1210"].each { zip ->

zipvalidate.validate(zip).shouldBe true

}}

lundi 15 novembre 2010

Page 89: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Spock (1/3)• From the horse’s mouth:

–« Spock is a testing and specification framework for Java and Groovy applications. What makes it stand out from the crowd is its beautiful and highly expressive specification language. »

76

class HelloSpock extends Specification {

    def "can you figure out what I'm up to?"() {

        expect:        name.size() == size

        where:        name | size

"Kirk" | 4 "Spock" | 5 "Scotty" | 6    }}

lundi 15 novembre 2010

Page 90: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Spock (2/3)• Extensible (but transparent) use of AST

transformations to «pervert» the Groovy language–reuse of labels for the BDD actions

• Spock brought Groovy 1.7’s enhanced asserts

77

Condition not satisfied:

max(a, b) == c|   |  |  |  |3   1  3  |  2          false

lundi 15 novembre 2010

Page 91: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Spock (3/3)• Another example of the expressive language

–with powerful mocking capabilities

78

def "subscribers receive published events at least once"() {

    when: publisher.send(event)

  then: (1.._) * subscriber.receive(event)

    where: event << ["started", "paused", "stopped"]

}

lundi 15 novembre 2010

Page 92: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GMock (1/3)• GMock is a mocking framework for Groovy

• Mocking capabilities

79

File mockFile = mock(File, constructor("/a/path/file.txt"))

mockFile.getName().returns("file.txt")

play {  def file = new File("/a/path/file.txt")

  assertEquals "file.txt", file.getName()

}

–method calls–property access–static calls–partial mocks

–constructor calls–time matching–order matching–regex method matching

lundi 15 novembre 2010

Page 93: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GMock (2/3)• Mocking method calls

• Mock static calls

80

def loader = mock()loader.put("fruit").returns("apple")

play {  assertEquals "apple", loader.put("fruit"

)

}

def mockMath = mock(Math)mockMath.static.random().returns(0.5)

play {    assertEquals 0.5, Math.random()

}

lundi 15 novembre 2010

Page 94: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GMock (3/3)

81

• Expecting exceptions

• Time matching–never, once, atLeastOnce, atMostOnce, stub, times,

atLeast, atMost

loader.put("throw exception").raises(RuntimeException, "an exception")

mockLoader.load(2).returns(3).atLeastOnce()

play {    assertEquals 3, mockLoader.load(2)

    assertEquals 3, mockLoader.load(2)

}

lundi 15 novembre 2010

Page 95: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Gant• Gant is a tool for scripting Ant tasks using Groovy

instead of XML to specify the logic

82

includeTargets << gant.targets.Clean

cleanPattern << ['**/*~', '**/*.bak']

cleanDirectory << 'build'

target(stuff: 'A target to do some stuff.') {

println 'Stuff' depends clean echo message: 'A default message from A

nt.'

otherStuff()}

target(otherStuff: 'A target to do some other stuff') {

println 'OtherStuff'

echo message: 'Another message from Ant.'

clean()}

setDefaultTarget stuff

lundi 15 novembre 2010

Page 96: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Gradle (1/3)• Gradle is an enterprise-grade build system

–A very flexible general purpose build tool like Ant–Switchable, build-by-convention frameworks à la

Maven, for Java, Groovy and Scala projects–Groovy build scripts–Powerful support for multi-project builds–Dependency management based on Ivy–Full support for existing Maven or Ivy repository infra–Support for transitive dependency management–Ant tasks and builds as first class citizens

83

lundi 15 novembre 2010

Page 97: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Gradle (2/3)• For example, for a classical Java project

84

apply plugin: ‘java’

repositories { mavenCentral()}

dependencies { compile group: ‘commons-collection’,

module: ‘commons-collection’, version: ‘3.2’

testCompile group: ‘junit’,

module: ‘junit’, version: ‘4.+’

}

lundi 15 novembre 2010

Page 98: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Gradle (3/3)• Major projects migrate to Gradle

–Hibernate–Various SpringSource projects–Groovy -based projects: Grails, Groovy, GPars, Gaelyk–Customers with 200+ multi-projects

85

lundi 15 novembre 2010

Page 99: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Other build and quality tools• You can use Ant, Gant, Maven (GMaven plugin)

or Gradle to build your projects–fits nicely in any existing build and continuous

integration infrastructure

• A few Groovy-friendly tools provide handy metrics–CodeNarc: provides various rules for static analysis of

your Groovy codebase (style, size, braces, naming...)–Simian: detects duplication in your Groovy code base–Cobertura, Clover: give code coverage metrics

86

lundi 15 novembre 2010

Page 100: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

HTTPBuilder (1/3)• HTTPBuilder provides a convenient builder API

for complex HTTP requests

87

def http = new HTTPBuilder( 'http://ajax.googleapis.com' )

http.request(GET, JSON) {

uri.path = '/ajax/services/search/web'

uri.query = [v: '1.0', q: 'Calvin and Hobbes']

headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'

response.success = { resp, json ->

println resp.statusLine

json.responseData.results.each {

println " ${it.titleNoFormatting}: ${it.visibleUrl}"

} }}

lundi 15 novembre 2010

Page 101: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

HTTPBuilder (2/3)• Posting to a URL

88

import groovyx.net.http.HTTPBuilder

import static groovyx.net.http.ContentType.URLENC

 def http = new HTTPBuilder( 'http://twitter.com

/statuses/' )

def postBody = [status: 'update!', source: 'httpbuilder']

http.post( path: 'update.xml', body: postBody,

           requestContentType: URLENC ) { resp ‐>

     println "Tweet response status: ${resp.stat

usLine}"

    assert resp.statusLine.statusCode == 200

}

lundi 15 novembre 2010

Page 102: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

HTTPBuilder (3/3)• Posting XML content to a URL

89

http.request(POST, XML) {    body = {        auth {            user 'Bob'            password 'pass'

        }    }}

lundi 15 novembre 2010

Page 103: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GroovyWS (1/2)• Publishing and consuming WS-I

compliant SOAP web services

• Can also deal with complex objects

90

import groovyx.net.ws.WSClient

def proxy = new WSClient(

"http://www.w3schools.com/webservices/tempconvert.asmx?WSDL",

this.class.classLoader)

proxy.initialize()

def result = proxy.CelsiusToFahrenheit(0)

println "You are probably freezing at ${result} degrees Farhenheit"

lundi 15 novembre 2010

Page 104: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GroovyWS (2/2)• Publishing a service

–considering a service

–publishing the service

91

class MathService {

double add(double arg0, double arg1) { arg0 + arg1 }

double square(double arg0) { arg0 * arg0 }

}

import groovyx.net.ws.WSServer

def server = new WSServer()

server.setNode("MathService", "http://localhost:6980/MathService")

server.start()

lundi 15 novembre 2010

Page 105: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

EcosystemSummary

lundi 15 novembre 2010

Page 106: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Summary• «Groovy» is way more than just a language!

• It’s also a very rich and active ecosystem!–Grails, Griffon, Gradle, GPars, Spock, Gaelyk...

93

lundi 15 novembre 2010

Page 107: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Q&A

lundi 15 novembre 2010

Page 108: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Gaelyk

A lightweight Groovy toolkitFor developing web applications

on Google App Engine

lundi 15 novembre 2010

Page 109: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

CloudComputing

lundi 15 novembre 2010

Page 110: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

IaaS, PaaS, SaaS

• Software as a Service–Gmail, SalesForce.com

• Platform as a Service–Google App Engine

• Infrastructure as a Service–Amazon EC2

SaaS

PaaS

IaaS97

lundi 15 novembre 2010

Page 111: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

IaaS, PaaS, SaaS

• Software as a Service–Gmail, SalesForce.com

• Platform as a Service–Google App Engine

• Infrastructure as a Service–Amazon EC2

SaaS

PaaS

IaaS97

lundi 15 novembre 2010

Page 112: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

IaaS, PaaS, SaaS

• Software as a Service–Gmail, SalesForce.com

• Platform as a Service–Google App Engine

• Infrastructure as a Service–Amazon EC2

SaaS

PaaS

IaaS97

lundi 15 novembre 2010

Page 113: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Google App Engine• Google’s PaaS solution• Run your app on Google’s infrastructure

• Initially just Python supported

• 1+ year ago, Java supported added too–Sandboxed JVM–Jetty servlet container

• Several JVM-compatible language supported98

lundi 15 novembre 2010

Page 114: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Key aspects• You can use most of your usual web frameworks for

developping apps on App Engine Java–A WAR file, basically!–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 99

lundi 15 novembre 2010

Page 115: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Available services• Memcache

–JCache implementation–Save on CPU and DB

• URL Fetch–Access remote resources–HttpUrlConnection

• Mail–Support both incoming

and outgoing emails

• Images–Resize, crop, rotate...

• XMPP

–Send / receive Jabber messages (GTalk)

• User–Use Google’s user/

authentication system–OAuth support

• Cron & Task queues–Schedule tasks at regular

intervals–Queue units of work

• Blobstore–For storing large content

• And much more...100

lundi 15 novembre 2010

Page 116: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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 101

lundi 15 novembre 2010

Page 117: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Quotas

102

lundi 15 novembre 2010

Page 118: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Quotas (1/2)• Bandwidth

–1,3M requests/day–1GB/day in/out–6.5 CPU hours/day

• Datastore–10M calls–1GB/day–12GB in / 115GB out–60 CPU hours/day

• Mail–7K calls/day–2K recepients/day–5K emails/day–2K attachments–100MB of attachments

• URL Fetch–657K calls/day–4GB in/out /day

103

lundi 15 novembre 2010

Page 119: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Quotas (2/2)• XMPP

–657K calls/day–4GB data sent/day–657K recepients/day–1MB invitations/day

• Image manipulation–864 calls/day–1GB in / 5GB out–2.5M transforms

• Memcache–8.6M calls/day–10GB in–50GB out

• Task queues–100K calls

104

lundi 15 novembre 2010

Page 120: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Quotas (2/2)• XMPP

–657K calls/day–4GB data sent/day–657K recepients/day–1MB invitations/day

• Image manipulation–864 calls/day–1GB in / 5GB out–2.5M transforms

• Memcache–8.6M calls/day–10GB in–50GB out

• Task queues–100K calls

104

Outdate

d figures

lundi 15 novembre 2010

Page 121: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

The Datastore

lundi 15 novembre 2010

Page 122: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

The datastore...• It’s 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

106

lundi 15 novembre 2010

Page 123: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

...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 transaction107

lundi 15 novembre 2010

Page 124: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Nice dashboard

lundi 15 novembre 2010

Page 125: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

F

http://gaelyk.appspot.com

lundi 15 novembre 2010

Page 126: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

F

http://gaelyk.appspot.com

lundi 15 novembre 2010

Page 127: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Gaelyk• 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

110

lundi 15 novembre 2010

Page 128: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

• The truth: We worked with the Google App Engine Java team before the official launch of the platform, to ensure Groovy would run well on this new environment, and Gaelyk emerged from our test-bed project, and people asked me to Open-Source it!111

lundi 15 novembre 2010

Page 129: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 130: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 131: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 132: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 133: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 134: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 135: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 136: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 137: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 138: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 139: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

lundi 15 novembre 2010

Page 140: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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/

lundi 15 novembre 2010

Page 141: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

The web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">

<servlet> <servlet-name>GroovletServlet</servlet-name>

<servlet-class>groovyx.gaelyk.GaelykServlet</servlet-class>

</servlet> <servlet> <servlet-name>TemplateServlet</servlet-name>

<servlet-class>groovyx.gaelyk.GaelykTemplateServlet</servlet-class>

</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>

<welcome-file-list> <welcome-file>index.gtpl</welcome-file>

</welcome-file-list></web-app>

114

lundi 15 novembre 2010

Page 142: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

MVC: Groovlets and templates

Groovlets(controllers)

Templates(views)

En55es(domain)

115lundi 15 novembre 2010

Page 143: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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 }}

116

lundi 15 novembre 2010

Page 144: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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 }}

116

Auto‐re

loading

lundi 15 novembre 2010

Page 145: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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>

117

lundi 15 novembre 2010

Page 146: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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>

117

Auto‐re

loading

lundi 15 novembre 2010

Page 147: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Shortcuts• Google services

– datastore– blobstore– memcache– capabilities– images– urlFetch– mail– userService / user– defaultQueue / queues– xmpp– namespace

• Variables available– request / response– context / application– sessions– params / headers– out / sout / html– localMode / app.*

• Methods available– include / forward / redirect– println / print

118

lundi 15 novembre 2010

Page 148: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

DEMO

lundi 15 novembre 2010

Page 149: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Groovy sugar!

lundi 15 novembre 2010

Page 151: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

...compared to Java

Properties props = new Properties();

Session session = Session.getDefaultInstance(props, null);

String msgBody = "...";

try { Message msg = new MimeMessage(session);

    msg.setFrom(new InternetAddress("[email protected]", "Admin"));

    msg.addRecipient(Message.RecipientType.TO,

                     new InternetAddress("[email protected]", "Mr. User"));

    msg.setSubject("Your Example.com account has been activated");

    msg.setText(msgBody);

    Transport.send(msg);} catch (AddressException e) {}

} catch (MessagingException e) {}

122

lundi 15 novembre 2010

Page 152: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Accessing the datastore• Direct interaction with the low-level datastore API

import com.google.appengine.api.datastore.Entity

 Entity entity = new Entity("person") // subscript notation, like when accessing a map

entity['name'] = "Guillaume Laforge" // normal property access notationentity.age = 32

entity.save()entity.delete()

datastore.withTransaction { // do stuff with your entities // within the transaction}

123

lundi 15 novembre 2010

Page 153: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Querying to be improved...

import com.google.appengine.api.datastore.*import static com.google.appengine.api.datastore.FetchOptions.Builder.* // query the scripts stored in the datastoredef query = new Query("savedscript") // sort results by descending order of the creation datequery.addSort("dateCreated", Query.SortDirection.DESCENDING) // filters the entities so as to return only scripts by a certain authorquery.addFilter("author", Query.FilterOperator.EQUAL, params.author)

 PreparedQuery preparedQuery = datastore.prepare(query) // return only the first 10 resultsdef entities = preparedQuery.asList( withLimit(10) )

124

lundi 15 novembre 2010

Page 154: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

...into something groovier?

def entities = datastore.query { select all from savedscript sort desc by dateCreated where author == params.author limit 10} as List

125

lundi 15 novembre 2010

Page 155: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

...into something groovier?

def entities = datastore.query { select all from savedscript sort desc by dateCreated where author == params.author limit 10} as List

Not Yet

 Implem

ented!

125

lundi 15 novembre 2010

Page 156: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Task queue API// access a configured queue using the subscript notationqueues['dailyEmailQueue'] // or using the property access notationqueues.dailyEmailQueue // you can also access the default queue with:queues.defaultdefaultQueue

// add a task to the queuequeue << [ countdownMillis: 1000, url: "/task/dailyEmail", taskName: "sendDailyEmailNewsletter", method: 'PUT', params: [date: '20090914'], payload: content]

126

lundi 15 novembre 2010

Page 157: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Jabber / XMPP support (1/3)• Sending instant messages

String recipient = "[email protected]" // check if the user is onlineif (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()}

127

lundi 15 novembre 2010

Page 158: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Jabber / XMPP support (2/3)• Sending instant messages with an XML payload

String recipient = "[email protected]" // check if the service is onlineif (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()}

128

lundi 15 novembre 2010

Page 159: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Jabber / XMPP support (2/3)• Sending instant messages with an XML payload

String recipient = "[email protected]" // check if the service is onlineif (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()}

<customers> <customer id=’1’> <name>Google</name>

</customer></customers>

128

lundi 15 novembre 2010

Page 160: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Jabber / XMPP support (3/3)• Receving incoming instant messages

–Configure the XmppServlet in web.xml–Add the inbound message service in appengine-

web.xml

// get the body of the messagemessage.body// get the sender Jabber IDmessage.from// get the list of recipients Jabber IDsmessage.recipients // if the message is an XML document instead of a raw string messageif (message.isXml()) { // get the raw XML message.stanza // get a document parsed with XmlSlurper message.xml}

129

lundi 15 novembre 2010

Page 161: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Memcache service• Map notation access to the cache

class Country implements Serialzable { String name } def countryFr = new Country(name: 'France') // use the subscript notation to put a country object in the cache

// (you can also use non-string keys)memcache['FR'] = countryFr // check that a key is present in the cacheif ('FR' in memcache) { // use the subscript notation to get an entry from the cache using a key

def countryFromCache = memcache['FR']}

130

lundi 15 novembre 2010

Page 162: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Closure memoization• Cache the return values for each dinstinct

invocation (for a given arguments set)

131

def countEntities = memcache.memoize { String kind -> datastore.prepare( new Query(kind) ) .countEntities()}

// first calldef totalPics = countEntityes('photos')

// second call, hitting the cachetotalPics = countEntityes('photos')

lundi 15 novembre 2010

Page 163: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Blobstore enhancements• The blobstore allows to store some large content

–images, videos, etc.

132

def blob = ...print blob.filename // contentType, creation, size

// output the content of the blob to the responseblob.serve response

// read the content of the blobblob.withReader { Reader r -> ... }blob.withStream { InputStream is -> ... }

// delete the blobblob.delete()

lundi 15 novembre 2010

Page 164: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Images service• Readable DSL for manipulating images

133

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)

lundi 15 novembre 2010

Page 165: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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

134

if (capabilities[DATASTORE_WRITE].is(ENABLED)) { // write some content in the datastore} else { // otherwise, redirect to some maintenance page}

lundi 15 novembre 2010

Page 166: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

URL Routing system (1/3)• You can have friendly URL mappings with the

URL routing system

–You’ll have to configure the RouteFilter in web.xml

all "/blog/@year/@month/@day/@title", forward: "/blog.groovy?year=@year&month=@month@day=@day@title=@title"

get "/blog/@year/@month/@day", forward: "/blog.groovy?year=@year&month=@month@day=@day"

all "/aboutus", redirect: "/blog/2008/10/20/about-us"

get "/book/isbn/@isbn", forward: "/book.groovy?isbn=@isbn", validate: { isbn ==~ /\d{9}(\d|X)/ }

135

lundi 15 novembre 2010

Page 167: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

URL Routing system (2/3)• You can also define caching times

–Nice for GAE’s infamous «loading requests»

get "/aboutus", cache: 24.hours, forward: "/aboutus.gtpl"

get "/breaking-news", cache: 1.minute, forward: "/news.groovy?last=10"

136

lundi 15 novembre 2010

Page 168: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

URL Routing system (3/3)• Namespace awareness: nice for multitenancy• Capability awareness: for graceful degradation

137

// @cust customer variable could be « acme »post "/@cust/update", forward: "/update.groovy", namespace: { "ns-$cust" }

// different destinations depending on the GAE services status

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}

lundi 15 novembre 2010

Page 169: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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–provide any static content–add new libraries–do any initialization

138

lundi 15 novembre 2010

Page 170: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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.groovy139

lundi 15 novembre 2010

Page 171: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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 bindingbinding {

jsonLibVersion = "2.3"          // a simple string variable

json = new JsonGroovyBuilder()  // an instance of a class of a 3rd‐party JAR

} // add new routes with the usual routing system format

routes {get "/json", forward: "/json.groovy"

} // install a category you've developped

categories jsonlib.JsonlibCategory // any other initialization code you'd need

140

lundi 15 novembre 2010

Page 172: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

GaelykSummary

lundi 15 novembre 2010

Page 173: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

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 capabilities142

lundi 15 novembre 2010

Page 174: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

What’s coming next?• Gaelyk 0.5.6 released couple weeks ago with

additional URL routing support –capabilities, namespace support

• Expect more sugar around the Datastore–An SQL-like query DSL–Easier relationship management (builder)

• Perhaps pre-compiled groovlets and templates• Testing facilities specific to Gaelyk• More generally...

–Anything that’ll come up in upcoming GAE SDK versions

143

lundi 15 novembre 2010

Page 175: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Q&A

lundi 15 novembre 2010

Page 177: Groovy Update, Groovy Ecosystem, and Gaelyk -- Devoxx 2010 -- Guillaume Laforge

Images used in this presentationThree fingers http://markyoungtrainingsystems.com/wp-content/uploads/2009/10/three-fingers.jpgBandage http://image.made-in-china.com/2f0j00fIGaTPEYDQnB/Elastic-Crepe-Bandage-Gauze-.jpgRIP http://gipsydan.files.wordpress.com/2009/11/rip.jpgHouse / past: http://www.flickr.com/photos/jasonepowell/3680030831/sizes/o/Present clock: http://www.flickr.com/photos/38629278@N04/3784344944/sizes/o/Future: http://www.flickr.com/photos/befuddledsenses/2904000882/sizes/l/Cooking: http://www.flickr.com/photos/eole/449958332/sizes/l/Puzzle: http://www.everystockphoto.com/photo.php?imageId=263521Light bulb: https://newsline.llnl.gov/retooling/mar/03.28.08_images/lightBulb.pngSpeed limit : http://www.morguefile.com/archive/display/18492Warehouse : http://www.morguefile.com/archive/display/85628Check mark: http://www.lnl.infn.it/~epics/WikiDumps/localhost/600px-symbol_ok.svg.pngPuzzle: http://www.everystockphoto.com/photo.php?imageId=263521Light bulb: https://newsline.llnl.gov/retooling/mar/03.28.08_images/lightBulb.pngClouds http://www.morguefile.com/archive/display/627059http://www.morguefile.com/archive/display/625552http://www.morguefile.com/archive/display/629785Duke ok GAE http://weblogs.java.net/blog/felipegaucho/archive/ae_gwt_java.pngPython logo : http://python.org/images/python-logo.gifGaelyc cross with clouds : http://www.morguefile.com/archive/display/37889Speed limit : http://www.morguefile.com/archive/display/18492Warehouse : http://www.morguefile.com/archive/display/85628Snow foot steps : http://www.flickr.com/photos/robinvanmourik/2875929243/Sugar : http://www.flickr.com/photos/ayelie/441101223/sizes/l/Press release: http://www.napleswebdesign.net/wp-content/uploads/2009/06/press_release_11.jpgGreen leaf: http://www.flickr.com/photos/epsos/3384297473/Jeepers creepers: http://www.flickr.com/photos/27663074@N07/3413698337/Earth: http://www.flickr.com/photos/wwworks/2222523978/Trafic light: http://rihancompany.com/var/243/35581-Traffic%20light%20drawing.jpgButt kick: http://www.brentcsutoras.com/wp-content/uploads/2009/12/kick-ass-1.jpgGriffon: http://aldaria02.a.l.pic.centerblog.net/lz2levrz.jpgSoap: http://www.flickr.com/photos/geishaboy500/104137788/

146

lundi 15 novembre 2010