SlideShare a Scribd company logo
Groovy & Grails
 Kabisa Kennis Sessie - March 9, 2010




 { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Groovy




          { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Groovy

     Groovy is an agile and dynamic language for the JVM
     • With a Meta-Object Protocol
     • Compiles down to bytecode
     • But also supports static typing




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Groovy

     Groovy is an agile and dynamic language for the JVM
     • With a Meta-Object Protocol
     • Compiles down to bytecode
     • But also supports static typing
     Java on steroids:
     • Builds upon the strengths of Java, but...
     • With power features borrowed from Smalltalk/Python/Ruby
     • Makes modern programming features available to Java
       developers with a flat learning curve




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Groovy

     Groovy is an agile and dynamic language for the JVM
     • With a Meta-Object Protocol
     • Compiles down to bytecode
     • But also supports static typing
     Java on steroids:
     • Builds upon the strengths of Java, but...
     • With power features borrowed from Smalltalk/Python/Ruby
     • Makes modern programming features available to Java
       developers with a flat learning curve
     Seamlessly integrates with all existing Java objects and
     libraries


               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Groovy

     Groovy is an agile and dynamic language for the JVM
     • With a Meta-Object Protocol
     • Compiles down to bytecode
     • But also supports static typing
     Java on steroids:
     • Builds upon the strengths of Java, but...
     • With power features borrowed from Smalltalk/Python/Ruby
     • Makes modern programming features available to Java
       developers with a flat learning curve
     Seamlessly integrates with all existing Java objects and
     libraries
     Feels natural to Java developers

               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
From Java to Groovy

     A normal Java program
     public class HelloWorld {

         private String name;

         public void setName(String name) {
           this.name = name;
         }

         public String getName() {
           return name;
         }

         public String greet() {
           return "Hello " + name;
         }

         public static void main(String[] args) {
           HelloWorld helloWorld = new HelloWorld();
           helloWorld.setName("Groovy");
           System.out.println(helloWorld.greet());
         }
     }


                     { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
From Java to Groovy

     A valid Groovy program
     public class HelloWorld {

         private String name;

         public void setName(String name) {
           this.name = name;
         }

         public String getName() {
           return name;
         }

         public String greet() {
           return "Hello " + name;
         }

         public static void main(String[] args) {
           HelloWorld helloWorld = new HelloWorld();
           helloWorld.setName("Groovy");
           System.out.println(helloWorld.greet());
         }
     }


                     { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
From Java to groovy

     But hey?
     Where are the steroids?




              { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
From Java to Groovy

     A Groovier program
     class HelloWorld {
       def name
       def greet() { "Hello ${name}" }
     }

     helloWorld = new HelloWorld(name: "Groovy")
     println helloWorld.greet()




     Dynamic types using the def keyword
     Everything in Groovy is public unless defined otherwise
     Automatic getters and setters
     Semicolons at end-of-line are optional
     Variable interpolation through GStrings
     Return keyword is optional

                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
From Java to Ruby

     A Ruby program
     class HelloWorld < Struct.new(:name)
       def greet
         "Hello #{name}"
       end
     end

     hello_world = HelloWorld.new("Ruby")
     puts hello_world.greet




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
JVM Languages




                { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Joint Compilation

     Total interoperability


         Java Interface                            Groovy Interface


         Groovy Class                                     Java Class


           Java Class                                 Groovy Class


               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Native Syntax Constructs

     Lists
     • Java: int[] numbers = new int[] { 1, 2, 3 };
     • Groovy: numbers = [1, 2, 3]
     • Ruby: numbers = [1, 2, 3]




                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Native Syntax Constructs

     Lists
     • Java: int[] numbers = new int[] { 1, 2, 3 };
     • Groovy: numbers = [1, 2, 3]
     • Ruby: numbers = [1, 2, 3]

     Maps/Hashes
     • Java: Map countries = new HashMap();
              countries.put("nl", "Netherlands");
              countries.put("be", "Belgium");

     • Groovy: countries = [nl: "Netherlands", be: "Belgium"]
     • Ruby: countries = {:nl => "Netherlands", :be => "Belgium"}



                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Iterating

      Looping
      • Groovy: for (i in list) { println i }
      • Ruby: for i in list
                  puts i
                end




                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Iterating

      Looping
      • Groovy: for (i in list) { println i }
      • Ruby: for i in list
                  puts i
                end




      Looping with closures
      • Groovy: list.each { println it }
      • Ruby: list.each {|i| puts i }




                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
GStrings

     GStrings are interpolated strings
     • Placeholder variables are replaced
     • You can have multiline strings
       def person = "Marcel"
       def letter = """
           ${new Date()}
           Hello ${person},
           You have won 100,000,000GBP in the UK lottery!
       """




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Special Operators

     Elvis operator
     • A shortening of Java's ternary operator
       def displayName = user.name ? user.name : "Anonymous"
       def displayName = user.name ?: "Anonymous"




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Special Operators

     Elvis operator
     • A shortening of Java's ternary operator
        def displayName = user.name ? user.name : "Anonymous"
        def displayName = user.name ?: "Anonymous"


     Safe Navigation Operator
     • Java: String postalCode = null;
              if (user != null) {
                Address address = user.getAddress();
                if (address != null) {
                  postalCode = address.getPostalCode();
                  if (postalCode != null) {
                    postalCode = postalCode.toUpperCase();
                  }
                }
              }

     • Groovy: def postalCode = user?.address?.postalCode?.toUpperCase()
                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
The Groovy Truth

    Booleans
    def a = true
    def b = false
    assert a
    assert !b

    Collections
    def numbers = []
    assert !numbers // false, as numbers is an empty collection
    numbers = [1, 2, 3]
    assert numbers // true, as numbers is not empty

    Strings
    assert 'This is true'
    assert !''

    Numbers
    assert !0 // yeah, 0s are false, like in Perl
    assert 1 // this is also true for all other number types

    Objects
    assert new Object()


                    { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Meta Programming

    You can add methods and properties to any Object at
    runtime
    You can intercept method calls and property access
    (similar to AOP)
    def s = "Hello Groovy"
    println s
    println s.toUpperCase() // standard JDK method
    String.metaClass {
      toMixedCase { delegate.toUpperCase() } // add method
      toUpperCase { delegate.toLowerCase() } // override existing method
      multiply { i -> delegate * i } // add method with argument
    }
    println s.toMixedCase()
    println s.toUpperCase()
    println s.multiply(3)




                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Builders

     Simple mechanism for creating any create any structured
     tree of data
     • You can use out-of-the-box builders
     • You can create your own builders
           import groovy.xml.MarkupBuilder

           def mkp = new MarkupBuilder()
           mkp.html {
             head {
               title "Kabisa ICT"
             }
             body {
               div(class: "container") {
                 p "Welcome to Kabisa ICT"
               }
             }
           }

           println mkp



                     { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Do you want to be Groovy?




                                    ?
              { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Grails




          { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Grails

     Full-stack web application framework inspired by
     • Code by Convention
     • Don’t Repeat Yourself (DRY)
     • Ruby on Rails, Django, TurboGears




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Grails

     Full-stack web application framework inspired by
     • Code by Convention
     • Don’t Repeat Yourself (DRY)
     • Ruby on Rails, Django, TurboGears
     Built on the shoulders of Giants
     • Java/JEE
     • Spring framework
     • Hibernate




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Grails

     Full-stack web application framework inspired by
     • Code by Convention
     • Don’t Repeat Yourself (DRY)
     • Ruby on Rails, Django, TurboGears
     Built on the shoulders of Giants
     • Java/JEE
     • Spring framework
     • Hibernate
     Reduces complexity




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Grails

     Full-stack web application framework inspired by
     • Code by Convention
     • Don’t Repeat Yourself (DRY)
     • Ruby on Rails, Django, TurboGears
     Built on the shoulders of Giants
     • Java/JEE
     • Spring framework
     • Hibernate
     Reduces complexity
     Increases productivity



               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Introduction to Grails

     Full-stack web application framework inspired by
     • Code by Convention
     • Don’t Repeat Yourself (DRY)
     • Ruby on Rails, Django, TurboGears
     Built on the shoulders of Giants
     • Java/JEE
     • Spring framework
     • Hibernate
     Reduces complexity
     Increases productivity
     “Java”


               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Full-stack Web Application Framework

     Easy Object Relational Mapping (ORM) based on
     Hibernate
     View layer with Groovy Server Pages (GSP), dynamic Tag
     Libraries and SiteMesh
     Controller layer based on Spring MVC / Spring Web Flow
     Dependency Injection (DI) using the Spring Container
     Transactional service layer based on Spring’s transaction
     abstraction
     Internationalization (i18n) based on Spring’s
     MessageSource concept
     Embedded Tomcat servlet container for on the fly
     reloading

              { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
About SpringSource, G2One and VMware

    First version of Spring framework was released in 2003




             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
About SpringSource, G2One and VMware

    First version of Spring framework was released in 2003
    SpringSource was founded in 2004




             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
About SpringSource, G2One and VMware

    First version of Spring framework was released in 2003
    SpringSource was founded in 2004
    G2One (The Groovy Grails Company) was founded in
    2007 by the Groovy and Grails project leads




             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
About SpringSource, G2One and VMware

    First version of Spring framework was released in 2003
    SpringSource was founded in 2004
    G2One (The Groovy Grails Company) was founded in
    2007 by the Groovy and Grails project leads
    In November 2008 G2One was acquired by SpringSource




             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
About SpringSource, G2One and VMware

    First version of Spring framework was released in 2003
    SpringSource was founded in 2004
    G2One (The Groovy Grails Company) was founded in
    2007 by the Groovy and Grails project leads
    In November 2008 G2One was acquired by SpringSource
    In August 2009 SpringSource was acquired by VMware for
    $420m




             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
About SpringSource, G2One and VMware

    First version of Spring framework was released in 2003
    SpringSource was founded in 2004
    G2One (The Groovy Grails Company) was founded in
    2007 by the Groovy and Grails project leads
    In November 2008 G2One was acquired by SpringSource
    In August 2009 SpringSource was acquired by VMware for
    $420m
    SpringSource is now a division of VMware




             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Grails Stack


                     Grails
                                                        Other
   JEE         Spring            Hibernate
                                                       Libraries
                                                                         Groovy

                                  Java Development Kit
     Java Language
                                          (JDK)


                        Java Virtual Machine

               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Grails Command Line
    grails   create-app book
    grails   create-domain-class nl.kabisa.book
    grails   create-controller nl.kabisa.book
    grails   generate-all nl.kabisa.book
    grails   install plugin acegi
    grails   run-app
    grails   test-app
    grails   war
    grails   console
    ..
    Custom commands (scripts) can be added to project


             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Grails Project Breakdown
     grails-app               Top level source folder with Grails artifacts
     •   conf                    Configuration sources
     •   controlllers            Controller layer
     •   domain                  Model layer
     •   i18n                    Internationalized Resource Bundles
     •   services                Service layer
     •   taglib                  Dynamic Tag Libraries
     •   views                   Groovy Server Pages (GSP)
     web-app                  Stylesheets, Javascript, ...
     scripts                  Custom command-line scripts
     src                      Other project sources
     • groovy                    Other Groovy project sources
     • java                      Other Java project sources
     lib                      3th Party Libraries
     test                     Unit, Integration and Functional tests

                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Configuration per environment
   dataSource {
     pooled = true
     driverClassName = "org.hsqldb.jdbcDriver"
     username = "sa"
     password = ""
   }
   hibernate {
     cache.use_second_level_cache = true
     cache.use_query_cache = true
     cache.provider_class = "net.sf.ehcache.hibernate.EhCacheProvider"
   }
   // environment specific settings
   environments {
     development {
       dataSource {
         dbCreate = "create-drop" // one of 'create', 'create-drop','update'
         url = "jdbc:hsqldb:mem:devDB"
       }
     }
     production {
       dataSource {
         dbCreate = "update"
         url = "jdbc:hsqldb:file:prodDb;shutdown=true"
       }
     }
   }

                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
GORM

   GORM (Grails Object Relational Mapping)
   •   Domain Modeling
   •   Basic CRUD methods
   •   Dynamic Finders
   •   Events and Auto Timestamping
   •   Validations
   •   Custom ORM mappings with ORM Domain Specific Language




             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
GORM

   GORM (Grails Object Relational Mapping)
   •   Domain Modeling
   •   Basic CRUD methods
   •   Dynamic Finders
   •   Events and Auto Timestamping
   •   Validations
   •   Custom ORM mappings with ORM Domain Specific Language
   NO MIGRATIONS
   • LiquiBase Plugin




             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
GORM

   GORM (Grails Object Relational Mapping)
   •   Domain Modeling
   •   Basic CRUD methods
   •   Dynamic Finders
   •   Events and Auto Timestamping
   •   Validations
   •   Custom ORM mappings with ORM Domain Specific Language
   NO MIGRATIONS
   • LiquiBase Plugin
   Domain model is OOP based, not database based (as in
   Rails)


             { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Domain Classes

   Grails                                            Rails
   class Book {                                      class User < ActiveRecord::Base
     String title                                    end
     String isbn
     BigDecimal price
   }




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Domain Classes

   Grails                                            Rails
   class Author {                                    class Auhor < ActiveRecord::Base
     static hasMany = [books: Book]                    has_many :books
     String name                                     end
   }


   class Book {                                      class Book < ActiveRecord::Base
     static belongsTo = [author: Author]               belongs_to :author
     String title                                    end
     String isbn
     BigDecimal price
   }




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Validations, Events, Auto Timestamping, Mappings
   class Book {
     static belongsTo = [author: Author]

       String title
       String isbn
       BigDecimal price
       Date dateCreated
       Date lastUpdated

       def beforeInsert() {
         dateCreated = new Date()
       }

       static constraints = {
         title(blank: false, maxSize: 100)
         isbn(blank: false, matches: "[0-9]13", minSize: 13, maxSize: 13, unique: true)
         price(nullable: true, min: 0.0, max: 9999.99, scale: 2)
       }

       static mapping = {
         table "books"
         price column: "sales_price"
       }
   }




                      { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Basic CRUD methods

   Grails                                            Rails
   // create                                         # create
   def a = new Author(name: "Rowling")               a = Author.new(:name => "Rowling")
   a.save()                                          a.save

   // read                                           # read
   def a = Author.get(1)                             a = Author.find(1)

   // update                                         # update
   def a = Author.get(1)                             a = Author.find(1)
   a.name = "J.K. Rowling"                           a.name = "J.K. Rowling"
   a.save()                                          a.save

   // delete                                         # delete
   def a = Author.get(1)                             a = Author.find(1)
   a.delete()                                        a.delete




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Querying with GORM
   // query all authors
   def authors = Author.list()

   // pagination
   def authors = Author.list(max: 10, offset: 20)

   // sorting
   def authors = Author.list(order: "name", sort: "desc")

   // pagination and sorting
   def authors = Author.list(max: 10, offset: 20, order: "name", sort: "desc")




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
GORM Dynamic Finders

    FindBy (first result)
    FindAllBy (all results)
    Comparators
    • LessThan, LessThanEquals, GreaterThan, GreaterThanEquals
    • Like, Ilike, NotEqual, InList, Between
    • IsNotNull, IsNull
    def author = Author.findByName("J.K. Rowling")

    def books = Book.findAllByTileIlike("harry p%")

    def books = Book.findAllByPriceLessThan(10.0)

    def books = Book.findAllByTitleLikeAndPriceBetween("Harry P%", 10.0, 20.0)




                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Criteria and HQL
   // using criteria builder
   def c = Book.createCriteria()
   def books = c {
       like("title", "Harry P%")
       and {
           between("price", 10.0, 20.0)
       }
       order("title", "asc")
   }

   // using HQL (Hibernate Query Language)
   def books = Book.findAll("from Book as b where b.title like ?", ["Harry P%"])




                    { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Controllers

     Responsible for handling requests
     Render or prepare responses
     Bind request data to the model (including type conversions)
     Support interceptors
     Support content negotiation
     class SomeController {
       def action = {
         // do controller logic
         // create model
         return model
       }
     }




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Controllers

     Grails
     class BookController {
       def list = {
         [bookList: Book.list()]
       }
     }


     <ul>
         <g:each in="${bookList}">
             <li>${it.title}</li>
         </g:each>
     </ul>




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Controllers

     Grails
     class BookController {
       def list = {
         [bookList: Book.list()]
       }
     }


     <ul>
         <g:each in="${bookList}">
             <li>${it.title}</li>
         </g:each>
     </ul>



     Rails
     class BooksController < ApplicationController
       def list
         @books = Book.all
       end
     end




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Example Controller
   class BookController {

       static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

       def index = { redirect(action: "list", params: params) }

      def list = {
          [bookInstanceList: Book.list(params), bookInstanceTotal: Book.count()]
      }

      def create = {
          def bookInstance = new Book()
          bookInstance.properties = params
          return [bookInstance: bookInstance]
      }

      def save = {
          def bookInstance = new Book(params)
          if (bookInstance.save()) {
              redirect(action: "show", id: bookInstance.id)
          }
          else {
              render(view: "create", model: [bookInstance: bookInstance])
          }
      }


                    { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Example Controller
     def edit = {
         def bookInstance = Book.get(params.id)
         if (!bookInstance) {
             redirect(action: "list")
         }
         else {
             return [bookInstance: bookInstance]
         }
     }

     def update = {
         def bookInstance = Book.get(params.id)
         if (bookInstance) {
             bookInstance.properties = params
             if (!bookInstance.hasErrors() && bookInstance.save()) {
                 redirect(action: "show", id: bookInstance.id)
             }
             else {
                 render(view: "edit", model: [bookInstance: bookInstance])
             }
         }
         else {
             redirect(action: "list")
         }
     }


                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Example Controller
       def delete = {
           def bookInstance = Book.get(params.id)
           if (bookInstance) {
               bookInstance.delete(flush: true)
               redirect(action: "list")
           }
           else {
               redirect(action: "list")
           }
       }

       def show = {
           def bookInstance = Book.get(params.id)
           if (!bookInstance) {
               redirect(action: "list")
           }
           else {
               [bookInstance: bookInstance]
           }
       }

       def beforeInterceptor = { // do something }

       def afterInterceptor = { // do something }
   }


                    { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
XML Responses
   def list = {
       def bookList = Book.list()
       render(contentType: "text/xml") {
           books {
                for (b in bookList) {
                    book(title: b.title)
               }
           }
       }
   }

   // automatic xml marshalling
   def list = {
       render Book.list() as XML
   }




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Content Negotiation

     You can use HTTP Accept Header
     You can use format request paramter (/book/list?format=xml)
     You can use URI extension (/book/list.xml)
     Use the withFormat method to deal with different
     formats
     class BookController {
         def list = {
             def books = Book.list()
             withFormat {
                 html bookList:books
                 js { render "alert('hello')" }
                 xml { render books as XML }
             }
         }
     }




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Views

    Groovy Server Pages (GSP)
    • Similar like technologies like JSP and ASP
    • A mix of markup and GSP tags
    • Groovy code can be embedded, but is discouraged




              { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Views

    Groovy Server Pages (GSP)
    • Similar like technologies like JSP and ASP
    • A mix of markup and GSP tags
    • Groovy code can be embedded, but is discouraged
    NO HAML :-(




              { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Views

    Groovy Server Pages (GSP)
    • Similar like technologies like JSP and ASP
    • A mix of markup and GSP tags
    • Groovy code can be embedded, but is discouraged
    NO HAML :-(
    def show = {
        [book: Book.get(params.id)]
    }




                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Views

    Groovy Server Pages (GSP)
    • Similar like technologies like JSP and ASP
    • A mix of markup and GSP tags
    • Groovy code can be embedded, but is discouraged
    NO HAML :-(
    def show = {
        [book: Book.get(params.id)]
    }


    <%= book.title %>




                  { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Views and Tag Libraries

     Embedded Groovy code
     <html>
         <body>
             <% [1, 2, 3, 4].each { num ->
                 if (num > 2) { %>
                     <p><%= "Hello ${num}!" %></p>
             <% }
                } %>
         </body>
     </html>




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Views and Tag Libraries

     Embedded Groovy code
     <html>
         <body>
             <% [1, 2, 3, 4].each { num ->
                 if (num > 2) { %>
                     <p><%= "Hello ${num}!" %></p>
             <% }
                } %>
         </body>
     </html>

     Use Tag Libraries instead
     <html>
         <body>
             <g:each in="${[1, 2, 3, 4]}" var="num">
                 <g:if test="${num > 2}">
                     <p>Number ${num}</p>
                 </g:if>
             </g:each>
         </body>
     </html>




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code
     Like helpers in Rails




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code
     Like helpers in Rails
     Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while>




                 { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code
     Like helpers in Rails
     Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while>
     Links and Resources
     <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link>
     <g:link controller="book" action="list">Book List</g:link>




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code
     Like helpers in Rails
     Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while>
     Links and Resources
     <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link>
     <g:link controller="book" action="list">Book List</g:link>

     Forms and Fields
     <g:textField name="title" value="${bookInstance.title}" />
     <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" />
     <g:datePicker name="publishDate" value="${bookInstance.publishDate}" />




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code
     Like helpers in Rails
     Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while>
     Links and Resources
     <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link>
     <g:link controller="book" action="list">Book List</g:link>

     Forms and Fields
     <g:textField name="title" value="${bookInstance.title}" />
     <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" />
     <g:datePicker name="publishDate" value="${bookInstance.publishDate}" />

     Formatting




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code
     Like helpers in Rails
     Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while>
     Links and Resources
     <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link>
     <g:link controller="book" action="list">Book List</g:link>

     Forms and Fields
     <g:textField name="title" value="${bookInstance.title}" />
     <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" />
     <g:datePicker name="publishDate" value="${bookInstance.publishDate}" />

     Formatting
     Ajax



                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code
     Like helpers in Rails
     Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while>
     Links and Resources
     <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link>
     <g:link controller="book" action="list">Book List</g:link>

     Forms and Fields
     <g:textField name="title" value="${bookInstance.title}" />
     <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" />
     <g:datePicker name="publishDate" value="${bookInstance.publishDate}" />

     Formatting
     Ajax
     and more...

                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Core Tag Libraries

     Much more attractive than embedded Groovy code
     Like helpers in Rails
     Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while>
     Links and Resources
     <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link>
     <g:link controller="book" action="list">Book List</g:link>

     Forms and Fields
     <g:textField name="title" value="${bookInstance.title}" />
     <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" />
     <g:datePicker name="publishDate" value="${bookInstance.publishDate}" />

     Formatting
     Ajax
     and more...

                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Custom Tag Libraries

     Very complex and painful in standard Java
     • Complex interfaces to implement
     • Additional Tag Library Descriptors (XML) must be written
     • And need to be configured in web.xml




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Custom Tag Libraries

     Very complex and painful in standard Java
     • Complex interfaces to implement
     • Additional Tag Library Descriptors (XML) must be written
     • And need to be configured in web.xml
     But so easy in Grails
     class SimpleTagLib {
         static namespace = "auth"
         def isAdmin = { attrs, body ->
             if (attrs.user.admin)
                 out << body()
         }
     }


     <auth:isAdmin user="${session.user}">
         // some restricted content
     </auth:isAdmin>




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Views and Layouts
   <html>
     <head>
       <meta name="layout" content="main" />
       <title>Book List</title>
     </head>
     <body>
       <div class="nav">
          <span><a class="home" href="${createLink(uri: '/')}">Home</a></span>
          <span><g:link class="create" action="create">New Book</g:link></span>
       </div>
       <div class="body">
          <div class="list">
            <table>
              <g:each in="${bookInstanceList}" status="i" var="bookInstance">
                 <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
                   <td><g:link action="show" id="${bookInstance.id}">${bookInstance.id}</
   g:link></td>
                   <td>${bookInstance.title}</td>
                 </tr>
              </g:each>
            </table>
          </div>
       </div>
     </body>
   </html>


                    { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
URL Mappings

   Used for mapping URL’s to controllers
    • Similar like routes in Rails
    • Default convention is /controller/action/id




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
URL Mappings

   Used for mapping URL’s to controllers
     • Similar like routes in Rails
     • Default convention is /controller/action/id
   class UrlMappings {
       static mappings = {
           "/product" (controller: "product", action: "list")
           "/product/$id" (controller: "product")
           "/$blog/$year/$month/$day/$id" (controller: "blog", action: "show")
       }
   }




                   { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Filters

      Controllers already support fine grained interceptors but
      these are difficult to manage in larger applications




               { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Filters

      Controllers already support fine grained interceptors but
      these are difficult to manage in larger applications
      Use filters instead
      •   A Domain Specific Language is available for defining filters
      •   You can define scopes (all controllers, a specific controller/action, URI pattern)
      •   You can define interceptor types (before, after, afterView)
      •   You can use variables (params, request, response, session, grailsApplication)




                    { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Filters

      Controllers already support fine grained interceptors but
      these are difficult to manage in larger applications
      Use filters instead
      •   A Domain Specific Language is available for defining filters
      •   You can define scopes (all controllers, a specific controller/action, URI pattern)
      •   You can define interceptor types (before, after, afterView)
      •   You can use variables (params, request, response, session, grailsApplication)
      class SecurityFilters {
         def filters = {
             loginCheck(controller: '*', action: '*') {
                 before = {
                    if(!session.user && !actionName.equals('login')) {
                        redirect(action: 'login')
                         return false
                     }
                 }
             }
         }
      }
                    { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Services

     Don’t put core/reusable logic in controllers, but instead
     use the service layer
     Services are by default transactional
     Services can be scoped
     class BookService {

           static scope = "singleton" // other options include prototype, request, session
           static transactional = true

           def doSomething() {
               // TODO: implement
           }
     }




                     { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Plugins

     Grails is designed with a plugin architecture in mind
     Grails core features are built on plugins
     Plugins can provide basic artifacts
     • Domain Classes, Tag Libraries, Services, ...
     Plugins can provide new artifact types
     Plugins can hook into build events
     Plugins can hook into runtime configuration
     Plugins can add dynamic methods at runtime




                { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Plugins

     Spring Security                              LDAP
     Quartz                                       Commentable
     Searchable                                   Selenium RC
     Mail                                         Fixtures
     Canoo Webtest                                ReCaptcha
     GWT                                          LiquiBase
     Feeds                                        GORM-JPA
     Taggable                                     iWebKit
     Rateable                                     Webdriver
     XFire                                        Axis2
     Spring WS                                    Wicket

              { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Tooling

     Integrated Development Environments
     • SpringSource Tool Suite (STS)
     • NetBeans
     • IDEA IntelliJ
     TextMate




                { Agile Development } { Ruby on Rails } { Java / J2EE }
Groovy & Grails
Discussion & Demo




                             !?
             { Agile Development } { Ruby on Rails } { Java / J2EE }
{ Agile Development } { Ruby on Rails } { Java / J2EE }

More Related Content

KEY
Introduction To Grails
PDF
An Introduction to Groovy for Java Developers
PDF
JavaCro 2016 - From Java to Groovy: Adventure Time!
PDF
Embedding Groovy in a Java Application
PDF
Better DSL Support for Groovy-Eclipse
PDF
Practical Groovy DSL
PDF
Apache Groovy: the language and the ecosystem
PDF
GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
Introduction To Grails
An Introduction to Groovy for Java Developers
JavaCro 2016 - From Java to Groovy: Adventure Time!
Embedding Groovy in a Java Application
Better DSL Support for Groovy-Eclipse
Practical Groovy DSL
Apache Groovy: the language and the ecosystem
GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge

What's hot (20)

PDF
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
PDF
Grooscript gr8conf
PDF
Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020
ODP
eXo EC - Groovy Programming Language
PDF
Whats New In Groovy 1.6?
PPT
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
PDF
DSL's with Groovy
PDF
Greach 2014 - Metaprogramming with groovy
KEY
Groovy overview, DSLs and ecosystem - Mars JUG - 2010
PDF
Atlassian Groovy Plugins
PDF
re-frame à la spec
PDF
OpenLogic
KEY
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
PPTX
Metaprogramming Techniques In Groovy And Grails
PPT
What's New in Groovy 1.6?
PPS
Groovy & Grails
PPT
Groovy AST Demystified
PDF
Groovy Domain Specific Languages - SpringOne2GX 2012
PPTX
Dart the Better JavaScript
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
Grooscript gr8conf
Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020
eXo EC - Groovy Programming Language
Whats New In Groovy 1.6?
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
DSL's with Groovy
Greach 2014 - Metaprogramming with groovy
Groovy overview, DSLs and ecosystem - Mars JUG - 2010
Atlassian Groovy Plugins
re-frame à la spec
OpenLogic
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Metaprogramming Techniques In Groovy And Grails
What's New in Groovy 1.6?
Groovy & Grails
Groovy AST Demystified
Groovy Domain Specific Languages - SpringOne2GX 2012
Dart the Better JavaScript
Ad

Similar to Groovy & Grails (20)

PDF
Oscon Java Testing on the Fast Lane
PDF
JRuby Basics
PDF
Introduction to Oracle Groovy
PPT
Svcc Groovy Testing
PPT
Boosting Your Testing Productivity with Groovy
PPT
Javaone2008 Bof 5101 Groovytesting
PPT
GTAC Boosting your Testing Productivity with Groovy
PPT
Eclipsecon08 Introduction To Groovy
PPTX
Groovy And Grails Introduction
PPT
Introduction To Groovy
ODP
ZIP
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
PPT
Groovy for Java Developers
PDF
Groovy Up Your Code
PDF
Ugo Cei Presentation
PDF
Introduction to Groovy
PPT
2007 09 10 Fzi Training Groovy Grails V Ws
PDF
Groovy a Scripting Language for Java
KEY
Startup groovysession1
PDF
Dsl로 만나는 groovy
Oscon Java Testing on the Fast Lane
JRuby Basics
Introduction to Oracle Groovy
Svcc Groovy Testing
Boosting Your Testing Productivity with Groovy
Javaone2008 Bof 5101 Groovytesting
GTAC Boosting your Testing Productivity with Groovy
Eclipsecon08 Introduction To Groovy
Groovy And Grails Introduction
Introduction To Groovy
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy for Java Developers
Groovy Up Your Code
Ugo Cei Presentation
Introduction to Groovy
2007 09 10 Fzi Training Groovy Grails V Ws
Groovy a Scripting Language for Java
Startup groovysession1
Dsl로 만나는 groovy
Ad

Recently uploaded (20)

PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PPTX
A Presentation on Artificial Intelligence
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
August Patch Tuesday
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
TLE Review Electricity (Electricity).pptx
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
Spectroscopy.pptx food analysis technology
PDF
Getting Started with Data Integration: FME Form 101
PPTX
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Empathic Computing: Creating Shared Understanding
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
NewMind AI Weekly Chronicles - August'25-Week II
A Presentation on Artificial Intelligence
Group 1 Presentation -Planning and Decision Making .pptx
Network Security Unit 5.pdf for BCA BBA.
Agricultural_Statistics_at_a_Glance_2022_0.pdf
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Assigned Numbers - 2025 - Bluetooth® Document
August Patch Tuesday
Digital-Transformation-Roadmap-for-Companies.pptx
TLE Review Electricity (Electricity).pptx
Programs and apps: productivity, graphics, security and other tools
Spectral efficient network and resource selection model in 5G networks
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Spectroscopy.pptx food analysis technology
Getting Started with Data Integration: FME Form 101
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Empathic Computing: Creating Shared Understanding

Groovy & Grails

  • 1. Groovy & Grails Kabisa Kennis Sessie - March 9, 2010 { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 2. Groovy & Grails Groovy { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 3. Groovy & Grails Introduction to Groovy Groovy is an agile and dynamic language for the JVM • With a Meta-Object Protocol • Compiles down to bytecode • But also supports static typing { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 4. Groovy & Grails Introduction to Groovy Groovy is an agile and dynamic language for the JVM • With a Meta-Object Protocol • Compiles down to bytecode • But also supports static typing Java on steroids: • Builds upon the strengths of Java, but... • With power features borrowed from Smalltalk/Python/Ruby • Makes modern programming features available to Java developers with a flat learning curve { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 5. Groovy & Grails Introduction to Groovy Groovy is an agile and dynamic language for the JVM • With a Meta-Object Protocol • Compiles down to bytecode • But also supports static typing Java on steroids: • Builds upon the strengths of Java, but... • With power features borrowed from Smalltalk/Python/Ruby • Makes modern programming features available to Java developers with a flat learning curve Seamlessly integrates with all existing Java objects and libraries { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 6. Groovy & Grails Introduction to Groovy Groovy is an agile and dynamic language for the JVM • With a Meta-Object Protocol • Compiles down to bytecode • But also supports static typing Java on steroids: • Builds upon the strengths of Java, but... • With power features borrowed from Smalltalk/Python/Ruby • Makes modern programming features available to Java developers with a flat learning curve Seamlessly integrates with all existing Java objects and libraries Feels natural to Java developers { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 7. Groovy & Grails From Java to Groovy A normal Java program public class HelloWorld { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public String greet() { return "Hello " + name; } public static void main(String[] args) { HelloWorld helloWorld = new HelloWorld(); helloWorld.setName("Groovy"); System.out.println(helloWorld.greet()); } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 8. Groovy & Grails From Java to Groovy A valid Groovy program public class HelloWorld { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public String greet() { return "Hello " + name; } public static void main(String[] args) { HelloWorld helloWorld = new HelloWorld(); helloWorld.setName("Groovy"); System.out.println(helloWorld.greet()); } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 9. Groovy & Grails From Java to groovy But hey? Where are the steroids? { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 10. Groovy & Grails From Java to Groovy A Groovier program class HelloWorld { def name def greet() { "Hello ${name}" } } helloWorld = new HelloWorld(name: "Groovy") println helloWorld.greet() Dynamic types using the def keyword Everything in Groovy is public unless defined otherwise Automatic getters and setters Semicolons at end-of-line are optional Variable interpolation through GStrings Return keyword is optional { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 11. Groovy & Grails From Java to Ruby A Ruby program class HelloWorld < Struct.new(:name) def greet "Hello #{name}" end end hello_world = HelloWorld.new("Ruby") puts hello_world.greet { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 12. Groovy & Grails JVM Languages { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 13. Groovy & Grails Joint Compilation Total interoperability Java Interface Groovy Interface Groovy Class Java Class Java Class Groovy Class { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 14. Groovy & Grails Native Syntax Constructs Lists • Java: int[] numbers = new int[] { 1, 2, 3 }; • Groovy: numbers = [1, 2, 3] • Ruby: numbers = [1, 2, 3] { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 15. Groovy & Grails Native Syntax Constructs Lists • Java: int[] numbers = new int[] { 1, 2, 3 }; • Groovy: numbers = [1, 2, 3] • Ruby: numbers = [1, 2, 3] Maps/Hashes • Java: Map countries = new HashMap(); countries.put("nl", "Netherlands"); countries.put("be", "Belgium"); • Groovy: countries = [nl: "Netherlands", be: "Belgium"] • Ruby: countries = {:nl => "Netherlands", :be => "Belgium"} { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 16. Groovy & Grails Iterating Looping • Groovy: for (i in list) { println i } • Ruby: for i in list puts i end { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 17. Groovy & Grails Iterating Looping • Groovy: for (i in list) { println i } • Ruby: for i in list puts i end Looping with closures • Groovy: list.each { println it } • Ruby: list.each {|i| puts i } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 18. Groovy & Grails GStrings GStrings are interpolated strings • Placeholder variables are replaced • You can have multiline strings def person = "Marcel" def letter = """ ${new Date()} Hello ${person}, You have won 100,000,000GBP in the UK lottery! """ { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 19. Groovy & Grails Special Operators Elvis operator • A shortening of Java's ternary operator def displayName = user.name ? user.name : "Anonymous" def displayName = user.name ?: "Anonymous" { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 20. Groovy & Grails Special Operators Elvis operator • A shortening of Java's ternary operator def displayName = user.name ? user.name : "Anonymous" def displayName = user.name ?: "Anonymous" Safe Navigation Operator • Java: String postalCode = null; if (user != null) { Address address = user.getAddress(); if (address != null) { postalCode = address.getPostalCode(); if (postalCode != null) { postalCode = postalCode.toUpperCase(); } } } • Groovy: def postalCode = user?.address?.postalCode?.toUpperCase() { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 21. Groovy & Grails The Groovy Truth Booleans def a = true def b = false assert a assert !b Collections def numbers = [] assert !numbers // false, as numbers is an empty collection numbers = [1, 2, 3] assert numbers // true, as numbers is not empty Strings assert 'This is true' assert !'' Numbers assert !0 // yeah, 0s are false, like in Perl assert 1 // this is also true for all other number types Objects assert new Object() { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 22. Groovy & Grails Meta Programming You can add methods and properties to any Object at runtime You can intercept method calls and property access (similar to AOP) def s = "Hello Groovy" println s println s.toUpperCase() // standard JDK method String.metaClass { toMixedCase { delegate.toUpperCase() } // add method toUpperCase { delegate.toLowerCase() } // override existing method multiply { i -> delegate * i } // add method with argument } println s.toMixedCase() println s.toUpperCase() println s.multiply(3) { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 23. Groovy & Grails Builders Simple mechanism for creating any create any structured tree of data • You can use out-of-the-box builders • You can create your own builders import groovy.xml.MarkupBuilder def mkp = new MarkupBuilder() mkp.html { head { title "Kabisa ICT" } body { div(class: "container") { p "Welcome to Kabisa ICT" } } } println mkp { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 24. Groovy & Grails Do you want to be Groovy? ? { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 25. Groovy & Grails Grails { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 26. Groovy & Grails Introduction to Grails Full-stack web application framework inspired by • Code by Convention • Don’t Repeat Yourself (DRY) • Ruby on Rails, Django, TurboGears { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 27. Groovy & Grails Introduction to Grails Full-stack web application framework inspired by • Code by Convention • Don’t Repeat Yourself (DRY) • Ruby on Rails, Django, TurboGears Built on the shoulders of Giants • Java/JEE • Spring framework • Hibernate { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 28. Groovy & Grails Introduction to Grails Full-stack web application framework inspired by • Code by Convention • Don’t Repeat Yourself (DRY) • Ruby on Rails, Django, TurboGears Built on the shoulders of Giants • Java/JEE • Spring framework • Hibernate Reduces complexity { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 29. Groovy & Grails Introduction to Grails Full-stack web application framework inspired by • Code by Convention • Don’t Repeat Yourself (DRY) • Ruby on Rails, Django, TurboGears Built on the shoulders of Giants • Java/JEE • Spring framework • Hibernate Reduces complexity Increases productivity { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 30. Groovy & Grails Introduction to Grails Full-stack web application framework inspired by • Code by Convention • Don’t Repeat Yourself (DRY) • Ruby on Rails, Django, TurboGears Built on the shoulders of Giants • Java/JEE • Spring framework • Hibernate Reduces complexity Increases productivity “Java” { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 31. Groovy & Grails Full-stack Web Application Framework Easy Object Relational Mapping (ORM) based on Hibernate View layer with Groovy Server Pages (GSP), dynamic Tag Libraries and SiteMesh Controller layer based on Spring MVC / Spring Web Flow Dependency Injection (DI) using the Spring Container Transactional service layer based on Spring’s transaction abstraction Internationalization (i18n) based on Spring’s MessageSource concept Embedded Tomcat servlet container for on the fly reloading { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 32. Groovy & Grails About SpringSource, G2One and VMware First version of Spring framework was released in 2003 { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 33. Groovy & Grails About SpringSource, G2One and VMware First version of Spring framework was released in 2003 SpringSource was founded in 2004 { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 34. Groovy & Grails About SpringSource, G2One and VMware First version of Spring framework was released in 2003 SpringSource was founded in 2004 G2One (The Groovy Grails Company) was founded in 2007 by the Groovy and Grails project leads { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 35. Groovy & Grails About SpringSource, G2One and VMware First version of Spring framework was released in 2003 SpringSource was founded in 2004 G2One (The Groovy Grails Company) was founded in 2007 by the Groovy and Grails project leads In November 2008 G2One was acquired by SpringSource { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 36. Groovy & Grails About SpringSource, G2One and VMware First version of Spring framework was released in 2003 SpringSource was founded in 2004 G2One (The Groovy Grails Company) was founded in 2007 by the Groovy and Grails project leads In November 2008 G2One was acquired by SpringSource In August 2009 SpringSource was acquired by VMware for $420m { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 37. Groovy & Grails About SpringSource, G2One and VMware First version of Spring framework was released in 2003 SpringSource was founded in 2004 G2One (The Groovy Grails Company) was founded in 2007 by the Groovy and Grails project leads In November 2008 G2One was acquired by SpringSource In August 2009 SpringSource was acquired by VMware for $420m SpringSource is now a division of VMware { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 38. Groovy & Grails Grails Stack Grails Other JEE Spring Hibernate Libraries Groovy Java Development Kit Java Language (JDK) Java Virtual Machine { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 39. Groovy & Grails Grails Command Line grails create-app book grails create-domain-class nl.kabisa.book grails create-controller nl.kabisa.book grails generate-all nl.kabisa.book grails install plugin acegi grails run-app grails test-app grails war grails console .. Custom commands (scripts) can be added to project { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 40. Groovy & Grails Grails Project Breakdown grails-app Top level source folder with Grails artifacts • conf Configuration sources • controlllers Controller layer • domain Model layer • i18n Internationalized Resource Bundles • services Service layer • taglib Dynamic Tag Libraries • views Groovy Server Pages (GSP) web-app Stylesheets, Javascript, ... scripts Custom command-line scripts src Other project sources • groovy Other Groovy project sources • java Other Java project sources lib 3th Party Libraries test Unit, Integration and Functional tests { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 41. Groovy & Grails Configuration per environment dataSource { pooled = true driverClassName = "org.hsqldb.jdbcDriver" username = "sa" password = "" } hibernate { cache.use_second_level_cache = true cache.use_query_cache = true cache.provider_class = "net.sf.ehcache.hibernate.EhCacheProvider" } // environment specific settings environments { development { dataSource { dbCreate = "create-drop" // one of 'create', 'create-drop','update' url = "jdbc:hsqldb:mem:devDB" } } production { dataSource { dbCreate = "update" url = "jdbc:hsqldb:file:prodDb;shutdown=true" } } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 42. Groovy & Grails GORM GORM (Grails Object Relational Mapping) • Domain Modeling • Basic CRUD methods • Dynamic Finders • Events and Auto Timestamping • Validations • Custom ORM mappings with ORM Domain Specific Language { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 43. Groovy & Grails GORM GORM (Grails Object Relational Mapping) • Domain Modeling • Basic CRUD methods • Dynamic Finders • Events and Auto Timestamping • Validations • Custom ORM mappings with ORM Domain Specific Language NO MIGRATIONS • LiquiBase Plugin { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 44. Groovy & Grails GORM GORM (Grails Object Relational Mapping) • Domain Modeling • Basic CRUD methods • Dynamic Finders • Events and Auto Timestamping • Validations • Custom ORM mappings with ORM Domain Specific Language NO MIGRATIONS • LiquiBase Plugin Domain model is OOP based, not database based (as in Rails) { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 45. Groovy & Grails Domain Classes Grails Rails class Book { class User < ActiveRecord::Base String title end String isbn BigDecimal price } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 46. Groovy & Grails Domain Classes Grails Rails class Author { class Auhor < ActiveRecord::Base static hasMany = [books: Book] has_many :books String name end } class Book { class Book < ActiveRecord::Base static belongsTo = [author: Author] belongs_to :author String title end String isbn BigDecimal price } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 47. Groovy & Grails Validations, Events, Auto Timestamping, Mappings class Book { static belongsTo = [author: Author] String title String isbn BigDecimal price Date dateCreated Date lastUpdated def beforeInsert() { dateCreated = new Date() } static constraints = { title(blank: false, maxSize: 100) isbn(blank: false, matches: "[0-9]13", minSize: 13, maxSize: 13, unique: true) price(nullable: true, min: 0.0, max: 9999.99, scale: 2) } static mapping = { table "books" price column: "sales_price" } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 48. Groovy & Grails Basic CRUD methods Grails Rails // create # create def a = new Author(name: "Rowling") a = Author.new(:name => "Rowling") a.save() a.save // read # read def a = Author.get(1) a = Author.find(1) // update # update def a = Author.get(1) a = Author.find(1) a.name = "J.K. Rowling" a.name = "J.K. Rowling" a.save() a.save // delete # delete def a = Author.get(1) a = Author.find(1) a.delete() a.delete { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 49. Groovy & Grails Querying with GORM // query all authors def authors = Author.list() // pagination def authors = Author.list(max: 10, offset: 20) // sorting def authors = Author.list(order: "name", sort: "desc") // pagination and sorting def authors = Author.list(max: 10, offset: 20, order: "name", sort: "desc") { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 50. Groovy & Grails GORM Dynamic Finders FindBy (first result) FindAllBy (all results) Comparators • LessThan, LessThanEquals, GreaterThan, GreaterThanEquals • Like, Ilike, NotEqual, InList, Between • IsNotNull, IsNull def author = Author.findByName("J.K. Rowling") def books = Book.findAllByTileIlike("harry p%") def books = Book.findAllByPriceLessThan(10.0) def books = Book.findAllByTitleLikeAndPriceBetween("Harry P%", 10.0, 20.0) { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 51. Groovy & Grails Criteria and HQL // using criteria builder def c = Book.createCriteria() def books = c { like("title", "Harry P%") and { between("price", 10.0, 20.0) } order("title", "asc") } // using HQL (Hibernate Query Language) def books = Book.findAll("from Book as b where b.title like ?", ["Harry P%"]) { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 52. Groovy & Grails Controllers Responsible for handling requests Render or prepare responses Bind request data to the model (including type conversions) Support interceptors Support content negotiation class SomeController { def action = { // do controller logic // create model return model } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 53. Groovy & Grails Controllers Grails class BookController { def list = { [bookList: Book.list()] } } <ul> <g:each in="${bookList}"> <li>${it.title}</li> </g:each> </ul> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 54. Groovy & Grails Controllers Grails class BookController { def list = { [bookList: Book.list()] } } <ul> <g:each in="${bookList}"> <li>${it.title}</li> </g:each> </ul> Rails class BooksController < ApplicationController def list @books = Book.all end end { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 55. Groovy & Grails Example Controller class BookController { static allowedMethods = [save: "POST", update: "POST", delete: "POST"] def index = { redirect(action: "list", params: params) } def list = { [bookInstanceList: Book.list(params), bookInstanceTotal: Book.count()] } def create = { def bookInstance = new Book() bookInstance.properties = params return [bookInstance: bookInstance] } def save = { def bookInstance = new Book(params) if (bookInstance.save()) { redirect(action: "show", id: bookInstance.id) } else { render(view: "create", model: [bookInstance: bookInstance]) } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 56. Groovy & Grails Example Controller def edit = { def bookInstance = Book.get(params.id) if (!bookInstance) { redirect(action: "list") } else { return [bookInstance: bookInstance] } } def update = { def bookInstance = Book.get(params.id) if (bookInstance) { bookInstance.properties = params if (!bookInstance.hasErrors() && bookInstance.save()) { redirect(action: "show", id: bookInstance.id) } else { render(view: "edit", model: [bookInstance: bookInstance]) } } else { redirect(action: "list") } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 57. Groovy & Grails Example Controller def delete = { def bookInstance = Book.get(params.id) if (bookInstance) { bookInstance.delete(flush: true) redirect(action: "list") } else { redirect(action: "list") } } def show = { def bookInstance = Book.get(params.id) if (!bookInstance) { redirect(action: "list") } else { [bookInstance: bookInstance] } } def beforeInterceptor = { // do something } def afterInterceptor = { // do something } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 58. Groovy & Grails XML Responses def list = { def bookList = Book.list() render(contentType: "text/xml") { books { for (b in bookList) { book(title: b.title) } } } } // automatic xml marshalling def list = { render Book.list() as XML } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 59. Groovy & Grails Content Negotiation You can use HTTP Accept Header You can use format request paramter (/book/list?format=xml) You can use URI extension (/book/list.xml) Use the withFormat method to deal with different formats class BookController { def list = { def books = Book.list() withFormat { html bookList:books js { render "alert('hello')" } xml { render books as XML } } } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 60. Groovy & Grails Views Groovy Server Pages (GSP) • Similar like technologies like JSP and ASP • A mix of markup and GSP tags • Groovy code can be embedded, but is discouraged { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 61. Groovy & Grails Views Groovy Server Pages (GSP) • Similar like technologies like JSP and ASP • A mix of markup and GSP tags • Groovy code can be embedded, but is discouraged NO HAML :-( { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 62. Groovy & Grails Views Groovy Server Pages (GSP) • Similar like technologies like JSP and ASP • A mix of markup and GSP tags • Groovy code can be embedded, but is discouraged NO HAML :-( def show = { [book: Book.get(params.id)] } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 63. Groovy & Grails Views Groovy Server Pages (GSP) • Similar like technologies like JSP and ASP • A mix of markup and GSP tags • Groovy code can be embedded, but is discouraged NO HAML :-( def show = { [book: Book.get(params.id)] } <%= book.title %> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 64. Groovy & Grails Views and Tag Libraries Embedded Groovy code <html> <body> <% [1, 2, 3, 4].each { num -> if (num > 2) { %> <p><%= "Hello ${num}!" %></p> <% } } %> </body> </html> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 65. Groovy & Grails Views and Tag Libraries Embedded Groovy code <html> <body> <% [1, 2, 3, 4].each { num -> if (num > 2) { %> <p><%= "Hello ${num}!" %></p> <% } } %> </body> </html> Use Tag Libraries instead <html> <body> <g:each in="${[1, 2, 3, 4]}" var="num"> <g:if test="${num > 2}"> <p>Number ${num}</p> </g:if> </g:each> </body> </html> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 66. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 67. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code Like helpers in Rails { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 68. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code Like helpers in Rails Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 69. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code Like helpers in Rails Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while> Links and Resources <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link> <g:link controller="book" action="list">Book List</g:link> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 70. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code Like helpers in Rails Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while> Links and Resources <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link> <g:link controller="book" action="list">Book List</g:link> Forms and Fields <g:textField name="title" value="${bookInstance.title}" /> <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" /> <g:datePicker name="publishDate" value="${bookInstance.publishDate}" /> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 71. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code Like helpers in Rails Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while> Links and Resources <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link> <g:link controller="book" action="list">Book List</g:link> Forms and Fields <g:textField name="title" value="${bookInstance.title}" /> <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" /> <g:datePicker name="publishDate" value="${bookInstance.publishDate}" /> Formatting { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 72. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code Like helpers in Rails Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while> Links and Resources <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link> <g:link controller="book" action="list">Book List</g:link> Forms and Fields <g:textField name="title" value="${bookInstance.title}" /> <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" /> <g:datePicker name="publishDate" value="${bookInstance.publishDate}" /> Formatting Ajax { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 73. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code Like helpers in Rails Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while> Links and Resources <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link> <g:link controller="book" action="list">Book List</g:link> Forms and Fields <g:textField name="title" value="${bookInstance.title}" /> <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" /> <g:datePicker name="publishDate" value="${bookInstance.publishDate}" /> Formatting Ajax and more... { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 74. Groovy & Grails Core Tag Libraries Much more attractive than embedded Groovy code Like helpers in Rails Logic and Iteration <g:if> <g:else> <g:elsif> <g:each> <g:while> Links and Resources <g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link> <g:link controller="book" action="list">Book List</g:link> Forms and Fields <g:textField name="title" value="${bookInstance.title}" /> <g:select name="author.id" from="${Author.list()}" value="${bookInstance.author.id}" /> <g:datePicker name="publishDate" value="${bookInstance.publishDate}" /> Formatting Ajax and more... { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 75. Groovy & Grails Custom Tag Libraries Very complex and painful in standard Java • Complex interfaces to implement • Additional Tag Library Descriptors (XML) must be written • And need to be configured in web.xml { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 76. Groovy & Grails Custom Tag Libraries Very complex and painful in standard Java • Complex interfaces to implement • Additional Tag Library Descriptors (XML) must be written • And need to be configured in web.xml But so easy in Grails class SimpleTagLib { static namespace = "auth" def isAdmin = { attrs, body -> if (attrs.user.admin) out << body() } } <auth:isAdmin user="${session.user}"> // some restricted content </auth:isAdmin> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 77. Groovy & Grails Views and Layouts <html> <head> <meta name="layout" content="main" /> <title>Book List</title> </head> <body> <div class="nav"> <span><a class="home" href="${createLink(uri: '/')}">Home</a></span> <span><g:link class="create" action="create">New Book</g:link></span> </div> <div class="body"> <div class="list"> <table> <g:each in="${bookInstanceList}" status="i" var="bookInstance"> <tr class="${(i % 2) == 0 ? 'odd' : 'even'}"> <td><g:link action="show" id="${bookInstance.id}">${bookInstance.id}</ g:link></td> <td>${bookInstance.title}</td> </tr> </g:each> </table> </div> </div> </body> </html> { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 78. Groovy & Grails URL Mappings Used for mapping URL’s to controllers • Similar like routes in Rails • Default convention is /controller/action/id { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 79. Groovy & Grails URL Mappings Used for mapping URL’s to controllers • Similar like routes in Rails • Default convention is /controller/action/id class UrlMappings { static mappings = { "/product" (controller: "product", action: "list") "/product/$id" (controller: "product") "/$blog/$year/$month/$day/$id" (controller: "blog", action: "show") } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 80. Groovy & Grails Filters Controllers already support fine grained interceptors but these are difficult to manage in larger applications { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 81. Groovy & Grails Filters Controllers already support fine grained interceptors but these are difficult to manage in larger applications Use filters instead • A Domain Specific Language is available for defining filters • You can define scopes (all controllers, a specific controller/action, URI pattern) • You can define interceptor types (before, after, afterView) • You can use variables (params, request, response, session, grailsApplication) { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 82. Groovy & Grails Filters Controllers already support fine grained interceptors but these are difficult to manage in larger applications Use filters instead • A Domain Specific Language is available for defining filters • You can define scopes (all controllers, a specific controller/action, URI pattern) • You can define interceptor types (before, after, afterView) • You can use variables (params, request, response, session, grailsApplication) class SecurityFilters { def filters = { loginCheck(controller: '*', action: '*') { before = { if(!session.user && !actionName.equals('login')) { redirect(action: 'login') return false } } } } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 83. Groovy & Grails Services Don’t put core/reusable logic in controllers, but instead use the service layer Services are by default transactional Services can be scoped class BookService { static scope = "singleton" // other options include prototype, request, session static transactional = true def doSomething() { // TODO: implement } } { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 84. Groovy & Grails Plugins Grails is designed with a plugin architecture in mind Grails core features are built on plugins Plugins can provide basic artifacts • Domain Classes, Tag Libraries, Services, ... Plugins can provide new artifact types Plugins can hook into build events Plugins can hook into runtime configuration Plugins can add dynamic methods at runtime { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 85. Groovy & Grails Plugins Spring Security LDAP Quartz Commentable Searchable Selenium RC Mail Fixtures Canoo Webtest ReCaptcha GWT LiquiBase Feeds GORM-JPA Taggable iWebKit Rateable Webdriver XFire Axis2 Spring WS Wicket { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 86. Groovy & Grails Tooling Integrated Development Environments • SpringSource Tool Suite (STS) • NetBeans • IDEA IntelliJ TextMate { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 87. Groovy & Grails Discussion & Demo !? { Agile Development } { Ruby on Rails } { Java / J2EE }
  • 88. { Agile Development } { Ruby on Rails } { Java / J2EE }