© ASERT 2008-2010




                    Make Your Builds More Groovy
                                 Dr Paul King
                                 paulk@asert.com.au
                                 @paulk_asert
                                 ASERT, Australia
                                                      ESDC 2010 - 1
Topics
                    Build Pain Points
                    • Build Tool Landscape
                    • Groovy Intro
                    • Ant & friends
                    • Maven & friends
© ASERT 2008-2010




                    • Gradle
                    • Other Tools
                    • More Info



                                               ESDC 2010 - 2
Build Pain Points...
                    • Has anyone seen?
                      –   Large monolithic balls of mud
                      –   Complex usage, assumptions, conventions
                      –   Impossible to bend in desired ways
                      –   Never been (can't be) refactored/tested
                      –
© ASERT 2008-2010




                          Many manual steps
                      –   Environment fragile
                           • different machines, CI vs IDE, dev vs prod vs test




                                                                                  ESDC 2010 - 3
...Build Pain Points...
                    • Require powerful features
                      –   Dependency management
                      –   Version management
                      –   Polyglot compilation
                      –   Artifact production and manipulation (jar, war, ...)
                      –   Templating (generation of boilerplate text files)
© ASERT 2008-2010




                      –   Multifacted testing
                      –   Reporting
                      –   Quality control (Metrics, code quality, static analysis)
                      –   Property management
                      –   Infinitely(?) extensible



                                                                             ESDC 2010 - 4
...Build Pain Points
                    • Useful characteristics
                      –   Tool friendly
                      –   Cross platform
                      –   IDE support, CI support
                      –   Refactorable
                      –   Testable
© ASERT 2008-2010




                      –   Minimal noise (DSL like)
                      –   Easy to extend
                      –   Conventions
                      –   Good documentation
                      –   Polyglot friendly



                                                           ESDC 2010 - 5
Topics
                    • Build Pain Points
                    Build Tool Landscape
                    • Groovy Intro
                    • Ant & friends
                    • Maven & friends
© ASERT 2008-2010




                    • Gradle
                    • Other Tools
                    • More Info



                                             ESDC 2010 - 6
Build Tools
                    • Non-exhaustive list
                      – Ant, Maven, EasyAnt
                      – Gant, GMaven, Gradle, Graven (uptake?),
                        Groovy Frontend for Ant (emerge from sandbox?)
                      – Rake, Raven, Buildr
                      – Make, SCons, Waf
© ASERT 2008-2010




                      – MSBuild, Nant
                    • Used by
                      – Developers: NetBeans, Eclipse, Intellij, Command-line
                      – CI: Hudson (Groovy support and console), Team City,
                        CruiseControl, AnthillPro (Groovy support), Bamboo
                      – Deployment Management: Tableaux (Groovy support)
                      – Ad-hoc: batch processing, production applications
                                                                         ESDC 2010 - 7
Pros/Cons of Traditional Tools
                    • Ant                           • Maven
                      – Flexible (supports any        – Opinionated about
                        convention)                     conventions
                      – Easy to extend                   • Mostly a good thing
                      – Wealth of useful tasks        – Mostly declarative
                      – Well documented                  • XML != concise DSL
                                                      – Numerous plugins
© ASERT 2008-2010




                      – Partially declarative but
                        some scope for                – Some easy extension
                        procedural instructions         points but some more
                         • XML != prog. language        difficult options
                      – Lifecycle is hand-crafted        • Some things beyond
                                                           some teams
                        in your build file
                                                      – Structured lifecycle
                      – Can use Ivy or Maven Ant
                        tasks for dependency
                        management
                                                                           ESDC 2010 - 8
Enhancing Traditional Tools
                    • Ant + Groovy                 • Maven + Groovy
                      – Easy to write the            – Easier to extend
                        procedural pieces            – More concise syntax
                      – Easier to refactor           – Some scope for
                      – Easier to test                 refactoring
                      – Ease of creating a build
© ASERT 2008-2010




                        DSL
                      – More concise
                      – Better interaction with    • Gradle
                        Java                         – Take the best of both
                      – No impedence                   worlds and combine
                        mismatch with                  them
                        developers


                                                                        ESDC 2010 - 9
A Preview Example...
© ASERT 2008-2010




                                           ESDC 2010 - 10
...A Preview Example...
                              StringUtils: Vanilla Ant + Ivy
                    <project name="StringUtilsBuild" default="package"                                    <?xml version="1.0" encoding="ISO-8859-1"?>
                             xmlns:ivy="antlib:org.apache.ivy.ant" xmlns="antlib:org.apache.tools.ant">
                        <target name="clean">
                                                                                                          <ivy-module version="1.0">
                            <delete dir="target"/>                                                          <info organisation="org" module="groovycookbook" />
                            <delete dir="lib"/>                                                             <dependencies>
                        </target>                                                                             <dependency name="junit" rev="4.7" />
                       <target name="compile" depends="-init-ivy">                                          </dependencies>
                           <mkdir dir="target/classes"/>                                                  </ivy-module>
                           <javac srcdir="src/main"
                                  destdir="target/classes"/>
                       </target>

                       <target name="compileTest" depends="compile">
                           <mkdir dir="target/test-classes"/>                                             <ivysettings>
                           <javac srcdir="src/test"                                                         <settings defaultResolver="chained"/>
                                  destdir="target/test-classes">                                            <resolvers>
                               <classpath>                                                                    <chain name="chained" returnFirst="true">
                                    <pathelement location="target/classes"/>                                    <ibiblio name="ibiblio" />
                                    <fileset dir="lib" includes="*.jar"/>
                                                                                                                <url name="ibiblio-mirror">
                               </classpath>
                           </javac>                                                                               <artifact
                       </target>                                                                          pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/
© ASERT 2008-2010




                                                                                                                     [module]/[branch]/[revision]/[branch]-[revision].[ext]" />
                       <target name="test" depends="compileTest">                                               </url>
                           <mkdir dir="target/test-reports"/>                                                 </chain>
                           <junit printsummary="yes" fork="yes" haltonfailure="yes">                        </resolvers>
                               <classpath>
                                                                                                          </ivysettings>
                                    <pathelement location="target/classes"/>
                                    <pathelement location="target/test-classes"/>
                                    <fileset dir="lib" includes="*.jar"/>
                               </classpath>
                               <formatter type="plain"/>
                               <formatter type="xml"/>
                               <batchtest fork="yes" todir="target/test-reports">
                                    <fileset dir="target/test-classes"/>
                               </batchtest>
                           </junit>
                       </target>

                       <target name="package" depends="test">
                           <jar destfile="target/stringutils-1.0-SNAPSHOT.jar"
                                 basedir="target/classes"/>
                       </target>

                       <target name="-init-ivy" depends="-download-ivy">
                           <taskdef resource="org/apache/ivy/ant/antlib.xml"
                                    uri="antlib:org.apache.ivy.ant" classpath="lib/ivy.jar"/>
                           <ivy:settings file="ivysettings.xml"/>
                           <ivy:retrieve/>
                       </target>

                        <target name="-download-ivy">
                            <property name="ivy.version" value="2.1.0-rc2"/>
                            <mkdir dir="lib"/>
                            <get
                    src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.version}/ivy-
                    ${ivy.version}.jar"
                                  dest="lib/ivy.jar" usetimestamp="true"/>
                        </target>
                    </project>


                                                                                                                                                                              ESDC 2010 - 11
...A Preview Example...
                               StringUtils: Groovy's AntBuilder
                                                                                                        ...
                    import static groovy.xml.NamespaceBuilder.newInstance as namespace
                                                                                                        def test() {
                    ant = new AntBuilder()                                                                  compileTest()
                    clean()                                                                                 ant.mkdir dir: 'target/test-reports'
                    doPackage()                                                                             ant.junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') {
                                                                                                                classpath {
                    def doPackage() {                                                                               pathelement location: 'target/classes'
                        test()                                                                                      pathelement location: 'target/test-classes'
                        ant.jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar',                                    fileset dir: 'lib', includes: '*.jar'
                            basedir: 'target/classes'                                                           }
                    }                                                                                           formatter type: 'plain'
                                                                                                                formatter type: 'xml'
                    private dependencies() {                                                                    batchtest(todir: 'target/test-reports', fork: 'yes') {
                        def ivy_version = '2.1.0-rc2'                                                               fileset dir: 'target/test-classes'
                        def repo = 'http://repo2.maven.org/maven2'                                              }
                        ant.mkdir dir: 'lib'                                                                }
                        ant.get dest: 'lib/ivy.jar',                                                    }
                                usetimestamp: 'true',
                                src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar"
                        ant.taskdef classpath: 'lib/ivy.jar',
© ASERT 2008-2010




                                uri: 'antlib:org.apache.ivy.ant',
                                resource: 'org/apache/ivy/ant/antlib.xml'
                        def ivy = namespace(ant, 'antlib:org.apache.ivy.ant')
                        ivy.settings file: 'ivysettings.xml'
                        ivy.retrieve()                                                                  <?xml version="1.0" encoding="ISO-8859-1"?>
                    }                                                                                   <ivy-module version="1.0">
                                                                                                          <info organisation="org" module="groovycookbook" />
                    def clean() {                                                                         <dependencies>
                        ant.delete dir: 'target'
                        ant.delete dir: 'lib'
                                                                                                            <dependency name="junit" rev="4.7" />
                    }                                                                                     </dependencies>
                                                                                                        </ivy-module>
                    def compile() {
                        dependencies()
                        ant.mkdir dir: 'target/classes'
                        ant.javac destdir: 'target/classes', srcdir: 'src/main',                      <ivysettings>
                            includeantruntime: false                                                    <settings defaultResolver="chained"/>
                    }                                                                                   <resolvers>
                                                                                                          <chain name="chained" returnFirst="true">
                    def compileTest() {                                                                     <ibiblio name="ibiblio" />
                        compile()                                                                           <url name="ibiblio-mirror">
                        ant.mkdir dir: 'target/test-classes'                                                  <artifact
                        ant.javac(destdir: 'target/test-classes', srcdir: 'src/test',                 pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/
                            includeantruntime: false) {                                                          [module]/[branch]/[revision]/[branch]-[revision].[ext]" />
                            classpath {                                                                     </url>
                                pathelement location: 'target/classes'                                    </chain>
                                fileset dir: 'lib', includes: '*.jar'                                   </resolvers>
                            }                                                                         </ivysettings>
                        }
                    }
                    ...




                                                                                                                                                                    ESDC 2010 - 12
...A Preview Example...
                               StringUtils: Gant
                                                                                                     ...
                    import static groovy.xml.NamespaceBuilder.newInstance as namespace
                                                                                                     target(test: '') {
                    target('package': '') {                                                              depends 'compileTest'
                        depends 'test'                                                                   mkdir dir: 'target/test-reports'
                        jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar',                             junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') {
                            basedir: 'target/classes'                                                        classpath {
                    }                                                                                            pathelement location: 'target/classes'
                                                                                                                 pathelement location: 'target/test-classes'
                    target('-download-ivy': '') {                                                                fileset dir: 'lib', includes: '*.jar'
                        def ivy_version = '2.1.0-rc2'                                                        }
                        def repo = 'http://repo2.maven.org/maven2'                                           formatter type: 'plain'
                        mkdir dir: 'lib'                                                                     formatter type: 'xml'
                        get dest: 'lib/ivy.jar',                                                             batchtest(todir: 'target/test-reports', fork: 'yes') {
                            usetimestamp: 'true',                                                                fileset dir: 'target/test-classes'
                            src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar"              }
                    }                                                                                    }
                                                                                                     }
                    target(clean: '') {
                        delete dir: 'target'                                                         setDefaultTarget 'package'
                        delete dir: 'lib'
© ASERT 2008-2010




                    }

                    target(compile: '') {
                        depends '-init-ivy'
                        mkdir dir: 'target/classes'                                                 <?xml version="1.0" encoding="ISO-8859-1"?>
                        javac destdir: 'target/classes', srcdir: 'src/main'                         <ivy-module version="1.0">
                    }                                                                                 <info organisation="org" module="groovycookbook" />
                                                                                                      <dependencies>
                    target('-init-ivy': '') {
                        depends '-download-ivy'
                                                                                                        <dependency name="junit" rev="4.7" />
                        taskdef classpath: 'lib/ivy.jar',                                             </dependencies>
                                uri: 'antlib:org.apache.ivy.ant',                                   </ivy-module>
                                resource: 'org/apache/ivy/ant/antlib.xml'
                        def ivy = namespace(ant, 'antlib:org.apache.ivy.ant')
                        ivy.settings file: 'ivysettings.xml'
                        ivy.retrieve()                                                            <ivysettings>
                    }                                                                               <settings defaultResolver="chained"/>
                                                                                                    <resolvers>
                    target(compileTest: '') {                                                         <chain name="chained" returnFirst="true">
                        depends 'compile'                                                               <ibiblio name="ibiblio" />
                        mkdir dir: 'target/test-classes'                                                <url name="ibiblio-mirror">
                        javac(destdir: 'target/test-classes', srcdir: 'src/test') {                       <artifact
                            classpath {                                                           pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/
                                pathelement location: 'target/classes'                                       [module]/[branch]/[revision]/[branch]-[revision].[ext]" />
                                fileset dir: 'lib', includes: '*.jar'                                   </url>
                            }                                                                         </chain>
                        }                                                                           </resolvers>
                    }                                                                             </ivysettings>
                    ...




                                                                                                                                                                ESDC 2010 - 13
...A Preview Example...
                          StringUtils: Maven
                    <project xmlns="http://maven.apache.org/POM/4.0.0"
                            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                    http://maven.apache.org/maven-v4_0_0.xsd">
                        <modelVersion>4.0.0</modelVersion>
                        <groupId>org.groovycookbook.builds</groupId>
                        <artifactId>stringutils</artifactId>
                        <packaging>jar</packaging>
                        <version>1.0-SNAPSHOT</version>
                        <name>stringutils</name>
                        <url>http://maven.apache.org</url>
                        <dependencies>
© ASERT 2008-2010




                            <dependency>
                                 <groupId>junit</groupId>
                                 <artifactId>junit</artifactId>
                                 <version>4.7</version>
                                 <scope>test</scope>
                            </dependency>
                        </dependencies>
                        <build>
                            <plugins>
                                 <!-- this is a java 1.5 project -->
                                 <plugin>
                                     <groupId>org.apache.maven.plugins</groupId>
                                     <artifactId>maven-compiler-plugin</artifactId>
                                     <configuration>
                                         <source>1.5</source>
                                         <target>1.5</target>
                                     </configuration>
                                 </plugin>
                            </plugins>
                        </build>
                    </project>
                                                                                      ESDC 2010 - 14
...A Preview Example...
                        StringUtils: Maven 3 Groovy Dialect
                    project {
                      modelVersion '4.0.0'
                      groupId 'org.groovycookbook.builds'
                      artifactId 'stringutils'
                      packaging 'jar'
                      version '1.0-SNAPSHOT'
                      name 'stringutils'
                      url 'http://maven.apache.org'
                      dependencies {
                        dependency 'junit:junit:4.7:test'
© ASERT 2008-2010




                      }
                      build {
                        plugins {
                          /* this is a java 1.5 project */
                          plugin {
                            groupId 'org.apache.maven.plugins'
                            artifactId 'maven-compiler-plugin'
                            configuration {
                              source '1.5'
                              target '1.5'
                            }
                          }
                        }
                      }
                    }                                            ESDC 2010 - 15
...A Preview Example
                    StringUtils: Gradle


                      usePlugin 'java'

                      sourceCompatibility = 1.5
                      version = '1.0-SNAPSHOT'

                      repositories {
© ASERT 2008-2010




                          mavenCentral()
                      }

                      dependencies {
                          testCompile 'junit:junit:4.7'
                      }




                                                          ESDC 2010 - 16
Topics
                    • Build Pain Points
                    • Build Tool Landscape
                    Groovy Intro
                    • Ant & friends
                    • Maven & friends
© ASERT 2008-2010




                    • Gradle
                    • Other Tools
                    • More Info



                                               ESDC 2010 - 17
What is Groovy?
                    • “Groovy is like a super version
                      of Java. It can leverage Java's
                      enterprise capabilities but also
                      has cool productivity features like closures,
                      DSL support, builders and dynamic typing.”
© ASERT 2008-2010




                    Groovy = Java –    boiler plate code
                                  +    optional dynamic typing
                                  +    closures
                                  +    domain specific languages
                                  +    builders
                                  +    metaprogramming
                                  +    GDK library
                                                                ESDC 2010 - 18
Groovy Goodies Overview
                    • Fully object oriented
                    • Closures: reusable
                      and assignable
                      pieces of code
                    • Operators can be          • GPath: efficient
                      overloaded
© ASERT 2008-2010




                                                  object navigation
                    • Multimethods              • GroovyBeans
                    • Literal declaration for   • grep and switch
                      lists (arrays), maps,
                      ranges and regular        • Templates, builder,
                      expressions                 swing, Ant, markup,
                                                  XML, SQL, XML-RPC,
                                                  Scriptom, Grails,
                                                  tests, Mocks  ESDC 2010 - 19
Growing Acceptance …
  A slow and steady start but now gaining in
  momentum, maturity and mindshare




Now free
… Growing Acceptance …
© ASERT 2008-2010




                                             ESDC 2010 - 21
… Growing Acceptance …
© ASERT 2008-2010




                      Groovy and Grails downloads:
                      70-90K per month and growing
                                                     ESDC 2010 - 22
… Growing Acceptance …
© ASERT 2008-2010




                             Source: http://www.micropoll.com/akira/mpresult/501697-116746




                                                      Source: http://www.grailspodcast.co
                                                                                        ESDC 2010 - 23
… Growing Acceptance …
© ASERT 2008-2010




                          http://www.jroller.com/scolebourne/entry/devoxx_2008_whitebo




                                                      http://www.java.net   ESDC 2010 - 24
… Growing Acceptance
© ASERT 2006-2010




                     http://pollpigeon.com/jsf-grails-wicket/r/25665/
                                                                        ESDC 2010 - 25
… Growing Acceptance …
         What alternative JVM language are you using or intending to use
© ASERT 2008-2010




                           http://www.leonardoborges.com/writings
                                                                    ESDC 2010 - 26
… Growing Acceptance …
© ASERT 2008-2010




                    http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo
                                                                                                         ESDC 2010 - 27
… Growing Acceptance
© ASERT 2008-2010




                                           ESDC 2010 - 28
The Landscape of JVM Languages

                                                                                                                 mostly
                                                                                                                dynamic
                                                                                                                  typing
© ASERT 2008-2010




                                       Dynamic features call
                                       for dynamic types                                   Java bytecode calls
                                                                                               for static types




                    The terms “Java Virtual Machine” and “JVM” mean a Virtual Machine for the Java™ platform.
                                                                                                                     ESDC 2010 - 29
Groovy Starter
                    System.out.println("Hello, World!");   // optional semicolon,
                    println 'Hello, World!'                // System.out, brackets,
                                                           // main() method, class defn

                    def name = 'Guillaume'                 // dynamic typing
                    println "$name, I'll get the car."     // GString

                    String longer = """${name}, the car
                    is in the next row."""                 // multi-line string
                                                           // with static typing
© ASERT 2008-2010




                    assert 0.5 == 1/2                      // BigDecimal equals()

                    def printSize(obj) {                   // optional duck typing
                        print obj?.size()                  // safe dereferencing
                    }

                    def pets = ['ant', 'bee', 'cat']       //   native list syntax
                    pets.each { pet ->                     //   closure support
                        assert pet < 'dog'                 //   overloading '<' on String
                    }                                      //   or: for (pet in pets)...




                                                                                            ESDC 2010 - 30
A Better Java...
                    import java.util.List;
                    import java.util.ArrayList;

                    class Erase {
                        private List removeLongerThan(List strings, int length) {   This code
                            List result = new ArrayList();
                            for (int i = 0; i < strings.size(); i++) {              is valid
                                String s = (String) strings.get(i);
                                if (s.length() <= length) {                         Java and
                                }
                                    result.add(s);                                  valid Groovy
                            }
                            return result;
© ASERT 2008-2010




                        }
                        public static void main(String[] args) {
                            List names = new ArrayList();
                            names.add("Ted"); names.add("Fred");
                            names.add("Jed"); names.add("Ned");
                            System.out.println(names);
                            Erase e = new Erase();                                   Based on an
                            List shortNames = e.removeLongerThan(names, 3);
                            System.out.println(shortNames.size());                   example by
                            for (int i = 0; i < shortNames.size(); i++) {            Jim Weirich
                                String s = (String) shortNames.get(i);
                                System.out.println(s);                               & Ted Leung
                            }
                        }
                    }



                                                                                          ESDC 2010 - 31
...A Better Java...
                    import java.util.List;
                    import java.util.ArrayList;

                    class Erase {
                        private List removeLongerThan(List strings, int length) {   Do the
                            List result = new ArrayList();
                            for (int i = 0; i < strings.size(); i++) {              semicolons
                                String s = (String) strings.get(i);
                                if (s.length() <= length) {                         add anything?
                                }
                                    result.add(s);                                  And shouldn‟t
                            }                                                       we us more
                            return result;
© ASERT 2008-2010




                        }                                                           modern list
                        public static void main(String[] args) {
                            List names = new ArrayList();                           notation?
                            names.add("Ted"); names.add("Fred");
                            names.add("Jed"); names.add("Ned");
                                                                                    Why not
                            System.out.println(names);                              import common
                            Erase e = new Erase();
                            List shortNames = e.removeLongerThan(names, 3);         libraries?
                            System.out.println(shortNames.size());
                            for (int i = 0; i < shortNames.size(); i++) {
                                String s = (String) shortNames.get(i);
                                System.out.println(s);
                            }
                        }
                    }



                                                                                          ESDC 2010 - 32
...A Better Java...
                    class Erase {
                        private List removeLongerThan(List strings, int length) {
                            List result = new ArrayList()
                            for (String s in strings) {
                                if (s.length() <= length) {
                                    result.add(s)
                                }
                            }
                            return result
                        }

                        public static void main(String[] args) {
                            List names = new ArrayList()
© ASERT 2008-2010




                            names.add("Ted"); names.add("Fred")
                            names.add("Jed"); names.add("Ned")
                            System.out.println(names)
                            Erase e = new Erase()
                            List shortNames = e.removeLongerThan(names, 3)
                            System.out.println(shortNames.size())
                            for (String s in shortNames) {
                                System.out.println(s)
                            }
                        }
                    }




                                                                                    ESDC 2010 - 33
...A Better Java...
                    class Erase {
                        private List removeLongerThan(List strings, int length) {
                            List result = new ArrayList()
                            for (String s in strings) {
                                if (s.length() <= length) {
                                    result.add(s)                                   Do we need
                                }
                            }                                                       the static types?
                        }
                            return result                                           Must we always
                                                                                    have a main
                        public static void main(String[] args) {
                            List names = new ArrayList()                            method and
© ASERT 2008-2010




                            names.add("Ted"); names.add("Fred")
                            names.add("Jed"); names.add("Ned")                      class definition?
                            System.out.println(names)
                            Erase e = new Erase()
                                                                                    How about
                            List shortNames = e.removeLongerThan(names, 3)          improved
                            System.out.println(shortNames.size())
                            for (String s in shortNames) {                          consistency?
                                System.out.println(s)
                            }
                        }
                    }




                                                                                             ESDC 2010 - 34
...A Better Java...
                    def removeLongerThan(strings, length) {
                        def result = new ArrayList()
                        for (s in strings) {
                            if (s.size() <= length) {
                                result.add(s)
                            }
                        }
                        return result
                    }
© ASERT 2008-2010




                    names = new ArrayList()
                    names.add("Ted")
                    names.add("Fred")
                    names.add("Jed")
                    names.add("Ned")
                    System.out.println(names)
                    shortNames = removeLongerThan(names, 3)
                    System.out.println(shortNames.size())
                    for (s in shortNames) {
                        System.out.println(s)
                    }




                                                              ESDC 2010 - 35
...A Better Java...
                    def removeLongerThan(strings, length) {
                        def result = new ArrayList()
                        for (s in strings) {
                            if (s.size() <= length) {
                                result.add(s)                 Shouldn‟t we
                            }
                        }                                     have special
                        return result                         notation for lists?
                    }
                                                              And special
© ASERT 2008-2010




                    names = new ArrayList()                   facilities for
                    names.add("Ted")
                    names.add("Fred")
                                                              list processing?
                    names.add("Jed")                           Is „return‟
                    names.add("Ned")                          needed at end?
                    System.out.println(names)
                    shortNames = removeLongerThan(names, 3)
                    System.out.println(shortNames.size())
                    for (s in shortNames) {
                        System.out.println(s)
                    }




                                                                            ESDC 2010 - 36
...A Better Java...
                    def removeLongerThan(strings, length) {
                        strings.findAll{ it.size() <= length }
                    }

                    names = ["Ted", "Fred", "Jed", "Ned"]
                    System.out.println(names)
                    shortNames = removeLongerThan(names, 3)
                    System.out.println(shortNames.size())
                    shortNames.each{ System.out.println(s) }
© ASERT 2008-2010




                                                                 ESDC 2010 - 37
...A Better Java...
                    def removeLongerThan(strings, length) {
                        strings.findAll{ it.size() <= length }
                    }
                                                                 Is the method
                    names = ["Ted", "Fred", "Jed", "Ned"]        now needed?
                    System.out.println(names)
                    shortNames = removeLongerThan(names, 3)      Easier ways to
                    System.out.println(shortNames.size())        use common
                    shortNames.each{ System.out.println(s) }
                                                                 methods?
© ASERT 2008-2010




                                                                 Are brackets
                                                                 required here?




                                                                         ESDC 2010 - 38
...A Better Java...
                    names = ["Ted", "Fred", "Jed", "Ned"]
                    println names
                    shortNames = names.findAll{ it.size() <= 3 }
                    println shortNames.size()
                    shortNames.each{ println it }
© ASERT 2008-2010




                                                                   ESDC 2010 - 39
...A Better Java
                    names = ["Ted", "Fred", "Jed", "Ned"]
                    println names
                    shortNames = names.findAll{ it.size() <= 3 }
                    println shortNames.size()
                    shortNames.each{ println it }
© ASERT 2008-2010




                          [Ted, Fred, Jed, Ned]
                          3
                          Ted
                          Jed
                          Ned


                                                                   ESDC 2010 - 40
Topics
                    • Build Pain Points
                    • Build Tool Landscape
                    • Groovy Intro
                    Ant & friends
                         Calling Groovy from Ant
© ASERT 2008-2010




                         Calling Ant from Groovy
                         Gant
                    •   Maven & friends
                    •   Gradle
                    •   Other Tools
                    •   More Info
                                                     ESDC 2010 - 41
What is Ant?
                    • Tool to assist automating (build) steps

                    <project name="MyProject" default="dist" basedir=".">
                      <property name="src" location="src"/>
                      <property name="build" location="build"/>
© ASERT 2008-2010




                     <target name="init">
                       <mkdir dir="${build}"/>
                     </target>

                     <target name="compile" depends="init"
                           description="compile the source">
                       <javac srcdir="${src}" destdir="${build}"/>
                     </target>

                    </project>

                                                                     ESDC 2010 - 42
Groovy from Ant
                    • Need groovy jar on your Ant classpath

                     <taskdef name="groovy"
                              classname="org.codehaus.groovy.ant.Groovy"
                              classpathref="my.classpath"/>
© ASERT 2006-2010




                     <target name="printXmlFileNamesFromJar">
                       <zipfileset id="found" src="foobar.jar"
                                 includes="**/*.xml"/>
                       <groovy>
                         project.references.found.each {
                             println it.name
                         }
                       </groovy>
                     </target>


                                                                     ESDC 2010 - 43
Groovyc from Ant
                    • Need groovy jar on your Ant classpath

                     <taskdef name="groovyc"
                              classname="org.codehaus.groovy.ant.Groovyc"
                              classpathref="my.classpath"/>

                     <groovyc srcdir="${testSourceDirectory}"
© ASERT 2006-2010




                         destdir="${testClassesDirectory}">
                       <classpath>
                         <pathelement path="${mainClassesDirectory}"/>
                         <pathelement path="${testClassesDirectory}"/>
                         <path refid="testPath"/>
                       </classpath>
                       <javac source="1.5" target="1.5" debug="on" />
                     </groovyc>




                                                                            ESDC 2010 - 44
AntBuilder...
                      def ant = new AntBuilder()

                      ant.echo("hello")                  // let's just call one task

                      // create a block of Ant using the builder pattern
                      ant.with {
                          myDir = "target/AntTest/"
                          mkdir(dir: myDir)
© ASERT 2006-2010




                          copy(todir: myDir) {
                              fileset(dir: "src/test") {
                                  include(name: "**/*.groovy")
                              }
                          }
                          echo("done")
                      }

                      // now let's do some normal Groovy again
                      file = new File("target/test/AntTest.groovy")
                      assert file.exists()
                Needs ant.jar on your Groovy classpath                             ESDC 2010 - 45
...AntBuilder
                    • Built-in
                    new AntBuilder().with {
                        echo(file:'Temp.java', '''
                        class Temp {
                          public static void main(String[] args) {
                             System.out.println("Hello");
                          }
© ASERT 2006-2010




                        }
                        ''')
                        javac(srcdir:'.', includes:'Temp.java', fork:'true')
                        java(classpath:'.', classname:'Temp', fork:'true')
                        echo('Done')
                    }
                    // =>
                    //    [javac] Compiling 1 source file
                    //      [java] Hello
                    //      [echo] Done

                                                                      ESDC 2010 - 46
Using AntLibs: Maven Ant Tasks & AntUnit
                     import static groovy.xml.NamespaceBuilder.newInstance as namespace
                     def ant = new AntBuilder()
                     def mvn = namespace(ant, 'antlib:org.apache.maven.artifact.ant')
                     def antunit = namespace(ant, 'antlib:org.apache.ant.antunit')

                     direct = [groupId:'jfree', artifactId:'jfreechart', version:'1.0.9']
                     indirect = [groupId:'jfree', artifactId:'jcommon', version:'1.0.12']

                     // download artifacts
                     mvn.dependencies(filesetId:'artifacts') { dependency(direct) }
© ASERT 2006-2010




                     // print out what we downloaded
                     ant.fileScanner { fileset(refid:'artifacts') }.each { println it }

                     // use AntUnit to confirm expected files were downloaded
                     def prefix = System.properties.'user.home' + '/.m2/repository'
                     [direct, indirect].each { item ->
                         def (g, a, v) = [item.groupId, item.artifactId, item.version]
                         antunit.assertFileExists(file:"$prefix/$g/$a/$v/$a-${v}.jar")
                     }


                    C:Userspaulk.m2repositoryjfreejcommon1.0.12jcommon-1.0.12.jar
                    C:Userspaulk.m2repositoryjfreejfreechart1.0.9jfreechart-1.0.9.jar
                                                                                                ESDC 2010 - 47
Builds: Gant
                    • lightweight façade on Groovy's AntBuilder
                    • target def’ns, pre-defined ‘ant’, operations on
                      predefined objects

                     includeTargets << gant.targets.Clean
                     cleanPattern << [ '**/*~' , '**/*.bak' ]
                     cleanDirectory << 'build'
© ASERT 2006-2010




                     target ( stuff : 'A target to do some stuff.' ) {
                       println ( 'Stuff' )
                       depends ( clean )
                       echo ( message : 'A default message from Ant.' )
                       otherStuff ( )
                     }

                     target ( otherStuff : 'A target to do some other stuff' ) {
                       println ( 'OtherStuff' )
                       echo ( message : 'Another message from Ant.' )
                       clean ( )
                     }



                                                                                   ESDC 2010 - 48
Topics
                    • Build Pain Points
                    • Build Tool Landscape
                    • Groovy Intro
                    • Ant & friends
                    Maven & friends
© ASERT 2008-2010




                       Writing plugins in Groovy
                       Building your Groovy project
                    • Gradle
                    • Other Tools
                    • More Info

                                                       ESDC 2010 - 49
What is Maven?
                    • Tool to assist automating (build) steps
© ASERT 2008-2010




                                                            ESDC 2010 - 50
Builds: GMaven...
                    • Implementing Maven plugins has
                      never been Groovier!
                    • Groovy Mojos
                      – A Simple Groovy Mojo
                    • Building Plugins
                      – Project Definition
© ASERT 2006-2010




                      – Mojo Parameters
                    • Putting More Groove into your Mojo
                      – Using ant, Using fail()
                    • gmaven-archetype-mojo Archetype
                    • gmaven-plugin Packaging



                                                           ESDC 2010 - 51
...Builds: GMaven...
                <plugin>
                    <groupId>org.codehaus.groovy.maven</groupId>
                    <artifactId>gmaven-plugin</artifactId>
                    <executions>
                         <execution>
                             <phase>generate-resources</phase>
                             <goals>
                                 <goal>execute</goal>
                             </goals>
                             <configuration>
© ASERT 2006-2010




                                 <source>
                                     if (project.packaging != 'pom') {
                                         log.info('Copying some stuff...')
                                         def dir = new File(project.basedir, 'target/classes/META-IN
                                         ant.mkdir(dir: dir)
                                         ant.copy(todir: dir) {
                                             fileset(dir: project.basedir) {
                                                 include(name: 'LICENSE.txt')
                                                 include(name: 'NOTICE.txt')
                                             }
                                         }
                                     }
                                 </source>
                             </configuration>
                         </execution>
                    </executions>
                </plugin>                                                                 ESDC 2010 - 52
...Builds: GMaven...


                     <plugin>
                        <groupId>org.codehaus.mojo.groovy</groupId>
                        <artifactId>groovy-maven-plugin</artifactId>
                        <executions>
                           <execution>
                              <id>restart-weblogic</id>
© ASERT 2006-2010




                              <phase>pre-integration-test</phase>
                              <goals>
                                 <goal>execute</goal>
                              </goals>
                              <configuration>
                                 <source>
                                 ${pom.basedir}/src/main/script/restartWeblogic.groovy
                                 </source>
                              </configuration>
                           </execution>
                    ...




                                                                                  ESDC 2010 - 53
...Builds: GMaven...


                    def domainDir =
                       project.properties['weblogic.domain.easyimage.dir']

                    stopWebLogic()
                    copyFiles(domainDir)
                    startWebLogic(domainDir)
© ASERT 2006-2010




                    waitForWebLogicStartup()

                    def stopWebLogic() {
                       weblogicServerDir = project.properties['weblogic.server.dir']
                       adminUrl = project.properties['easyimage.weblogic.admin.t3']
                       userName = 'weblogic'
                       password = 'weblogic'
                       ant.exec(executable: 'cmd', failonerror: 'false') {
                          arg(line: "/C ${wlsDir}/bin/setWLSEnv.cmd && java ..." ...
                    }

                    ...



                                                                                       ESDC 2010 - 54
...Builds: GMaven
© ASERT 2006-2010




                                        ESDC 2010 - 55
Topics
                    • Build Pain Points
                    • Build Tool Landscape
                    • Groovy Intro
                    • Ant & friends
                    • Maven & friends
© ASERT 2008-2010




                    Gradle
                    • Other Tools
                    • More Info



                                               ESDC 2010 - 56
What is Gradle?
                    • Tool to assist automating (build) steps

                          task hello << {
                              println 'Hello world!'
                          }

                          task intro(dependsOn: hello) << {
© ASERT 2008-2010




                              println "I'm Gradle"
                          }


                         > gradle -q intro
                         Hello world!
                         I'm Gradle



                                                              ESDC 2010 - 57
Gradle Features
                    • A very flexible general purpose build tool like Ant
                    • Switchable, build-by-convention frameworks a la Maven. But
                      we never lock you in!
                    • Very powerful support for multi-project builds
                    • Very powerful dependency management (based on Apache
                      Ivy)
                    • Full support for your existing Maven or Ivy repository
© ASERT 2006-2010




                      infrastructure
                    • Support for transitive dependency management without the
                      need for remote repositories or pom.xml and ivy.xml files
                    • Ant tasks as first class citizens
                    • Groovy build scripts
                    • A rich domain model for describing your build




                                                                           ESDC 2010 - 58
Gradle Examples
© ASERT 2006-2010




                                      ESDC 2010 - 59
Revisiting our Preview Example

                                               Switching
                                               to IDE
© ASERT 2008-2010




                                                     ESDC 2010 - 60
Topics
                    • Build Pain Points
                    • Build Tool Landscape
                    • Groovy Intro
                    • Ant & friends
                    • Maven & friends
© ASERT 2008-2010




                    • Gradle
                    Other Tools
                    • More Info



                                               ESDC 2010 - 61
Hudson
                     • Gant Plugin — This plugin allows Hudson to invoke
                       Gant build script as the main build step
                     • Gradle Plugin — This plugin allows Hudson to invoke
                       Gradle build script as the main build step
                     • Grails Plugin — This plugin allows Hudson to invoke
                       Grails tasks as build steps
© ASERT 2006-2010




                     • Hudson CLI and GroovyShell




                    Source: http://weblogs.java.net/blog/kohsuke/archive/2009/05/hudson_cli_and.html   ESDC 2010 - 62
Hudson: Groovy Postbuild Plugin...
                    if (manager.logContains(".*uses or overrides a deprecated API.*")) {
                        manager.addWarningBadge("Thou shalt not use deprecated methods.")
                        manager.createSummary("warning.gif").appendText(
                            "<h1>You have been warned!</h1>", false, false, false, "red")
                        manager.buildUnstable()
                    }
© ASERT 2006-2010




                Source: http://wiki.hudson-ci.org/display/HUDSON/Groovy+Postbuild+Plugin
...Hudson: Groovy Postbuild Plugin
                    regex = 'src/main/java/(.*).java:[^ ]* (.*) is Sun proprietary API and may
                    be removed in a future release'
                    map = [:]
                    manager.build.logFile.eachMatch(regex) { full, ownClass, sunClass ->
                        map[ownClass.replaceAll("/", ".")] = sunClass
                    }
                    if (map) {
                        manager.createSummary("warning.gif").with {
                            appendText("Classes using Sun proprietary API:<ul>", false)
                            map.each { k, v ->
                                appendText("<li><b>$k</b> - uses $v</li>", false)
© ASERT 2006-2010




                            }
                            appendText("</ul>", false)
                        }
                    }




                Adapted from: http://wiki.hudson-ci.org/display/HUDSON/Groovy+Postbuild+Plugin
Topics
                    • Build Pain Points
                    • Build Tool Landscape
                    • Groovy Intro
                    • Ant & friends
                    • Maven & friends
© ASERT 2008-2010




                    • Gradle
                    • Other Tools
                    More Info



                                               ESDC 2010 - 65
More Information...
                    • Ant
                      – http://ant.apache.org
                      – http://groovy.codehaus.org/The+groovy+Ant+Task
                      – http://groovy.codehaus.org/Using+Ant+from+Groovy
                      – http://groovy.codehaus.org/Using+Ant+Libraries+with
                        +AntBuilder
© ASERT 2008-2010




                      – http://gant.codehaus.org/
                    • Maven
                      – http://maven.apache.org
                      – http://gmaven.codehaus.org
                    • Gradle
                      – http://gradle.org

                                                                     ESDC 2010 - 66
...More Information...
                    • Groovy Web sites
                      –   http://groovy.codehaus.org
                      –   http://grails.codehaus.org
                      –   http://pleac.sourceforge.net/pleac_groovy (many examples)
                      –   http://www.asert.com.au/training/java/GV110.htm (workshop)

                    • Groovy User Mailing list
                      – user@groovy.codehaus.org
© ASERT 2006-2010




                    • Groovy Information portals
                      – http://www.aboutgroovy.org
                      – http://www.groovyblogs.org

                    • Groovy Documentation (1000+ pages)
                      – Getting Started Guide, User Guide, Developer Guide, Testing Guide,
                        Cookbook Examples, Advanced Usage Guide



                                                                                       ESDC 2010 - 67
GinA 2ed “ReGinA” is coming ...
© ASERT 2006-2010

Make Your Builds More Groovy

  • 1.
    © ASERT 2008-2010 Make Your Builds More Groovy Dr Paul King paulk@asert.com.au @paulk_asert ASERT, Australia ESDC 2010 - 1
  • 2.
    Topics Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle • Other Tools • More Info ESDC 2010 - 2
  • 3.
    Build Pain Points... • Has anyone seen? – Large monolithic balls of mud – Complex usage, assumptions, conventions – Impossible to bend in desired ways – Never been (can't be) refactored/tested – © ASERT 2008-2010 Many manual steps – Environment fragile • different machines, CI vs IDE, dev vs prod vs test ESDC 2010 - 3
  • 4.
    ...Build Pain Points... • Require powerful features – Dependency management – Version management – Polyglot compilation – Artifact production and manipulation (jar, war, ...) – Templating (generation of boilerplate text files) © ASERT 2008-2010 – Multifacted testing – Reporting – Quality control (Metrics, code quality, static analysis) – Property management – Infinitely(?) extensible ESDC 2010 - 4
  • 5.
    ...Build Pain Points • Useful characteristics – Tool friendly – Cross platform – IDE support, CI support – Refactorable – Testable © ASERT 2008-2010 – Minimal noise (DSL like) – Easy to extend – Conventions – Good documentation – Polyglot friendly ESDC 2010 - 5
  • 6.
    Topics • Build Pain Points Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle • Other Tools • More Info ESDC 2010 - 6
  • 7.
    Build Tools • Non-exhaustive list – Ant, Maven, EasyAnt – Gant, GMaven, Gradle, Graven (uptake?), Groovy Frontend for Ant (emerge from sandbox?) – Rake, Raven, Buildr – Make, SCons, Waf © ASERT 2008-2010 – MSBuild, Nant • Used by – Developers: NetBeans, Eclipse, Intellij, Command-line – CI: Hudson (Groovy support and console), Team City, CruiseControl, AnthillPro (Groovy support), Bamboo – Deployment Management: Tableaux (Groovy support) – Ad-hoc: batch processing, production applications ESDC 2010 - 7
  • 8.
    Pros/Cons of TraditionalTools • Ant • Maven – Flexible (supports any – Opinionated about convention) conventions – Easy to extend • Mostly a good thing – Wealth of useful tasks – Mostly declarative – Well documented • XML != concise DSL – Numerous plugins © ASERT 2008-2010 – Partially declarative but some scope for – Some easy extension procedural instructions points but some more • XML != prog. language difficult options – Lifecycle is hand-crafted • Some things beyond some teams in your build file – Structured lifecycle – Can use Ivy or Maven Ant tasks for dependency management ESDC 2010 - 8
  • 9.
    Enhancing Traditional Tools • Ant + Groovy • Maven + Groovy – Easy to write the – Easier to extend procedural pieces – More concise syntax – Easier to refactor – Some scope for – Easier to test refactoring – Ease of creating a build © ASERT 2008-2010 DSL – More concise – Better interaction with • Gradle Java – Take the best of both – No impedence worlds and combine mismatch with them developers ESDC 2010 - 9
  • 10.
    A Preview Example... ©ASERT 2008-2010 ESDC 2010 - 10
  • 11.
    ...A Preview Example... StringUtils: Vanilla Ant + Ivy <project name="StringUtilsBuild" default="package" <?xml version="1.0" encoding="ISO-8859-1"?> xmlns:ivy="antlib:org.apache.ivy.ant" xmlns="antlib:org.apache.tools.ant"> <target name="clean"> <ivy-module version="1.0"> <delete dir="target"/> <info organisation="org" module="groovycookbook" /> <delete dir="lib"/> <dependencies> </target> <dependency name="junit" rev="4.7" /> <target name="compile" depends="-init-ivy"> </dependencies> <mkdir dir="target/classes"/> </ivy-module> <javac srcdir="src/main" destdir="target/classes"/> </target> <target name="compileTest" depends="compile"> <mkdir dir="target/test-classes"/> <ivysettings> <javac srcdir="src/test" <settings defaultResolver="chained"/> destdir="target/test-classes"> <resolvers> <classpath> <chain name="chained" returnFirst="true"> <pathelement location="target/classes"/> <ibiblio name="ibiblio" /> <fileset dir="lib" includes="*.jar"/> <url name="ibiblio-mirror"> </classpath> </javac> <artifact </target> pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/ © ASERT 2008-2010 [module]/[branch]/[revision]/[branch]-[revision].[ext]" /> <target name="test" depends="compileTest"> </url> <mkdir dir="target/test-reports"/> </chain> <junit printsummary="yes" fork="yes" haltonfailure="yes"> </resolvers> <classpath> </ivysettings> <pathelement location="target/classes"/> <pathelement location="target/test-classes"/> <fileset dir="lib" includes="*.jar"/> </classpath> <formatter type="plain"/> <formatter type="xml"/> <batchtest fork="yes" todir="target/test-reports"> <fileset dir="target/test-classes"/> </batchtest> </junit> </target> <target name="package" depends="test"> <jar destfile="target/stringutils-1.0-SNAPSHOT.jar" basedir="target/classes"/> </target> <target name="-init-ivy" depends="-download-ivy"> <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpath="lib/ivy.jar"/> <ivy:settings file="ivysettings.xml"/> <ivy:retrieve/> </target> <target name="-download-ivy"> <property name="ivy.version" value="2.1.0-rc2"/> <mkdir dir="lib"/> <get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.version}/ivy- ${ivy.version}.jar" dest="lib/ivy.jar" usetimestamp="true"/> </target> </project> ESDC 2010 - 11
  • 12.
    ...A Preview Example... StringUtils: Groovy's AntBuilder ... import static groovy.xml.NamespaceBuilder.newInstance as namespace def test() { ant = new AntBuilder() compileTest() clean() ant.mkdir dir: 'target/test-reports' doPackage() ant.junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') { classpath { def doPackage() { pathelement location: 'target/classes' test() pathelement location: 'target/test-classes' ant.jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar', fileset dir: 'lib', includes: '*.jar' basedir: 'target/classes' } } formatter type: 'plain' formatter type: 'xml' private dependencies() { batchtest(todir: 'target/test-reports', fork: 'yes') { def ivy_version = '2.1.0-rc2' fileset dir: 'target/test-classes' def repo = 'http://repo2.maven.org/maven2' } ant.mkdir dir: 'lib' } ant.get dest: 'lib/ivy.jar', } usetimestamp: 'true', src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar" ant.taskdef classpath: 'lib/ivy.jar', © ASERT 2008-2010 uri: 'antlib:org.apache.ivy.ant', resource: 'org/apache/ivy/ant/antlib.xml' def ivy = namespace(ant, 'antlib:org.apache.ivy.ant') ivy.settings file: 'ivysettings.xml' ivy.retrieve() <?xml version="1.0" encoding="ISO-8859-1"?> } <ivy-module version="1.0"> <info organisation="org" module="groovycookbook" /> def clean() { <dependencies> ant.delete dir: 'target' ant.delete dir: 'lib' <dependency name="junit" rev="4.7" /> } </dependencies> </ivy-module> def compile() { dependencies() ant.mkdir dir: 'target/classes' ant.javac destdir: 'target/classes', srcdir: 'src/main', <ivysettings> includeantruntime: false <settings defaultResolver="chained"/> } <resolvers> <chain name="chained" returnFirst="true"> def compileTest() { <ibiblio name="ibiblio" /> compile() <url name="ibiblio-mirror"> ant.mkdir dir: 'target/test-classes' <artifact ant.javac(destdir: 'target/test-classes', srcdir: 'src/test', pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/ includeantruntime: false) { [module]/[branch]/[revision]/[branch]-[revision].[ext]" /> classpath { </url> pathelement location: 'target/classes' </chain> fileset dir: 'lib', includes: '*.jar' </resolvers> } </ivysettings> } } ... ESDC 2010 - 12
  • 13.
    ...A Preview Example... StringUtils: Gant ... import static groovy.xml.NamespaceBuilder.newInstance as namespace target(test: '') { target('package': '') { depends 'compileTest' depends 'test' mkdir dir: 'target/test-reports' jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar', junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') { basedir: 'target/classes' classpath { } pathelement location: 'target/classes' pathelement location: 'target/test-classes' target('-download-ivy': '') { fileset dir: 'lib', includes: '*.jar' def ivy_version = '2.1.0-rc2' } def repo = 'http://repo2.maven.org/maven2' formatter type: 'plain' mkdir dir: 'lib' formatter type: 'xml' get dest: 'lib/ivy.jar', batchtest(todir: 'target/test-reports', fork: 'yes') { usetimestamp: 'true', fileset dir: 'target/test-classes' src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar" } } } } target(clean: '') { delete dir: 'target' setDefaultTarget 'package' delete dir: 'lib' © ASERT 2008-2010 } target(compile: '') { depends '-init-ivy' mkdir dir: 'target/classes' <?xml version="1.0" encoding="ISO-8859-1"?> javac destdir: 'target/classes', srcdir: 'src/main' <ivy-module version="1.0"> } <info organisation="org" module="groovycookbook" /> <dependencies> target('-init-ivy': '') { depends '-download-ivy' <dependency name="junit" rev="4.7" /> taskdef classpath: 'lib/ivy.jar', </dependencies> uri: 'antlib:org.apache.ivy.ant', </ivy-module> resource: 'org/apache/ivy/ant/antlib.xml' def ivy = namespace(ant, 'antlib:org.apache.ivy.ant') ivy.settings file: 'ivysettings.xml' ivy.retrieve() <ivysettings> } <settings defaultResolver="chained"/> <resolvers> target(compileTest: '') { <chain name="chained" returnFirst="true"> depends 'compile' <ibiblio name="ibiblio" /> mkdir dir: 'target/test-classes' <url name="ibiblio-mirror"> javac(destdir: 'target/test-classes', srcdir: 'src/test') { <artifact classpath { pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/ pathelement location: 'target/classes' [module]/[branch]/[revision]/[branch]-[revision].[ext]" /> fileset dir: 'lib', includes: '*.jar' </url> } </chain> } </resolvers> } </ivysettings> ... ESDC 2010 - 13
  • 14.
    ...A Preview Example... StringUtils: Maven <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.groovycookbook.builds</groupId> <artifactId>stringutils</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>stringutils</name> <url>http://maven.apache.org</url> <dependencies> © ASERT 2008-2010 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- this is a java 1.5 project --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project> ESDC 2010 - 14
  • 15.
    ...A Preview Example... StringUtils: Maven 3 Groovy Dialect project { modelVersion '4.0.0' groupId 'org.groovycookbook.builds' artifactId 'stringutils' packaging 'jar' version '1.0-SNAPSHOT' name 'stringutils' url 'http://maven.apache.org' dependencies { dependency 'junit:junit:4.7:test' © ASERT 2008-2010 } build { plugins { /* this is a java 1.5 project */ plugin { groupId 'org.apache.maven.plugins' artifactId 'maven-compiler-plugin' configuration { source '1.5' target '1.5' } } } } } ESDC 2010 - 15
  • 16.
    ...A Preview Example StringUtils: Gradle usePlugin 'java' sourceCompatibility = 1.5 version = '1.0-SNAPSHOT' repositories { © ASERT 2008-2010 mavenCentral() } dependencies { testCompile 'junit:junit:4.7' } ESDC 2010 - 16
  • 17.
    Topics • Build Pain Points • Build Tool Landscape Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle • Other Tools • More Info ESDC 2010 - 17
  • 18.
    What is Groovy? • “Groovy is like a super version of Java. It can leverage Java's enterprise capabilities but also has cool productivity features like closures, DSL support, builders and dynamic typing.” © ASERT 2008-2010 Groovy = Java – boiler plate code + optional dynamic typing + closures + domain specific languages + builders + metaprogramming + GDK library ESDC 2010 - 18
  • 19.
    Groovy Goodies Overview • Fully object oriented • Closures: reusable and assignable pieces of code • Operators can be • GPath: efficient overloaded © ASERT 2008-2010 object navigation • Multimethods • GroovyBeans • Literal declaration for • grep and switch lists (arrays), maps, ranges and regular • Templates, builder, expressions swing, Ant, markup, XML, SQL, XML-RPC, Scriptom, Grails, tests, Mocks ESDC 2010 - 19
  • 20.
    Growing Acceptance … A slow and steady start but now gaining in momentum, maturity and mindshare Now free
  • 21.
    … Growing Acceptance… © ASERT 2008-2010 ESDC 2010 - 21
  • 22.
    … Growing Acceptance… © ASERT 2008-2010 Groovy and Grails downloads: 70-90K per month and growing ESDC 2010 - 22
  • 23.
    … Growing Acceptance… © ASERT 2008-2010 Source: http://www.micropoll.com/akira/mpresult/501697-116746 Source: http://www.grailspodcast.co ESDC 2010 - 23
  • 24.
    … Growing Acceptance… © ASERT 2008-2010 http://www.jroller.com/scolebourne/entry/devoxx_2008_whitebo http://www.java.net ESDC 2010 - 24
  • 25.
    … Growing Acceptance ©ASERT 2006-2010 http://pollpigeon.com/jsf-grails-wicket/r/25665/ ESDC 2010 - 25
  • 26.
    … Growing Acceptance… What alternative JVM language are you using or intending to use © ASERT 2008-2010 http://www.leonardoborges.com/writings ESDC 2010 - 26
  • 27.
    … Growing Acceptance… © ASERT 2008-2010 http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo ESDC 2010 - 27
  • 28.
    … Growing Acceptance ©ASERT 2008-2010 ESDC 2010 - 28
  • 29.
    The Landscape ofJVM Languages mostly dynamic typing © ASERT 2008-2010 Dynamic features call for dynamic types Java bytecode calls for static types The terms “Java Virtual Machine” and “JVM” mean a Virtual Machine for the Java™ platform. ESDC 2010 - 29
  • 30.
    Groovy Starter System.out.println("Hello, World!"); // optional semicolon, println 'Hello, World!' // System.out, brackets, // main() method, class defn def name = 'Guillaume' // dynamic typing println "$name, I'll get the car." // GString String longer = """${name}, the car is in the next row.""" // multi-line string // with static typing © ASERT 2008-2010 assert 0.5 == 1/2 // BigDecimal equals() def printSize(obj) { // optional duck typing print obj?.size() // safe dereferencing } def pets = ['ant', 'bee', 'cat'] // native list syntax pets.each { pet -> // closure support assert pet < 'dog' // overloading '<' on String } // or: for (pet in pets)... ESDC 2010 - 30
  • 31.
    A Better Java... import java.util.List; import java.util.ArrayList; class Erase { private List removeLongerThan(List strings, int length) { This code List result = new ArrayList(); for (int i = 0; i < strings.size(); i++) { is valid String s = (String) strings.get(i); if (s.length() <= length) { Java and } result.add(s); valid Groovy } return result; © ASERT 2008-2010 } public static void main(String[] args) { List names = new ArrayList(); names.add("Ted"); names.add("Fred"); names.add("Jed"); names.add("Ned"); System.out.println(names); Erase e = new Erase(); Based on an List shortNames = e.removeLongerThan(names, 3); System.out.println(shortNames.size()); example by for (int i = 0; i < shortNames.size(); i++) { Jim Weirich String s = (String) shortNames.get(i); System.out.println(s); & Ted Leung } } } ESDC 2010 - 31
  • 32.
    ...A Better Java... import java.util.List; import java.util.ArrayList; class Erase { private List removeLongerThan(List strings, int length) { Do the List result = new ArrayList(); for (int i = 0; i < strings.size(); i++) { semicolons String s = (String) strings.get(i); if (s.length() <= length) { add anything? } result.add(s); And shouldn‟t } we us more return result; © ASERT 2008-2010 } modern list public static void main(String[] args) { List names = new ArrayList(); notation? names.add("Ted"); names.add("Fred"); names.add("Jed"); names.add("Ned"); Why not System.out.println(names); import common Erase e = new Erase(); List shortNames = e.removeLongerThan(names, 3); libraries? System.out.println(shortNames.size()); for (int i = 0; i < shortNames.size(); i++) { String s = (String) shortNames.get(i); System.out.println(s); } } } ESDC 2010 - 32
  • 33.
    ...A Better Java... class Erase { private List removeLongerThan(List strings, int length) { List result = new ArrayList() for (String s in strings) { if (s.length() <= length) { result.add(s) } } return result } public static void main(String[] args) { List names = new ArrayList() © ASERT 2008-2010 names.add("Ted"); names.add("Fred") names.add("Jed"); names.add("Ned") System.out.println(names) Erase e = new Erase() List shortNames = e.removeLongerThan(names, 3) System.out.println(shortNames.size()) for (String s in shortNames) { System.out.println(s) } } } ESDC 2010 - 33
  • 34.
    ...A Better Java... class Erase { private List removeLongerThan(List strings, int length) { List result = new ArrayList() for (String s in strings) { if (s.length() <= length) { result.add(s) Do we need } } the static types? } return result Must we always have a main public static void main(String[] args) { List names = new ArrayList() method and © ASERT 2008-2010 names.add("Ted"); names.add("Fred") names.add("Jed"); names.add("Ned") class definition? System.out.println(names) Erase e = new Erase() How about List shortNames = e.removeLongerThan(names, 3) improved System.out.println(shortNames.size()) for (String s in shortNames) { consistency? System.out.println(s) } } } ESDC 2010 - 34
  • 35.
    ...A Better Java... def removeLongerThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() <= length) { result.add(s) } } return result } © ASERT 2008-2010 names = new ArrayList() names.add("Ted") names.add("Fred") names.add("Jed") names.add("Ned") System.out.println(names) shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) for (s in shortNames) { System.out.println(s) } ESDC 2010 - 35
  • 36.
    ...A Better Java... def removeLongerThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() <= length) { result.add(s) Shouldn‟t we } } have special return result notation for lists? } And special © ASERT 2008-2010 names = new ArrayList() facilities for names.add("Ted") names.add("Fred") list processing? names.add("Jed") Is „return‟ names.add("Ned") needed at end? System.out.println(names) shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) for (s in shortNames) { System.out.println(s) } ESDC 2010 - 36
  • 37.
    ...A Better Java... def removeLongerThan(strings, length) { strings.findAll{ it.size() <= length } } names = ["Ted", "Fred", "Jed", "Ned"] System.out.println(names) shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) shortNames.each{ System.out.println(s) } © ASERT 2008-2010 ESDC 2010 - 37
  • 38.
    ...A Better Java... def removeLongerThan(strings, length) { strings.findAll{ it.size() <= length } } Is the method names = ["Ted", "Fred", "Jed", "Ned"] now needed? System.out.println(names) shortNames = removeLongerThan(names, 3) Easier ways to System.out.println(shortNames.size()) use common shortNames.each{ System.out.println(s) } methods? © ASERT 2008-2010 Are brackets required here? ESDC 2010 - 38
  • 39.
    ...A Better Java... names = ["Ted", "Fred", "Jed", "Ned"] println names shortNames = names.findAll{ it.size() <= 3 } println shortNames.size() shortNames.each{ println it } © ASERT 2008-2010 ESDC 2010 - 39
  • 40.
    ...A Better Java names = ["Ted", "Fred", "Jed", "Ned"] println names shortNames = names.findAll{ it.size() <= 3 } println shortNames.size() shortNames.each{ println it } © ASERT 2008-2010 [Ted, Fred, Jed, Ned] 3 Ted Jed Ned ESDC 2010 - 40
  • 41.
    Topics • Build Pain Points • Build Tool Landscape • Groovy Intro Ant & friends  Calling Groovy from Ant © ASERT 2008-2010  Calling Ant from Groovy  Gant • Maven & friends • Gradle • Other Tools • More Info ESDC 2010 - 41
  • 42.
    What is Ant? • Tool to assist automating (build) steps <project name="MyProject" default="dist" basedir="."> <property name="src" location="src"/> <property name="build" location="build"/> © ASERT 2008-2010 <target name="init"> <mkdir dir="${build}"/> </target> <target name="compile" depends="init" description="compile the source"> <javac srcdir="${src}" destdir="${build}"/> </target> </project> ESDC 2010 - 42
  • 43.
    Groovy from Ant • Need groovy jar on your Ant classpath <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="my.classpath"/> © ASERT 2006-2010 <target name="printXmlFileNamesFromJar"> <zipfileset id="found" src="foobar.jar" includes="**/*.xml"/> <groovy> project.references.found.each { println it.name } </groovy> </target> ESDC 2010 - 43
  • 44.
    Groovyc from Ant • Need groovy jar on your Ant classpath <taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" classpathref="my.classpath"/> <groovyc srcdir="${testSourceDirectory}" © ASERT 2006-2010 destdir="${testClassesDirectory}"> <classpath> <pathelement path="${mainClassesDirectory}"/> <pathelement path="${testClassesDirectory}"/> <path refid="testPath"/> </classpath> <javac source="1.5" target="1.5" debug="on" /> </groovyc> ESDC 2010 - 44
  • 45.
    AntBuilder... def ant = new AntBuilder() ant.echo("hello") // let's just call one task // create a block of Ant using the builder pattern ant.with { myDir = "target/AntTest/" mkdir(dir: myDir) © ASERT 2006-2010 copy(todir: myDir) { fileset(dir: "src/test") { include(name: "**/*.groovy") } } echo("done") } // now let's do some normal Groovy again file = new File("target/test/AntTest.groovy") assert file.exists() Needs ant.jar on your Groovy classpath ESDC 2010 - 45
  • 46.
    ...AntBuilder • Built-in new AntBuilder().with { echo(file:'Temp.java', ''' class Temp { public static void main(String[] args) { System.out.println("Hello"); } © ASERT 2006-2010 } ''') javac(srcdir:'.', includes:'Temp.java', fork:'true') java(classpath:'.', classname:'Temp', fork:'true') echo('Done') } // => // [javac] Compiling 1 source file // [java] Hello // [echo] Done ESDC 2010 - 46
  • 47.
    Using AntLibs: MavenAnt Tasks & AntUnit import static groovy.xml.NamespaceBuilder.newInstance as namespace def ant = new AntBuilder() def mvn = namespace(ant, 'antlib:org.apache.maven.artifact.ant') def antunit = namespace(ant, 'antlib:org.apache.ant.antunit') direct = [groupId:'jfree', artifactId:'jfreechart', version:'1.0.9'] indirect = [groupId:'jfree', artifactId:'jcommon', version:'1.0.12'] // download artifacts mvn.dependencies(filesetId:'artifacts') { dependency(direct) } © ASERT 2006-2010 // print out what we downloaded ant.fileScanner { fileset(refid:'artifacts') }.each { println it } // use AntUnit to confirm expected files were downloaded def prefix = System.properties.'user.home' + '/.m2/repository' [direct, indirect].each { item -> def (g, a, v) = [item.groupId, item.artifactId, item.version] antunit.assertFileExists(file:"$prefix/$g/$a/$v/$a-${v}.jar") } C:Userspaulk.m2repositoryjfreejcommon1.0.12jcommon-1.0.12.jar C:Userspaulk.m2repositoryjfreejfreechart1.0.9jfreechart-1.0.9.jar ESDC 2010 - 47
  • 48.
    Builds: Gant • lightweight façade on Groovy's AntBuilder • target def’ns, pre-defined ‘ant’, operations on predefined objects includeTargets << gant.targets.Clean cleanPattern << [ '**/*~' , '**/*.bak' ] cleanDirectory << 'build' © ASERT 2006-2010 target ( stuff : 'A target to do some stuff.' ) { println ( 'Stuff' ) depends ( clean ) echo ( message : 'A default message from Ant.' ) otherStuff ( ) } target ( otherStuff : 'A target to do some other stuff' ) { println ( 'OtherStuff' ) echo ( message : 'Another message from Ant.' ) clean ( ) } ESDC 2010 - 48
  • 49.
    Topics • Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends Maven & friends © ASERT 2008-2010  Writing plugins in Groovy  Building your Groovy project • Gradle • Other Tools • More Info ESDC 2010 - 49
  • 50.
    What is Maven? • Tool to assist automating (build) steps © ASERT 2008-2010 ESDC 2010 - 50
  • 51.
    Builds: GMaven... • Implementing Maven plugins has never been Groovier! • Groovy Mojos – A Simple Groovy Mojo • Building Plugins – Project Definition © ASERT 2006-2010 – Mojo Parameters • Putting More Groove into your Mojo – Using ant, Using fail() • gmaven-archetype-mojo Archetype • gmaven-plugin Packaging ESDC 2010 - 51
  • 52.
    ...Builds: GMaven... <plugin> <groupId>org.codehaus.groovy.maven</groupId> <artifactId>gmaven-plugin</artifactId> <executions> <execution> <phase>generate-resources</phase> <goals> <goal>execute</goal> </goals> <configuration> © ASERT 2006-2010 <source> if (project.packaging != 'pom') { log.info('Copying some stuff...') def dir = new File(project.basedir, 'target/classes/META-IN ant.mkdir(dir: dir) ant.copy(todir: dir) { fileset(dir: project.basedir) { include(name: 'LICENSE.txt') include(name: 'NOTICE.txt') } } } </source> </configuration> </execution> </executions> </plugin> ESDC 2010 - 52
  • 53.
    ...Builds: GMaven... <plugin> <groupId>org.codehaus.mojo.groovy</groupId> <artifactId>groovy-maven-plugin</artifactId> <executions> <execution> <id>restart-weblogic</id> © ASERT 2006-2010 <phase>pre-integration-test</phase> <goals> <goal>execute</goal> </goals> <configuration> <source> ${pom.basedir}/src/main/script/restartWeblogic.groovy </source> </configuration> </execution> ... ESDC 2010 - 53
  • 54.
    ...Builds: GMaven... def domainDir = project.properties['weblogic.domain.easyimage.dir'] stopWebLogic() copyFiles(domainDir) startWebLogic(domainDir) © ASERT 2006-2010 waitForWebLogicStartup() def stopWebLogic() { weblogicServerDir = project.properties['weblogic.server.dir'] adminUrl = project.properties['easyimage.weblogic.admin.t3'] userName = 'weblogic' password = 'weblogic' ant.exec(executable: 'cmd', failonerror: 'false') { arg(line: "/C ${wlsDir}/bin/setWLSEnv.cmd && java ..." ... } ... ESDC 2010 - 54
  • 55.
    ...Builds: GMaven © ASERT2006-2010 ESDC 2010 - 55
  • 56.
    Topics • Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 Gradle • Other Tools • More Info ESDC 2010 - 56
  • 57.
    What is Gradle? • Tool to assist automating (build) steps task hello << { println 'Hello world!' } task intro(dependsOn: hello) << { © ASERT 2008-2010 println "I'm Gradle" } > gradle -q intro Hello world! I'm Gradle ESDC 2010 - 57
  • 58.
    Gradle Features • A very flexible general purpose build tool like Ant • Switchable, build-by-convention frameworks a la Maven. But we never lock you in! • Very powerful support for multi-project builds • Very powerful dependency management (based on Apache Ivy) • Full support for your existing Maven or Ivy repository © ASERT 2006-2010 infrastructure • Support for transitive dependency management without the need for remote repositories or pom.xml and ivy.xml files • Ant tasks as first class citizens • Groovy build scripts • A rich domain model for describing your build ESDC 2010 - 58
  • 59.
    Gradle Examples © ASERT2006-2010 ESDC 2010 - 59
  • 60.
    Revisiting our PreviewExample Switching to IDE © ASERT 2008-2010 ESDC 2010 - 60
  • 61.
    Topics • Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle Other Tools • More Info ESDC 2010 - 61
  • 62.
    Hudson • Gant Plugin — This plugin allows Hudson to invoke Gant build script as the main build step • Gradle Plugin — This plugin allows Hudson to invoke Gradle build script as the main build step • Grails Plugin — This plugin allows Hudson to invoke Grails tasks as build steps © ASERT 2006-2010 • Hudson CLI and GroovyShell Source: http://weblogs.java.net/blog/kohsuke/archive/2009/05/hudson_cli_and.html ESDC 2010 - 62
  • 63.
    Hudson: Groovy PostbuildPlugin... if (manager.logContains(".*uses or overrides a deprecated API.*")) { manager.addWarningBadge("Thou shalt not use deprecated methods.") manager.createSummary("warning.gif").appendText( "<h1>You have been warned!</h1>", false, false, false, "red") manager.buildUnstable() } © ASERT 2006-2010 Source: http://wiki.hudson-ci.org/display/HUDSON/Groovy+Postbuild+Plugin
  • 64.
    ...Hudson: Groovy PostbuildPlugin regex = 'src/main/java/(.*).java:[^ ]* (.*) is Sun proprietary API and may be removed in a future release' map = [:] manager.build.logFile.eachMatch(regex) { full, ownClass, sunClass -> map[ownClass.replaceAll("/", ".")] = sunClass } if (map) { manager.createSummary("warning.gif").with { appendText("Classes using Sun proprietary API:<ul>", false) map.each { k, v -> appendText("<li><b>$k</b> - uses $v</li>", false) © ASERT 2006-2010 } appendText("</ul>", false) } } Adapted from: http://wiki.hudson-ci.org/display/HUDSON/Groovy+Postbuild+Plugin
  • 65.
    Topics • Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle • Other Tools More Info ESDC 2010 - 65
  • 66.
    More Information... • Ant – http://ant.apache.org – http://groovy.codehaus.org/The+groovy+Ant+Task – http://groovy.codehaus.org/Using+Ant+from+Groovy – http://groovy.codehaus.org/Using+Ant+Libraries+with +AntBuilder © ASERT 2008-2010 – http://gant.codehaus.org/ • Maven – http://maven.apache.org – http://gmaven.codehaus.org • Gradle – http://gradle.org ESDC 2010 - 66
  • 67.
    ...More Information... • Groovy Web sites – http://groovy.codehaus.org – http://grails.codehaus.org – http://pleac.sourceforge.net/pleac_groovy (many examples) – http://www.asert.com.au/training/java/GV110.htm (workshop) • Groovy User Mailing list – user@groovy.codehaus.org © ASERT 2006-2010 • Groovy Information portals – http://www.aboutgroovy.org – http://www.groovyblogs.org • Groovy Documentation (1000+ pages) – Getting Started Guide, User Guide, Developer Guide, Testing Guide, Cookbook Examples, Advanced Usage Guide ESDC 2010 - 67
  • 68.
    GinA 2ed “ReGinA”is coming ... © ASERT 2006-2010