Groovy Grails DevJam Jam Session

Post on 10-May-2015

6.310 views 1 download

Tags:

description

Groovy is a dynamic programming language that runs on the JVM and seamlessly interacts with Java. Grails melds the concept of "Convention over Configuration" and the dynamic power of Groovy to create a framework that greatly simplifies the development of web based applications. This slideshow explores the two - dive into some Groovy vs. Java code examples and see some examples of Grails. We'll also discuss when to introduce either into an existing (or greenfield) environment and where they have worked and where they have failed

Transcript of Groovy Grails DevJam Jam Session

Groovy/Grails DevJam

Act I

“When you program in Groovy, in many waysyou’re writing a special kind of Java.”

-Dierk KönigGroovy in Action

.java .groovy

hugobook:groovy mjhugo$ groovycusage: groovyc [options] <source-files>

options:

--encoding <encoding> Specify the encoding of the user class files.

-F <flag>

-J <property=value>

-d Specify where to place generated class files.

-e,--exception Print stack trace on error.

-h,--help Print a synopsis of standard options.

-j,--jointCompilation Attach javac compiler to compile .java files. -v,--version Print the version.

20%

80%

getters and setters

1 package com.piragua.java;

2

3 public class SimpleBook {

4 private String title;

5 private String authorName;

6

7 public String getTitle() {

8 return title;

9 }

10

11 public void setTitle(String title) {

12 this.title = title;

13 }

14

15 public String getAuthorName() {

16 return authorName;

17 }

18

19 public void setAuthorName(String authorName) {

20 this.authorName = authorName;

21 }

22 }

1 package com.piragua.groovy

2

3 class SimpleBook {

4 String title

5 String authorName

6 }

javap -private SimpleBook

Compiled from "SimpleBook.groovy"

public class com.piragua.groovy.SimpleBook ... {

private java.lang.String title;

private java.lang.String author;

public java.lang.String getTitle(); public void setTitle(java.lang.String);

public java.lang.String getAuthor(); public void setAuthor(java.lang.String);

...

}

javap -private SimpleBook

Compiled from "SimpleBook.groovy"

public class com.piragua.groovy.SimpleBook ... {

private java.lang.String title; private java.lang.String author;

public java.lang.String getTitle(); public void setTitle(java.lang.String);

public java.lang.String getAuthor(); public void setAuthor(java.lang.String);

...

}

1 package com.piragua.java;

2

3 import java.util.Date;

4 import java.util.List;

5

6 public class Book {

7 private String title;

8 private String authorName;

9 private Integer numberOfPages;

10 private String subTitle;

11 private List<Chapter> chapters;

12 private Date publishDate;

13 private String publisher;

14

15 public String getPublisher() {

16 return publisher;

17 }

18

19 public void setPublisher(String publisher) {

20 this.publisher = publisher;

21 }

22

23 public Date getPublishDate() {

24 return publishDate;

25 }

26

27 public void setPublishDate(Date publishDate) {

28 this.publishDate = publishDate;

29 }

30

31 public List getChapters() {

32 return chapters;

33 }

34

35 public void setChapters(List chapters) {

36 this.chapters = chapters;

37 }

38

39 public String getTitle() {

40 return title;

41 }

42

43 public void setTitle(String title) {

44 this.title = title;

45 }

46

47 public String getAuthorName() {

48 return authorName;

49 }

50

51 public void setAuthorName(String authorName) {

52 this.authorName = authorName;

53 }

54

55 public Integer getNumberOfPages() {

56 return numberOfPages;

57 }

58

59 public void setNumberOfPages(Integer numberOfPages) {

60 this.numberOfPages = numberOfPages;

61 }

62

63 public String getSubTitle() {

64 return subTitle;

65 }

66

67 public void setSubTitle(String subTitle) {

68 this.subTitle = subTitle;

69 }

70

71 public String toString() {

72 String upperCaseTitle = null;

73 if (title != null) {

74 upperCaseTitle = title.toUpperCase();

75 }

76 return upperCaseTitle;

77 }

78

79 public String displayString() {

80 return "<u>" + title + "</u> by " + authorName + ", (" + numberOfPages + " pages)";

81 }

82

83 public Chapter findChapterByTitle(String chapterTitle) {

84 Chapter foundChapter = null;

85

86 if (chapterTitle != null && chapters != null) {

87 for (int i = 0; i < chapters.size(); i++) {

88 if (chapters.get(i) != null &&

89 chapterTitle.equals(chapters.get(i).getTitle())) {

90 foundChapter = chapters.get(i);

91 break;

92 }

93 }

94 }

95 return foundChapter;

96 }

97 }

1 package com.piragua.groovy

2

3 class Book {

4 String title

5 String authorName

6 Integer numberOfPages

7 String subTitle

8 List chapters

9 Date publishDate

10 String publisher

11

12 String toString() {

13 title?.toUpperCase()

14 }

15

16 String displayString() {

17 "<u>${title}</u> by ${authorName}, (${numberOfPages} pages)"

18 }

19

20 Chapter findChapterByTitle(String title) {

21 // finding the first item that matches criteria

22 chapters?.find({it?.title == title})

23 }

24 }

constructor convenience

http://flickr.com/photos/9229859@N02/1052409181/

1 package com.piragua.java;

2

3 import junit.framework.TestCase;

4

5 import java.util.ArrayList;

6 import java.util.Date;

7

8 public class BookTest extends TestCase {

9 Book book;

10 Chapter chapter;

11

12 public void setUp() {

13 book = new Book();

14 book.setNumberOfPages(300);

15 book.setAuthorName("Mike Hugo");

16 book.setTitle("Groovy Jam");

17 book.setSubTitle("Jammin");

18 book.setPublisher("Piragua Press");

19 book.setPublishDate(new Date());

20 }

1 package com.piragua.groovy

2

3 public class BookTest extends GroovyTestCase {

4 Book book

5 Chapter grails, groovy, why

6

7 void setUp() {

8 book = new Book(title: "Groovy Jam", subTitle:"Jammin",

9 authorName: "Mike Hugo", numberOfPages: 300,

10 publishDate:new Date(), publisher: "Piragua Press")

11 }

null safe dereferencing

http://flickr.com/photos/synthesisstudios/352834727/

32 public String toString() {

33 String upperCaseTitle = null;

34 if (title != null){

35 upperCaseTitle = title.toUpperCase();

36 }

37 return upperCaseTitle;

38 }

String toString(){

title?.toUpperCase()

}

// more complex

String toString(){

book?.publisher?.address?.city?.toUpperCase()

}

groovy strings

http://flickr.com/photos/austinevan/416813459/

// Java Example

public String displayString() {

return "<u>" + title + "</u> by " +

authorName + ", (" +

numberOfPages + " pages)";

}

// Java Example

public String displayString() {

return "<u>" + title + "</u> by " +

authorName + ", (" +

numberOfPages + " pages)";

}

String displayString() {

"<u>${title}</u> by ${authorName}, (${numberOfPages} pages)"

}

String multiLineDisplayString() {

"""<u>${title}</u>

by ${authorName}

(${numberOfPages} pages)"""

}

collections

http://flickr.com/photos/stibbons/375342559/

11 private List<Chapter> chapters;

//...

55 public Chapter findChapterByTitle(String chapterTitle) {

56 Chapter foundChapter = null;

57

58 if (chapterTitle != null && chapters != null) {

59 for (int i = 0; i < chapters.size(); i++) {

60 if (chapters.get(i) != null &&

61 chapterTitle.equals(chapters.get(i).getTitle())) {

62 foundChapter = chapters.get(i);

63 break;

64 }

65 }

66 }

67 return foundChapter;

68 }

11 private List<Chapter> chapters;

//...

55 public Chapter findChapterByTitle(String chapterTitle) {

56 Chapter foundChapter = null;

57

58 if (chapterTitle != null && chapters != null) {

59 for (int i = 0; i < chapters.size(); i++) {

60 if (chapters.get(i) != null &&

61 chapterTitle.equals(chapters.get(i).getTitle())) {

62 foundChapter = chapters.get(i);

63 break;

64 }

65 }

66 }

67 return foundChapter;

68 }

8 List chapters

//...

17 Chapter findChapterByTitle(String title) {

18 // finding the first item that matches criteria

19 chapters?.find({it?.title == title})

20 }

8 List chapters

//...

22 List findChaptersByTitleStartingWith(String searchKeyword) {

23 // finding all matching items

24 chapters?.findAll({it?.title?.startsWith(searchKeyword)})

25 }

8 List chapters

//...

27 void printChapterTitles() {

28 // iterating over a list

29 chapters.each {chapter ->

30 println chapter?.title

31 }

32 }

duck typing

http://flickr.com/photos/davidw/380277419/

1 package com.piragua.java;

2

3 import javax.servlet.ServletException;

4 import javax.servlet.http.*;

5 import java.io.IOException;

6

7 public class MyServlet extends HttpServlet {

8

9 @Override

10 protected void doPost(HttpServletRequest request,

11 HttpServletResponse response)

12 throws ServletException, IOException {

13

14 String username = request.getParameter("username");

15 if (username != null) {

16 HttpSession session = request.getSession(true);

17 session.setAttribute("loggedInUser", username);

18 }

19

20 }

21 }

22

1 package com.piragua.groovy

2

3 import javax.servlet.http.*

4 import com.piragua.java.MyServlet

5

6 public class MyServletTest extends GroovyTestCase {

7

8 Map params

9 Map session

10

11 def request

12

13 protected void setUp() {

14 params = [:]

15 session = [:]

16 def mockSession = [setAttribute: {k, v -> session[k] = v }]

17

18 request = [

19 getParameter: {param -> return params[param]},

20 getSession: {createNew -> return mockSession as HttpSession}]

21 }

23 void testDoGetFoundUser() {

24 params.username = 'mike'

25 new MyServlet().doPost(request as HttpServletRequest,

26 [:] as HttpServletResponse)

27 assertEquals(params.username, session.loggedInUser)

28 }

29

30 void testDoGetNoUser() {

31 params.username = null

32 new MyServlet().doPost(request as HttpServletRequest,

33 [:] as HttpServletResponse)

34 assertNull(session.loggedInUser)

35 }

If we had more time...• file handling

• really easy regular expressions

• groovy truth

• case / switch

• closures

• meta programming

http://groovy.codehaus.org/ http://groovy.mn/

Act II

Web MVC Framework

convention

http://flickr.com/photos/markpasc/92779595

configuration

http://flickr.com/photos/clintjcl/169886338

DRY

http://flickr.com/photos/joshsommers/935470210/

Development

Deployment

http://flickr.com/photos/ragesoss/118620722/

Artifacts

http://flickr.com/photos/ragesoss/118620722/

Artefacts

grails create-app devjam

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

Zero

Customer

Address

class Customer {

! Address address

}

IncidentCustomer

class Customer {

! static hasMany = [incidents:Incident]

}

ProductCustomerCustomer

Product

class Customer {

! static hasMany = [products:Product]

}

class Product {

static hasMany = [customers:Customer]

static belongsTo = Customer //Customer owns the relationship

}

http://server/devjam/event/list

name of application

http://server/devjam/event/list

name of controller

http://server/devjam/event/list

name of action

http://server/devjam/event/list?max=10

Data Binding

Dependency Injection

Demo

If we had more time...• testing

• tag libraries

• services

• plugins

• content negotiation

http://grails.org http://grails.org/doc/1.0.x/

Act III

http://flickr.com/photos/johnniewalker/359440369

http://flickr.com/photos/philliecasablanca/2473728872

0

25

50

75

100

Learning Curve

* data for this chart is completely fabricated

0

25

50

75

100

Learning Curve

* data for this chart is completely fabricated

http://flickr.com/photos/13010608@N02/2441101135/

+ +

http://flickr.com/photos/kevint/85911467

1 package com.piragua.groovy

2

3 import javax.servlet.http.*

4 import com.piragua.java.MyServlet

5

6 class MyServletTest extends GroovyTestCase {

7

8 Map params

9 Map session

10

11 def request

12

13 protected void setUp() {

14 params = [:]

15 session = [:]

16 def mockSession = [setAttribute: {k, v -> session[k] = v }]

http://flickr.com/photos/nengard/82039595

200,000 users

1 Million page views/month

$250/monthVPS

http://flickr.com/photos/oxygenws/39895404

XYZ Thing

http://flickr.com/photos/thatblondegirl/467513888

Thank You

Groovy/Grails DevJam

https://duke.dev.java.net/images/guitar/DukeAsKeith-daylight.pnghttp://svn.codehaus.org/groovy/trunk/groovy/groovy-core/cruise/reporting-app/images/DukeGroovyChair.jpg

3 things to talk about tonight:-Brief overview of Groovy-High level Grails (and Live Coding!)-Thumbs up and Thumbs Down:! -When should you choose to use Groovy/Grails in existing or greenfield project! -Where it has worked (and why) and where it has failed (and why)

Act I

What is Groovy? - ask the audience...possible answers:- answers.com: “Very pleasing; wonderful.”- agile language- scripting language for the JVM- dynamically typed language- build tool- runtime tool for the JVM- high level language for the JVM that compiles to byte code- open source java language- language to make unit testing easier for Java applications

“When you program in Groovy, in many waysyou’re writing a special kind of Java.”

-Dierk KönigGroovy in Action

Groovy is all of those things, but most of all I like this definition. What is Groovy? - answer by Dierk König, Groovy committer and author of “Groovy in Action”- dynamic language for the JVM

.java .groovy

In fact, most of the time you can take .java file and rename it .groovy and it will compile and run

Groovy and Java work seamlessly together

-your java classes can reference groovy classes and groovy classes can reference java classes

hugobook:groovy mjhugo$ groovycusage: groovyc [options] <source-files>

options:

--encoding <encoding> Specify the encoding of the user class files.

-F <flag>

-J <property=value>

-d Specify where to place generated class files.

-e,--exception Print stack trace on error.

-h,--help Print a synopsis of standard options.

-j,--jointCompilation Attach javac compiler to compile .java files. -v,--version Print the version.

This is because of something unique to groovy - the Groovy Joint Compiler - you can compile .groovy and .java files at the same time allowing that seamless interaction

What this means is if you’re already using Java, it works with everything you already have - IDEs- Open Source Frameworks- Application Servers, etc.

20%

80%

For me, it comes down to the 80/20 rule. Groovy gives me the ability to write concise code that"s straight to the point of what I"m trying to do. I don"t have to include “ceremony” - code that doesn"t relate to the task at hand (Stuart Halloway, http://blog.thinkrelevance.com/2008/4/1/ending-legacy-code-in-our-lifetime) and can focus directly on the goal my code is trying to achieve.

Examples...

getters and setters

Getters and Setters ExampleStandard stuff - create some properties and have your IDE of choice generate the getters and settersbut WHY generate them? they add so much noise to your code...

1 package com.piragua.java;

2

3 public class SimpleBook {

4 private String title;

5 private String authorName;

6

7 public String getTitle() {

8 return title;

9 }

10

11 public void setTitle(String title) {

12 this.title = title;

13 }

14

15 public String getAuthorName() {

16 return authorName;

17 }

18

19 public void setAuthorName(String authorName) {

20 this.authorName = authorName;

21 }

22 }

Java example: two properties, 15 lines of code for getters/setters

Now, let"s look at the same class in Groovy...

1 package com.piragua.groovy

2

3 class SimpleBook {

4 String title

5 String authorName

6 }

Same class, 0 lines of code for getters/setters

Also notice that the attributes and the class are not scoped - that"s because Groovy provides sensible defaults for these -

Lets take a look at a snippet of the byte code as shown by javap

javap -private SimpleBook

Compiled from "SimpleBook.groovy"

public class com.piragua.groovy.SimpleBook ... {

private java.lang.String title;

private java.lang.String author;

public java.lang.String getTitle(); public void setTitle(java.lang.String);

public java.lang.String getAuthor(); public void setAuthor(java.lang.String);

...

}

- getters and setters are provided automatically! - You can add your own getters and setters to define custom behavior - but how often do you really do this?

javap -private SimpleBook

Compiled from "SimpleBook.groovy"

public class com.piragua.groovy.SimpleBook ... {

private java.lang.String title; private java.lang.String author;

public java.lang.String getTitle(); public void setTitle(java.lang.String);

public java.lang.String getAuthor(); public void setAuthor(java.lang.String);

...

}

- no need to define class as public - that"s the default- attributes are private by default- methods are public by default

1 package com.piragua.java;

2

3 import java.util.Date;

4 import java.util.List;

5

6 public class Book {

7 private String title;

8 private String authorName;

9 private Integer numberOfPages;

10 private String subTitle;

11 private List<Chapter> chapters;

12 private Date publishDate;

13 private String publisher;

14

15 public String getPublisher() {

16 return publisher;

17 }

18

19 public void setPublisher(String publisher) {

20 this.publisher = publisher;

21 }

22

23 public Date getPublishDate() {

24 return publishDate;

25 }

26

27 public void setPublishDate(Date publishDate) {

28 this.publishDate = publishDate;

29 }

30

31 public List getChapters() {

32 return chapters;

33 }

34

35 public void setChapters(List chapters) {

36 this.chapters = chapters;

37 }

38

39 public String getTitle() {

40 return title;

41 }

42

43 public void setTitle(String title) {

44 this.title = title;

45 }

46

47 public String getAuthorName() {

48 return authorName;

49 }

50

51 public void setAuthorName(String authorName) {

52 this.authorName = authorName;

53 }

54

55 public Integer getNumberOfPages() {

56 return numberOfPages;

57 }

58

59 public void setNumberOfPages(Integer numberOfPages) {

60 this.numberOfPages = numberOfPages;

61 }

62

63 public String getSubTitle() {

64 return subTitle;

65 }

66

67 public void setSubTitle(String subTitle) {

68 this.subTitle = subTitle;

69 }

70

71 public String toString() {

72 String upperCaseTitle = null;

73 if (title != null) {

74 upperCaseTitle = title.toUpperCase();

75 }

76 return upperCaseTitle;

77 }

78

79 public String displayString() {

80 return "<u>" + title + "</u> by " + authorName + ", (" + numberOfPages + " pages)";

81 }

82

83 public Chapter findChapterByTitle(String chapterTitle) {

84 Chapter foundChapter = null;

85

86 if (chapterTitle != null && chapters != null) {

87 for (int i = 0; i < chapters.size(); i++) {

88 if (chapters.get(i) != null &&

89 chapterTitle.equals(chapters.get(i).getTitle())) {

90 foundChapter = chapters.get(i);

91 break;

92 }

93 }

94 }

95 return foundChapter;

96 }

97 }

1 package com.piragua.groovy

2

3 class Book {

4 String title

5 String authorName

6 Integer numberOfPages

7 String subTitle

8 List chapters

9 Date publishDate

10 String publisher

11

12 String toString() {

13 title?.toUpperCase()

14 }

15

16 String displayString() {

17 "<u>${title}</u> by ${authorName}, (${numberOfPages} pages)"

18 }

19

20 Chapter findChapterByTitle(String title) {

21 // finding the first item that matches criteria

22 chapters?.find({it?.title == title})

23 }

24 }

This is the same class - on the left is Java (97 lines of code), on the right is Groovy (24 lines of code).6 pt font Each class has 7 attributes and three methods.

When you go to maintain the Book class, which file would you rather work with?

constructor convenience

http://flickr.com/photos/9229859@N02/1052409181/

1 package com.piragua.java;

2

3 import junit.framework.TestCase;

4

5 import java.util.ArrayList;

6 import java.util.Date;

7

8 public class BookTest extends TestCase {

9 Book book;

10 Chapter chapter;

11

12 public void setUp() {

13 book = new Book();

14 book.setNumberOfPages(300);

15 book.setAuthorName("Mike Hugo");

16 book.setTitle("Groovy Jam");

17 book.setSubTitle("Jammin");

18 book.setPublisher("Piragua Press");

19 book.setPublishDate(new Date());

20 }

Constructor ShortcutHappens all the time in unit testing, but also sometimes in real code for setting defaultsNew up an object, then call all the setters to populate some values

1 package com.piragua.groovy

2

3 public class BookTest extends GroovyTestCase {

4 Book book

5 Chapter grails, groovy, why

6

7 void setUp() {

8 book = new Book(title: "Groovy Jam", subTitle:"Jammin",

9 authorName: "Mike Hugo", numberOfPages: 300,

10 publishDate:new Date(), publisher: "Piragua Press")

11 }

In groovy, you can use named parameters in the constructor to build objects- can happen in any order- can pass all, some, or none of the attributes to the constructor- it"s descriptive - you know what"s being set because it says it right here (e.g. title: “groovy jam”)...if you created a java constructor how would you remember which order to pass the parameters?

null safe dereferencing

http://flickr.com/photos/synthesisstudios/352834727/

32 public String toString() {

33 String upperCaseTitle = null;

34 if (title != null){

35 upperCaseTitle = title.toUpperCase();

36 }

37 return upperCaseTitle;

38 }

In Java, you often have times where you check to see if something is null before performing an action on it

String toString(){

title?.toUpperCase()

}

In Groovy, you can use the ? operator to safely traverse the tree of an object graph

// more complex

String toString(){

book?.publisher?.address?.city?.toUpperCase()

}

If any of the attributes in this example are null, groovy will stop at that point and return null

groovy strings

http://flickr.com/photos/austinevan/416813459/

// Java Example

public String displayString() {

return "<u>" + title + "</u> by " +

authorName + ", (" +

numberOfPages + " pages)";

}

Yeck.

String concatenation is evilSo is using string buffer

// Java Example

public String displayString() {

return "<u>" + title + "</u> by " +

authorName + ", (" +

numberOfPages + " pages)";

}

Yeck.

String concatenation is evilSo is using string buffer

String displayString() {

"<u>${title}</u> by ${authorName}, (${numberOfPages} pages)"

}

Groovy strings allow you to construct strings using ${} notation

You can also do multi line strings

String multiLineDisplayString() {

"""<u>${title}</u>

by ${authorName}

(${numberOfPages} pages)"""

}

You can also do multi line strings

collections

http://flickr.com/photos/stibbons/375342559/

11 private List<Chapter> chapters;

//...

55 public Chapter findChapterByTitle(String chapterTitle) {

56 Chapter foundChapter = null;

57

58 if (chapterTitle != null && chapters != null) {

59 for (int i = 0; i < chapters.size(); i++) {

60 if (chapters.get(i) != null &&

61 chapterTitle.equals(chapters.get(i).getTitle())) {

62 foundChapter = chapters.get(i);

63 break;

64 }

65 }

66 }

67 return foundChapter;

68 }

Java example of finding a chapter by title

- iterate over the the list until you find the one you"re looking for, set it in a temp variable and break

11 private List<Chapter> chapters;

//...

55 public Chapter findChapterByTitle(String chapterTitle) {

56 Chapter foundChapter = null;

57

58 if (chapterTitle != null && chapters != null) {

59 for (int i = 0; i < chapters.size(); i++) {

60 if (chapters.get(i) != null &&

61 chapterTitle.equals(chapters.get(i).getTitle())) {

62 foundChapter = chapters.get(i);

63 break;

64 }

65 }

66 }

67 return foundChapter;

68 }

Java example of finding a chapter by title

- by the way, did you notice all the null checking going on that distracts from the essence of the code: finding a chapter by title

8 List chapters

//...

17 Chapter findChapterByTitle(String title) {

18 // finding the first item that matches criteria

19 chapters?.find({it?.title == title})

20 }

Groovy example

- use .find and pass a closure- closure is executed against every item in the list until a match is found

- #it" is an implicit parameter passed to a closure, can be named- == in groovy is the same as .equals()

8 List chapters

//...

22 List findChaptersByTitleStartingWith(String searchKeyword) {

23 // finding all matching items

24 chapters?.findAll({it?.title?.startsWith(searchKeyword)})

25 }

- can also use .findAll

8 List chapters

//...

27 void printChapterTitles() {

28 // iterating over a list

29 chapters.each {chapter ->

30 println chapter?.title

31 }

32 }

or .each to iterate over a collection

duck typing

http://flickr.com/photos/davidw/380277419/

http://en.wikipedia.org/wiki/Duck_typingIf it walks like a duck and quacks like a duck, I would call it a duck.

Rather than create an interface to define the contract, use behavior at runtime to determine the functionality

So now, a Java example

oh wait. you can"t do this in java. no example here.

1 package com.piragua.java;

2

3 import javax.servlet.ServletException;

4 import javax.servlet.http.*;

5 import java.io.IOException;

6

7 public class MyServlet extends HttpServlet {

8

9 @Override

10 protected void doPost(HttpServletRequest request,

11 HttpServletResponse response)

12 throws ServletException, IOException {

13

14 String username = request.getParameter("username");

15 if (username != null) {

16 HttpSession session = request.getSession(true);

17 session.setAttribute("loggedInUser", username);

18 }

19

20 }

21 }

22

Here"s an example of a Java Servlet. It takes a parameter from the request, and if it is not null, sets it in to the session.

If I wanted to test this, I would have to provide a full implementation of HttpServletRequest and HttpServletResponse just in order to call the method.

Note: Spring (and other frameworks) provide Mock implementations of HttpServletRequest and HttpServletResponse, but pretend those don"t exist for the purpose of this example

1 package com.piragua.groovy

2

3 import javax.servlet.http.*

4 import com.piragua.java.MyServlet

5

6 public class MyServletTest extends GroovyTestCase {

7

8 Map params

9 Map session

10

11 def request

12

13 protected void setUp() {

14 params = [:]

15 session = [:]

16 def mockSession = [setAttribute: {k, v -> session[k] = v }]

17

18 request = [

19 getParameter: {param -> return params[param]},

20 getSession: {createNew -> return mockSession as HttpSession}]

21 }

But using Groovy, I can utilize Duck Typing to mock out the implementation.

Line 20 has an example: “mockSession as HttpSession”

more in the tests

23 void testDoGetFoundUser() {

24 params.username = 'mike'

25 new MyServlet().doPost(request as HttpServletRequest,

26 [:] as HttpServletResponse)

27 assertEquals(params.username, session.loggedInUser)

28 }

29

30 void testDoGetNoUser() {

31 params.username = null

32 new MyServlet().doPost(request as HttpServletRequest,

33 [:] as HttpServletResponse)

34 assertNull(session.loggedInUser)

35 }

Line 25: “request as HttpServletRequest” - my map (defined in the setup method) now looks like a HttpServletRequest to the Servlet under test

Line 33: “[:] as HttpServletResponse” just acts as a non-null HttpServletResponse. How would you do this in Java? Create a class, implement the HttpServletResponse interface with a bunch of empty methods, then new it up and pass it into the doPost method. That sucks.

Now, I know duck typing is controversial. Interfaces can be a good thing, and they enforce the contract at compile time. With duck typing, you don"t have compile time checking of the contract - so testing is really important here. Regardless of your opinion, remember:

If we had more time...• file handling

• really easy regular expressions

• groovy truth

• case / switch

• closures

• meta programming

For reference in the handout:- File: Convenience methods for writing and reading files: http://docs.codehaus.org/display/GROOVY/JN2015-Files- Truth: .equals is the same as ==; 1 is true, 0 is false; null is false; empty string is false; etc. : http://docs.codehaus.org/display/GROOVY/Groovy+Truth- Regular expressions are so easy! http://naleid.com/blog/2008/05/19/dont-fear-the-regexp/- Case / Switch: can switch on any type: http://groovy.codehaus.org/Logical+Branching- Closures: named block of code. pass it around, reuse it, do all sorts of fun things: http://groovy.codehaus.org/Closures- Meta Programming: http://groovy.dzone.com/articles/metaprogramming-groovy-ii-expa , also http://naleid.com/blog/2008/05/07/what-methods-does-my-groovygrails-class-have/- See more differences from Java: http://groovy.codehaus.org/Differences+from+Java

http://groovy.codehaus.org/ http://groovy.mn/

Two resources:Groovy website @ codehaus - api, documentation, and lots of examplesGroovy Users Group of MN - meets the second Tuesday of the month in NE minneapolis

Also see this presentation by Guillaume LaForge (groovy project manager) on Groovyhttp://www.slideshare.net/glaforge/groovy-and-grails-in-action-devoxx-2008-university-guillaume-laforge-presentation

Three books:-Groovy in Action (Dierk König)-Groovy Recipies (Scott Davis)-Programming Groovy (Venkat Subramaniam)

http://www.amazon.com/Groovy-Action-Dierk-Koenig/dp/1932394842http://www.amazon.com/Groovy-Recipes-Greasing-Pragmatic-Programmers/dp/0978739299/

Act II

So now, on to Grails...What is Grails?

Web MVC Framework

Grails is a Web Model/View/Controller framework

that leverages the power of Groovy, Hibernate, Spring and Java

convention

http://flickr.com/photos/markpasc/92779595

With it you can do rapid application development by using the concepts of Convention...

configuration

http://flickr.com/photos/clintjcl/169886338

instead of configuration (AKA convention over configuration)

DRY

http://flickr.com/photos/joshsommers/935470210/

And “Don’t Repeat Yourself” Why add all sorts of ceremony to your code in configuration when it could be implied?

Development

Grails provides a full *development* environment out of the box including an:- in-memory HSQL DB- Jetty application server- Automatic reloading of most artifacts

But you’re not limited to that in Development or even in Production -

Deployment

Jetty and HSQLDB are just the defaults -You can deploy a grails application on any application server that can handle a WAR fileand any database that has a JDBC driver

But I’m getting ahead of myself...let’s get started with some Grails basics

http://flickr.com/photos/ragesoss/118620722/

Artifacts

Artifacts. or, if you’re british

http://flickr.com/photos/ragesoss/118620722/

Artefacts

A lot of the core contributors to Grails are in the UK, so you sometimes run into this (in the Grails code base)

grails create-app devjam

Every Grails Application has a common structureUnderneath the ‘grails-app’ directory there are sub-directories for “special” grails artifacts.Let’s look at a few

The domain subdirectory is for any class that you want to be persistent. These classes are automatically mapped to the DB through Hibernate

Grails will automatically create your database tables based on your domain classes using Hibernate’s hbm2ddlThere are other ways to manage DB migrations, this is just the default

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

! - the domain class name becomes the table name

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

! - attribute names are converted into column names

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

- id (PK) and version (optimistic locking) columns are added to DB, but don’t need to be explicitly specified in code

all of these defaults can be overridden through a mapping DSL or through explicit Hibernate configuration

The next couple examples are screen shots of the “Grails Console” - an interactive Swing console that is wired up with hibernate and all your spring beans and everything

Not only are the domain classes automatically mapped to the DB, Grails adds persistent methods like

.save() - inserts or updates an object

.get(id)

pass in the ID of a persistent object and hibernate will retrieve it

.list()

select * from table

and last but not least, dynamic finders like “findByTitle”

and you can even add criteria like ‘EventDateLessThan’

how about a query using case insensitive ‘like’?

or a query using HQL?

or a query using criteria?

Zero

All of this with: Zero - the amount of configuration and DAO lines of code you have to do to perform crud on a domain class.

Customer

Address

class Customer {

! Address address

}

Associations are also supported - you can have - one to one

IncidentCustomer

class Customer {

! static hasMany = [incidents:Incident]

}

- one to many

ProductCustomerCustomer

Product

class Customer {

! static hasMany = [products:Product]

}

class Product {

static hasMany = [customers:Customer]

static belongsTo = Customer //Customer owns the relationship

}

- many to many

Controllers are servlets in the Grails world. Any groovy class in this directory will have a url mapping by convention - no xml config required:

http://server/devjam/event/list

name of application

The context root of your app is the name of the application, in this case “devjam”

http://server/devjam/event/list

name of controller

The next part of a URL is the name of the controller

http://server/devjam/event/list

name of action

and the final part is the name of the action (which is a closure defined in the controller)

These are the defaults - you can change URL mappings to your liking

http://server/devjam/event/list?max=10

Grails puts all the parameters coming in to a controller in to a map called ‘params’ - you can access them using ‘dot’ notation (like ‘params dot max’ to get the ‘max’ parameter)

Data Binding

This is also fantastic for data binding - on a new object you can pass the ‘params’ map straight to a object constructor (thank you Groovy constructor convenience)

Dependency Injection

Grails artifacts like controllers and services are created as spring beans - and grails autowires beans together by name.

In the case, AuthenticateService will automatically be injected into the EventController - no config needed

Views are GSP (grails server pages) instead of JSPs

you can reference anything that is in the ‘model’ with ${} notation (like eventInstance)

there’s a convention for where the views go - by default views for the “EventController” go in the “views/event” subdirectory

Grails uses SiteMesh to decorate pages - so your GSPs are simple HTML

that have a layout applied to them

Demo

Demo - build a simple Grails app to -list events (demo sca"olding)-create a new event (demo domain constraints)-allow users to RSVP to them (demo reloading of controller and dependency injection)-create RSS feed of events list (install and use feeds plugin)

If we had more time...• testing

• tag libraries

• services

• plugins

• content negotiation

For reference in the handout:Testing: http://www.grails.org/Testing+PluginTag Libraries: http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html#6.3%20Tag%20LibrariesServices: http://grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.htmlPlugins: http://grails.org/PluginsContent Negotiation: http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html#6.8%20Content%20Negotiation

http://grails.org http://grails.org/doc/1.0.x/

Two resources:Grails.org website - great starting point - and a grails app itselfGrails reference guide - excellent documentation of Grails

Two excellent books coming out very soon (early editions available from publisher now)

GIA (May?): http://www.amazon.com/Grails-Action-Glen-Smith/dp/1933988932/DGG (Jan): http://www.amazon.com/Definitive-Guide-Grails-Second/dp/1590599950

Act III

Act III: - when should you consider using these tools in an existing environment? - greenfield environment?- Where have they worked and where haven"t they?

When should you consider using these tools in an existing environment?

The first question I ask is “Are you already a Java shop?”

http://flickr.com/photos/johnniewalker/359440369

If you are - then you already have the infrastructure you need to build and deploy applications with Groovy/Grails...

http://flickr.com/photos/philliecasablanca/2473728872

And you also have resources that understand Java

If your company/client is open source friendly

Then bringing Groovy into your existing environment is a piece of cake.

0

25

50

75

100

Learning Curve

* data for this chart is completely fabricated

The learning curve for a new language might look like this

0

25

50

75

100

Learning Curve

* data for this chart is completely fabricated

With Groovy, your Java developers will have a jump start on learning the language -the syntax is basically the same-all the Java APIs are available to you-can immediately be productive with the language and conveniences it provides

Integrating Grails into an existing environment may not be quite as easy

If you’re already using Hibernate for the ORM layer, then it’s possible. You can take your existing database, existing hibernate mapping files and Java domain classes and take advantage of all the features Grails has to o"er.

(See “Grails In Action” book for using Grails to map the “Legacy Database from Hell”)

http://flickr.com/photos/13010608@N02/2441101135/

But where Grails really excels is in a green field

+ +

-If your team is familiar with Hibernate and Spring-Your process includes iterative development and a fast feedback loop -And testing is important

Then you should seriously be considering Grails for your next project

http://flickr.com/photos/kevint/85911467

Where has it worked?

1 package com.piragua.groovy

2

3 import javax.servlet.http.*

4 import com.piragua.java.MyServlet

5

6 class MyServletTest extends GroovyTestCase {

7

8 Map params

9 Map session

10

11 def request

12

13 protected void setUp() {

14 params = [:]

15 session = [:]

16 def mockSession = [setAttribute: {k, v -> session[k] = v }]

Unit Testing is a great way to start integrating Groovy into your code base- collections / xml / file convenience features reduce the amount of ceremony in your tests- can make mocking is easier (as shown in earlier groovy slides)

http://flickr.com/photos/nengard/82039595

“internal” apps are a great place for Grails - it’s very easy to develop a fully functional web app very quickly

I built one at my last client in 12 hours (full user login, search, audit history and workflow task management)

There are tons of success stories for Grails (http://grails.org/Success+Stories)Some very large, some smaller.

200,000 users

1 Million page views/month

$250/monthVPS

Like this example - this Brazilian Entertainment website has 200k users, 1 million page views per month and runs on a $250/month VPS - no load balancing or major performance tuning

Feb 2008reference: http://www.nabble.com/Grails-1.0.1-is-out-td15548113.html

Linked in uses Grails for some of its sites for corporate customers

http://blog.linkedin.com/2008/06/11/grails-at-linkedin/

Hot o" the press - a full case study is coming soon!wired.com/reviews is Grails powered and more of Wired.com is moving to Grails soon

http://flickr.com/photos/oxygenws/39895404

Where has it failed?

I have seen projects run into trouble when they don’t test enough. The dynamic nature of Groovy/Grails means that the compiler won’t find certain errors - you need good testing to mitigate this

XYZ Thing

Too far outside the box

For instance - one project that didn’t use the conventions that GORM provides and tried to roll their own persistence mechanism didn’t go so well.

I hope you"ve enjoyed the overview of Groovy/Grails and some thoughts to consider when choosing them

http://flickr.com/photos/thatblondegirl/467513888

Obviously, I’m drinking the Koolaid

But I’ve also been working with Groovy and Grails for almost 2 years and I’m still a happy camper.

I encourage you to go download Groovy or download Grails and walk through the “Getting Started” tutorials - and see how these new tools can help you be more e"ective

Thank You