+ All Categories
Home > Entertainment & Humor > Gg Code Mash2009 20090106

Gg Code Mash2009 20090106

Date post: 25-May-2015
Category:
Upload: jim-shingler
View: 34,495 times
Download: 1 times
Share this document with a friend
Description:
CodeMash 2009 Groovy and Grails Precompile Presentations by Chris Judd and Jim Shingler
Popular Tags:
256
Chris Judd & Jim Shingler CodeMash 2009 Percompile &
Transcript
Page 1: Gg Code Mash2009 20090106

Chris Judd & Jim Shingler

CodeMash 2009 Percompile

&

Page 2: Gg Code Mash2009 20090106

Christopher JuddPresident/Consultant of

leader

Creator of open source projects FallME and Fiddle

Page 3: Gg Code Mash2009 20090106

Jim ShinglerChief Technical Architect

President of Genuine Solutions

Co-Creator Open Source Project of FallME

Co-Author of Beginning Groovy and Grails

Page 4: Gg Code Mash2009 20090106

Goal:Gain enough Groovy and Grails knowledge to be able to build a modest Grails applications.

Install Groovy and GrailsCreate and Run Groovy ScriptsUnderstand basic Groovy Language FeaturesCreate a Scaffolded Web ApplicationApply a Custom Layout and StylingInstall and use PluginsEnable Security

Page 5: Gg Code Mash2009 20090106

Example Codehttp://github.com/jshingler/codemash2009precompile/tree/master

Page 6: Gg Code Mash2009 20090106

Software Used• JDK 1.5 >

• Eclipse 3.4

• Groovy plug-in

• Groovy 1.5.7

• Grails 1.0.4

• Plug-ins

• feeds 1.4

• searchable 0.5.1

• jsecurity 0.4-SNAPSHOT

Plus:• Slides• Example Code• Example Resources

Page 7: Gg Code Mash2009 20090106

Java Platform

Page 8: Gg Code Mash2009 20090106

What is Java?

Page 9: Gg Code Mash2009 20090106

What is Java?

Page 10: Gg Code Mash2009 20090106

What is Java?

Virtual Machine

Page 11: Gg Code Mash2009 20090106

What is Java?

Virtual Machine

API/Library

Page 12: Gg Code Mash2009 20090106

What is Java?

Virtual Machine

API/Library

Java Language

Page 13: Gg Code Mash2009 20090106

What is Java?

Virtual Machine

API/Library

Java LanguageJavaScript

Page 14: Gg Code Mash2009 20090106

What is Java?

Virtual Machine

API/Library

Java LanguageJavaScript Groovy

Page 15: Gg Code Mash2009 20090106

What is Java?

Virtual Machine

API/Library

Java LanguageJavaScript Groovy Ruby

Page 16: Gg Code Mash2009 20090106

What is Java?

Virtual Machine

API/Library

Java LanguageJavaScript Groovy Ruby Python

Page 17: Gg Code Mash2009 20090106

Language Stack

Page 18: Gg Code Mash2009 20090106

Java Language

Language Stack

System (static)

Page 19: Gg Code Mash2009 20090106

Java Language

Language Stack

Groovy

System (static)

Application (Dynamic)

Page 20: Gg Code Mash2009 20090106

Java Language

Language Stack

Groovy

Domain Specific Languages

System (static)

Application (Dynamic)

Domain

Page 21: Gg Code Mash2009 20090106

Groovy By Example

Page 22: Gg Code Mash2009 20090106

import java.util.ArrayList;import java.util.List;

public class Student {

private String firstName; private String lastName; public Student(String firstName, String lastName) { super(); this.firstName = firstName; this.lastName = lastName; }

public String getFirstName() { return firstName; }

public void setFirstName(String firstName) { this.firstName = firstName; }

public String getLastName() { return lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

public static void main(String[] args) { List<Student> students = new ArrayList<Student>(); students.add(new Student("Chris", "Judd")); students.add(new Student("Jim", "Shingler")); students.add(new Student("Joseph", "Nusairat")); System.out.println("Students:"); for (Student student : students) { System.out.println(student.getLastName() + ", " + student.getFirstName()); } }}

javac -d classes src\main\java\com\juddsolutions\groovy\basics\Student.java

java -cp classes com.juddsolutions.groovy.basics.Student

Student.class

Students:Judd, ChrisShingler, JimNusairat, Joseph

Java Example

Page 23: Gg Code Mash2009 20090106

import java.util.ArrayList;import java.util.List;

public class Student {

private String firstName; private String lastName; public Student(String firstName, String lastName) { super(); this.firstName = firstName; this.lastName = lastName; }

public String getFirstName() { return firstName; }

public void setFirstName(String firstName) { this.firstName = firstName; }

public String getLastName() { return lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

public static void main(String[] args) { List<Student> students = new ArrayList<Student>(); students.add(new Student("Chris", "Judd")); students.add(new Student("Jim", "Shingler")); students.add(new Student("Joseph", "Nusairat")); System.out.println("Students:"); for (Students student : students) { System.out.println(student.getLastName() + ", " + student.getFirstName()); } }}

Rename to Students.groovy

groovy src\main\java\com\juddsolutions\groovy\basics\Students.groovy

Students:Judd, ChrisShingler, JimNusairat, Joseph

Page 24: Gg Code Mash2009 20090106

Congratulationsyou are a

programmer

Page 25: Gg Code Mash2009 20090106

Christopher M. Judd

President, Consultant, Author685 Farrington Drive

Worthington, Ohio 43085Phone: (614) 378-4119

Email: [email protected]

SUMMARY

Chris has 12 years of professional experience in object-oriented, web and mobile technologies as well as technical education and leadership. He has experience with all phases of the software development life-cycle, including requirements, analysis, architecture and design, implementation, testing, performance tuning, support, training and project leadership. In addition, he has provided technical instruction to thousands of information technology professionals though instructor led training, mentoring, conferences, user group meetings and co-authoring “Beginning Groovy and Grails”, “Enterprise Java Development on a Budget” and “Pro Eclipse JST”. He has provided services to a diverse group of industries including manufacturing, transportation, government, insurance, publishing, retail, content management, entertainment, service, and technology consulting.

EXPERIENCE

Java User Group Leader! July 2002 – PresetCentral Ohio Java User Group (COJUG)

! Coordinate and advertise monthly meetings on Java related topics.

Consultant! Sept 2004 – Sept 2008Nationwide Insurance

! Assisted in developing, architecting and performance testing a service oriented architecture (SOA) for selling and servicing insurance agreements using IBM’s Insurance Application Architecture (IAA) as the canonical business model. The services coordinated and orchestrated thirty six integration points including three policy administrative systems. The services were used by three front ends that supported agents and customers on the Internet.

! Assisted in developing and architecting an implementation of IBM’s conceptual Insurance Application Architecture (IAA) framework using Rational Application Developer, WebSphere Application Server, DB2 and Rational Software Modeler for UML modeling

! Profiled and performance tested insurance framework using HP Diagnostics Software. ! Architected, Designed and Developed an IAA based product modeler build on top of the Eclipse

Platform including Eclipse Modeling Framework (EMF) and Graphical Editing Framework (GEF)! Mentored a team of developers with no Java or web development experience to build web applications

using Groovy and Grails.! Mentored a team of developers in Java, J2EE, unit testing, configuration management and agile

methodologies! Set up and administered a continuous integration build server which provides code quality and metrics

reports using ANT, Maven, Cruise Control, CVS, Subversion and other open source tools

Chief Technical O"cer! Jan 2008 – May 2008gwizMOBILE

! Assisted in developing and architecting a mobile auto trading application and advertisement tool using Groovy, Grails and J2ME.

Consultant! June 2003 – Sept 2004CINTAS

! Mentored a team of 4 developers with almost no Java experience to become productive J2EE developers! Archited and developed a multi-tier reusable service based J2EE application using JBuilder, WebLogic,

Struts, Together and SQL Server for a new document management line of business! Taught JBuilder, J2EE, StarTeam, Linux, Dreamweaver, Struts and Object-Oriented Programming

Groovy

Don’t forget to update your

resume.

Page 26: Gg Code Mash2009 20090106

Copy/Paste Compatibility

Page 27: Gg Code Mash2009 20090106

idiomatic

Page 28: Gg Code Mash2009 20090106

Convert POJO to POGOimport java.util.ArrayList;import java.util.List;

public class Student {

private String firstName; private String lastName; public Student(String firstName, String lastName) { super(); this.firstName = firstName; this.lastName = lastName; }

public String getFirstName() { return firstName; }

public void setFirstName(String firstName) { this.firstName = firstName; }

public String getLastName() { return lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

public static void main(String[] args) { List<Student> students = new ArrayList<Student>(); students.add(new Student("Chris", "Judd")); students.add(new Student("Jim", "Shingler")); students.add(new Student("Joseph", "Nusairat")); System.out.println("Students:"); for (Students student : students) { System.out.println(student.getLastName() + ", " + student.getFirstName()); } }}

Remove visibility modifiers (default is public)

Remove constructor

Remove accessors and mutators

Use named parameter constructor

Use properties

Page 29: Gg Code Mash2009 20090106

Convert POJO to POGO

package com.juddsolutions.groovy.basics;

import java.util.ArrayList;import java.util.List;

public class Student {

String firstName; String lastName;

public static void main(String[] args) { List<Student> students = new ArrayList<Student>(); students.add(new Student(firstName:"Chris", lastName:"Judd")); students.add(new Student(firstName:"Jim", lastName:"Shingler")); students.add(new Student(firstName:"Joseph", lastName:"Nusairat")); System.out.println("Students:"); for (Students student : students) { System.out.println(student.lastName + ", " + student.firstName); } }}

Remove visibility modifiers (default is public)Remove constructorRemove accessors and mutators

Use named parameter constructor

Use properties

Page 30: Gg Code Mash2009 20090106

Simplify Code

package com.juddsolutions.groovy.basics;

import java.util.ArrayList;import java.util.List;

public class Student {

String firstName; String lastName;

public static void main(String[] args) { List<Student> students = new ArrayList<Student>(); students.add(new Student(firstName:"Chris", lastName:"Judd")); students.add(new Student(firstName:"Jim", lastName:"Shingler")); students.add(new Student(firstName:"Joseph", lastName:"Nusairat")); System.out.println("Students:"); for (Students student : students) { System.out.println(student.lastName + ", " + student.firstName); } }}

java.util.*, java.net.*, java.io.* as well as groovy.lang.* and groovy.util.* are implicitly

imported

Typing variables is optional

Semicolons and parenthesis are optional

Convenience methodsFlexible Strings

Page 31: Gg Code Mash2009 20090106

Simplify Code

package com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

public static void main(String[] args) { def students = new ArrayList() students.add new Student(firstName:"Chris", lastName:"Judd") students.add new Student(firstName:"Jim", lastName:"Shingler") students.add new Student(firstName:"Joseph", lastName:"Nusairat") println "Students:" for (Student student : students) { println "${student.lastName}, ${student.firstName}" } }}

java.util.*, java.net.*, java.io.* as well as groovy.lang.* and groovy.util.* are implicitly

imported

Typing variables is optional

Semicolons and parenthesis are optional

Convenience methodsFlexible Strings

Page 32: Gg Code Mash2009 20090106

Collections and Closures

package com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

public static void main(String[] args) { def students = new ArrayList() students.add new Student(firstName:"Chris", lastName:"Judd") students.add new Student(firstName:"Jim", lastName:"Shingler") students.add new Student(firstName:"Joseph", lastName:"Nusairat") println "Students:" for (Student student : students) { println "${student.lastName}, ${student.firstName}" } }}

Use Groovy collection notation

Use Groovy closures for looping

Page 33: Gg Code Mash2009 20090106

Collections and Closures

package com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

public static void main(String[] args) { def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"), ] println "Students:" students.each {student -> println "${student.lastName}, ${student.firstName}" } }}

Use Groovy collection notation

Use Groovy closures for looping

Page 34: Gg Code Mash2009 20090106

Scripts

package com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

public static void main(String[] args) { def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"), ] println "Students:" students.each {student -> println "${student.lastName}, ${student.firstName}" } }}

Java’s main method is not necessary since Groovy is scriptable

Page 35: Gg Code Mash2009 20090106

Scripts

package com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

}

def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"),] println "Students:"students.each {student -> println "${student.lastName}, ${student.firstName}"}

Java’s main method is not necessary since Groovy is scriptable

Page 36: Gg Code Mash2009 20090106

VS

package com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

}

def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"),] println "Students:"students.each {student -> println "${student.lastName}, ${student.firstName}"}

import java.util.ArrayList;import java.util.List;

public class Student {

private String firstName; private String lastName; public Student(String firstName, String lastName) { super(); this.firstName = firstName; this.lastName = lastName; }

public String getFirstName() { return firstName; }

public void setFirstName(String firstName) { this.firstName = firstName; }

public String getLastName() { return lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

public static void main(String[] args) { List<Student> students = new ArrayList<Student>(); students.add(new Student("Chris", "Judd")); students.add(new Student("Jim", "Shingler")); students.add(new Student("Joseph", "Nusairat")); System.out.println("Students:"); for (Student student : students) { System.out.println(student.getLastName() + ", " + student.getFirstName()); } }}

Page 37: Gg Code Mash2009 20090106

VS

package com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

}

def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"),] println "Students:"students.each {student -> println "${student.lastName}, ${student.firstName}"}

import java.util.ArrayList;import java.util.List;

public class Student {

private String firstName; private String lastName; public Student(String firstName, String lastName) { super(); this.firstName = firstName; this.lastName = lastName; }

public String getFirstName() { return firstName; }

public void setFirstName(String firstName) { this.firstName = firstName; }

public String getLastName() { return lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

public static void main(String[] args) { List<Student> students = new ArrayList<Student>(); students.add(new Student("Chris", "Judd")); students.add(new Student("Jim", "Shingler")); students.add(new Student("Joseph", "Nusairat")); System.out.println("Students:"); for (Student student : students) { System.out.println(student.getLastName() + ", " + student.getFirstName()); } }}

Page 38: Gg Code Mash2009 20090106

Groovy Basics

Page 39: Gg Code Mash2009 20090106

What is Groovy?Groovy is an expressive, dynamic, object oriented language

built for the Java Virtual Machine (JVM) with lots of agile and modern language features.

Page 40: Gg Code Mash2009 20090106

What is Groovy?Groovy is an expressive, dynamic, object oriented language

built for the Java Virtual Machine (JVM) with lots of agile and modern language features.

Better Java

Page 41: Gg Code Mash2009 20090106

What is Groovy?Groovy is an expressive, dynamic, object oriented language

built for the Java Virtual Machine (JVM) with lots of agile and modern language features.

Java 3.0Better Java

Page 42: Gg Code Mash2009 20090106

What is Groovy?Groovy is an expressive, dynamic, object oriented language

built for the Java Virtual Machine (JVM) with lots of agile and modern language features.

Java 3.0Better Java• Properties• Closures• Optional Typing• Cool Operators• Operator Overloading

Page 43: Gg Code Mash2009 20090106

What is Groovy?Groovy is an expressive, dynamic, object oriented language

built for the Java Virtual Machine (JVM) with lots of agile and modern language features.

Java 3.0Better Java• Properties• Closures• Optional Typing• Cool Operators• Operator Overloading

• Builders • Meta-Programming• Groovy JDK• Domain Specific Languages• Unit Testing

Page 44: Gg Code Mash2009 20090106

def groovy = []groovy << javagroovy << rubygroovy << pythongroovy << smalltalkgroovy << dynamicgroovy << scriptinggroovy << agile

Page 45: Gg Code Mash2009 20090106

Groovy is Java

Page 46: Gg Code Mash2009 20090106

Groovy is Javapackage com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

}

def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"),] println "Students:"students.each {student -> println "${student.lastName}, ${student.firstName}"}

Page 47: Gg Code Mash2009 20090106

Groovy is Javapackage com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

}

def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"),] println "Students:"students.each {student -> println "${student.lastName}, ${student.firstName}"}

javap Studentgroovyc Student

Page 48: Gg Code Mash2009 20090106

Groovy is Javapackage com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

}

def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"),] println "Students:"students.each {student -> println "${student.lastName}, ${student.firstName}"}

javap Studentgroovyc Studentpublic class com.juddsolutions.groovy.basics.Student

extends java.lang.Object implements groovy.lang.GroovyObject {

public static final java.lang.Class $ownClass; public static java.lang.ref.SoftReference $staticMetaClass; transient groovy.lang.MetaClass metaClass; public static java.lang.Long __timeStamp; public static java.lang.Long __timeStamp__239_neverHappen1228887197896; public com.juddsolutions.groovy.basics.Student(); protected groovy.lang.MetaClass $getStaticMetaClass(); public groovy.lang.MetaClass getMetaClass(); public java.lang.Object invokeMethod(java.lang.String, java.lang.Object); public java.lang.Object getProperty(java.lang.String); public void setProperty(java.lang.String, java.lang.Object); static {};

public java.lang.String getFirstName(); public void setFirstName(java.lang.String); public java.lang.String getLastName(); public void setLastName(java.lang.String); public void setMetaClass(groovy.lang.MetaClass); void super$1$wait(); java.lang.String super$1$toString(); void super$1$wait(long); void super$1$wait(long, int); void super$1$notify(); void super$1$notifyAll(); java.lang.Class super$1$getClass(); boolean super$1$equals(java.lang.Object); java.lang.Object super$1$clone(); int super$1$hashCode(); void super$1$finalize(); static java.lang.Class class$(java.lang.String);}

Page 49: Gg Code Mash2009 20090106

Groovy is Javapackage com.juddsolutions.groovy.basics;

public class Student {

String firstName String lastName

}

def students = [ new Student(firstName:"Chris", lastName:"Judd"), new Student(firstName:"Jim", lastName:"Shingler"), new Student(firstName:"Joseph", lastName:"Nusairat"),] println "Students:"students.each {student -> println "${student.lastName}, ${student.firstName}"}

javap Student

But Java is not Groovy

groovyc Studentpublic class com.juddsolutions.groovy.basics.Student

extends java.lang.Object implements groovy.lang.GroovyObject {

public static final java.lang.Class $ownClass; public static java.lang.ref.SoftReference $staticMetaClass; transient groovy.lang.MetaClass metaClass; public static java.lang.Long __timeStamp; public static java.lang.Long __timeStamp__239_neverHappen1228887197896; public com.juddsolutions.groovy.basics.Student(); protected groovy.lang.MetaClass $getStaticMetaClass(); public groovy.lang.MetaClass getMetaClass(); public java.lang.Object invokeMethod(java.lang.String, java.lang.Object); public java.lang.Object getProperty(java.lang.String); public void setProperty(java.lang.String, java.lang.Object); static {};

public java.lang.String getFirstName(); public void setFirstName(java.lang.String); public java.lang.String getLastName(); public void setLastName(java.lang.String); public void setMetaClass(groovy.lang.MetaClass); void super$1$wait(); java.lang.String super$1$toString(); void super$1$wait(long); void super$1$wait(long, int); void super$1$notify(); void super$1$notifyAll(); java.lang.Class super$1$getClass(); boolean super$1$equals(java.lang.Object); java.lang.Object super$1$clone(); int super$1$hashCode(); void super$1$finalize(); static java.lang.Class class$(java.lang.String);}

Page 50: Gg Code Mash2009 20090106

Dynamic

Static

StrongWeakC++

JavaScript

Scala

Page 51: Gg Code Mash2009 20090106

Dynamic

Static

StrongWeakC++

JavaScript

Scala

Groovy is:• Strongly typed• Dynamically typed• Optionally typed• Duck typed

Page 52: Gg Code Mash2009 20090106

Also known as the Groovy JDKextends the classes built into the JDK class

library

GDK

Even final classes like String

def p = "cmd /c dir".execute()println p.text

java.lang.String

Page 53: Gg Code Mash2009 20090106

Also known as the Groovy JDKextends the classes built into the JDK class

library

GDK

Even final classes like String

def p = "cmd /c dir".execute()println p.text

java.lang.String Volume in drive C has no label. Volume Serial Number is 38EC-A476

Directory of C:\devl\workspaces\groovy-class\groovy-language-basics

12/15/2008 02:40 PM <DIR> .12/15/2008 02:40 PM <DIR> ..12/09/2008 03:12 AM 373 .classpath12/02/2008 04:42 AM 588 .project12/02/2008 04:42 AM <DIR> .settings12/15/2008 02:42 PM <DIR> bin-groovy12/09/2008 03:12 AM <DIR> build12/02/2008 06:58 PM <DIR> src 2 File(s) 961 bytes 6 Dir(s) 30,512,635,904 bytes free

Page 54: Gg Code Mash2009 20090106

Installing Groovy

1. Download from http://groovy.codehaus.org/Download• 1.5.7 - Stable Release• 1.6 beta 2 - Development Release

2. Unzip archive3. Set GROOVY_HOME environment variable4. Add %GROOVY_HOME%\bin to system path

Depends on JDK 1.4 or greater

Page 55: Gg Code Mash2009 20090106

Installing Groovy

1. Download from http://groovy.codehaus.org/Download• 1.5.7 - Stable Release• 1.6 beta 2 - Development Release

2. Unzip archive3. Set GROOVY_HOME environment variable4. Add %GROOVY_HOME%\bin to system path

Don’t use the installer!!!

Depends on JDK 1.4 or greater

Page 56: Gg Code Mash2009 20090106

Running Groovy

scripts

shell

console groovyConsole

groovysh

groovy

Page 57: Gg Code Mash2009 20090106

just include groovy-all-<version>.jar in classpath

Deploying

Page 58: Gg Code Mash2009 20090106

Note: Quality of Groovy support is represented by size

Page 59: Gg Code Mash2009 20090106

Ant.property(environment:"env") grailsHome = Ant.antProject.properties."env.GRAILS_HOME"

includeTargets << new File ( "${grailsHome}/scripts/War.groovy" )

target ('default':'''Copies a WAR archive to a Java EE application server's deploy directory.

Example: grails deploygrails prod deploy''') { deploy()}

target (deploy: "The implementation target") { depends( war ) def deployDir = Ant.antProject.properties.'deploy.dir'

Ant.copy(todir:"${deployDir}", overwrite:true) { fileset(dir:"${basedir}", includes:"*.war") }

event("StatusFinal", ["Done copying WAR to ${deployDir}"])}

<groovy>println "Hello World"

</groovy>

<build> <plugins> <plugin> <groupId>org.codehaus.groovy.maven</groupId> <artifactId>gmaven-plugin</artifactId> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> </execution> </executions> </plugin> </plugins></build>

Page 60: Gg Code Mash2009 20090106
Page 61: Gg Code Mash2009 20090106

Groovy Site - http://groovy.codehaus.org/Documentation - http://groovy.codehaus.org/Documentation

GDK - http://groovy.codehaus.org/groovy-jdk/

Groovy Zone - http://groovy.dzone.com/Groovy Blogs - http://groovyblogs.org/entries/recent

Page 62: Gg Code Mash2009 20090106

Web Application FrameworkPersistable Domains ObjectsControllersViews (Groovy Server Pages)

Development EnvironmentSpringHibernate (GORM)SiteMeshJettyHSQLDBPrototype & ScriptaculousJUnitGant

Page 63: Gg Code Mash2009 20090106

Griffon

Swing Application Framework

Page 64: Gg Code Mash2009 20090106

Griffon

Swing Application Framework

Page 65: Gg Code Mash2009 20090106

How do you introduceGroovy to the Enterprise?

Unit TestingAutomationBuildsPrototyping

Page 66: Gg Code Mash2009 20090106

Lab 11.Create a HelloWorld Groovy script passing your name

as a parameter.2.Execute the HelloWorld script. 3. javap the HelloWorld code from Lab 1 to determine the

super class.4.Use either the Groovy Console or Groovy Shell to

print out 10 asterisks.

Page 67: Gg Code Mash2009 20090106

Lab 11.Create a HelloWorld Groovy script passing your name

as a parameter.2.Execute the HelloWorld script. 3. javap the HelloWorld code from Lab 1 to determine the

super class.4.Use either the Groovy Console or Groovy Shell to

print out 10 asterisks.

Hello Chris!!!

Page 68: Gg Code Mash2009 20090106

Language Basics

Page 69: Gg Code Mash2009 20090106

StringsQuotedef quote = "Double Quote"println "${quote} is a ${quote.class.name}"

Single

def single = 'Single Quote'println "${single} is a ${single.class.name}"

def slashy = /Slashy Quote/println "${slashy} is a ${slashy.class.name}"

Slashy

Multilinedef multiline = """select * from tablewhere name=value"""

println "${multiline} is a ${multiline.class.name}"

Page 70: Gg Code Mash2009 20090106

StringsQuotedef quote = "Double Quote"println "${quote} is a ${quote.class.name}"

Single

def single = 'Single Quote'println "${single} is a ${single.class.name}"

def slashy = /Slashy Quote/println "${slashy} is a ${slashy.class.name}"

Slashy

Multilinedef multiline = """select * from tablewhere name=value"""

println "${multiline} is a ${multiline.class.name}"

Don’t have to escape \

Page 71: Gg Code Mash2009 20090106

GString

def datetime = "Datetime: ${new Date()}"println "${datetime}"

org.codehaus.groovy.runtime.GStringImpl

String interpolation

Page 72: Gg Code Mash2009 20090106

Asserts

assert a != nullassert a != null, 'a must not be null'

An assertion is used to validate an expected condition is true, according to Groovy Truth.

If the expected condition is not true, a java.lang.AssertionError is thrown.

Page 73: Gg Code Mash2009 20090106

Groovy Truth

true• Non-empty maps• Non-empty Strings• Non-zero numbers• Non-null object references• Matching regex patterns

false• Empty collections• Iterators or Enumerators

with no further elements

Page 74: Gg Code Mash2009 20090106

Groovy Methods

Implicitly returns last expressionAccess modifier is public by default

def passwordtize(text) { def password = '' text.each {password += '*'} password}

Page 75: Gg Code Mash2009 20090106

Closures

A block of reusable code.

A closure is an object.

def sayHello = { println "hello!" }sayHello() //prints "hello!"

def sayHelloTo = {name -> println "Hello ${name}!" }sayHelloTo('Chris') //prints "Hello Chris"sayHelloTo 'Chris' //prints "Hello Chris"

passing parameters

def sayHelloTo = {println "Hello ${it}!" }sayHelloTo 'Jim' //prints "Hello Jim"

implicit it

Page 76: Gg Code Mash2009 20090106

Lists

def authors = []authors.add 'Chris'authors += 'Jim'authors << 'Joseph'

println "Authors:"authors.each{ println it }

println "type: ${authors.class.name}" // java.util.ArrayListprintln "first author is ${authors[0]}"println "last author is ${authors.last()}"

Array like syntax

Connivence methods and operators

def books = [] as Setbooks << "Enterprise Java Development on a Budget"books << "Pro Eclipse JST"books << "Beginning Groovy and Grails"

println"\nBooks:"books.each {book -> println book}println "type: ${books.class.name}" // java.util.HashSet

Alternative types

Page 77: Gg Code Mash2009 20090106

RangesA list of sequential values.

def numbers = 1..10assert numbers.size() == 10numbers.each{ print it }assert numbers.contains(5)

println()

('a'..'z').each{ print it }

println()

for(i in 'a'..'z') { print i}

Page 78: Gg Code Mash2009 20090106

RangesA list of sequential values.

def numbers = 1..10assert numbers.size() == 10numbers.each{ print it }assert numbers.contains(5)

println()

('a'..'z').each{ print it }

println()

for(i in 'a'..'z') { print i} 12345678910

abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz

Page 79: Gg Code Mash2009 20090106

MapsAn unordered collection of key/value pair where the key is unique.def map = ['a':'A', 'b':'B', 'c':'C' ]

println mapprintln map.getClass().name // java.util.LinkedHashMap

println map['a']println map.'a'println map.aprintln map.get('a')println map.getAt('a')

println map.get('d', 'D')map.e = 'E'map['f'] = 'F'map.'g' = 'G'map.put('h', 'H')

println map

Page 80: Gg Code Mash2009 20090106

MapsAn unordered collection of key/value pair where the key is unique.def map = ['a':'A', 'b':'B', 'c':'C' ]

println mapprintln map.getClass().name // java.util.LinkedHashMap

println map['a']println map.'a'println map.aprintln map.get('a')println map.getAt('a')

println map.get('d', 'D')map.e = 'E'map['f'] = 'F'map.'g' = 'G'map.put('h', 'H')

println map

["a":"A", "b":"B", "c":"C"]java.util.LinkedHashMapAAAAAD["a":"A", "b":"B", "c":"C", "d":"D", "e":"E", "f":"F", "g":"G", "h":"H"]

Page 81: Gg Code Mash2009 20090106

Maps

//Print each key/value pair on aseparate line map.each { println "Key: ${it.key}, Value: ${it.value}" }

// Print each key/value pair on aseparate line with index map.eachWithIndex { it, i -> println "${i} Key: ${it.key}, Value: ${it.value}" }

//Print the key setprintln "\nKeys:"map.keySet().each { println it }

// Print the value setprintln "\nValues:"map.values().each { println it }

def numbers = [1:'one', 2: 'two', 3:'three']

def all = map + numbersprintln all

Page 82: Gg Code Mash2009 20090106

Regular Expressions

Operators• match (==~)• find (=~)• pattern (~string)

// Matching Operators

assert "abc" ==~ 'abc' assert "abc" ==~ /abc/ assert !("abcabc" ==~ /abc/) // Fails – not an exact match assert "abc" ==~ /^a.c/ // Starts with a, 1 char, ends with c assert "abc" ==~ /^a../ // Starts with a, 2 chars assert "abc" ==~ /.*c$/ // One or more chars end with c assert "abc" ==~ ".*c\$" // Slashy string is better

// Find Operatordef matcher = 'Groovy is groovy' =~ /(G|g)roovy/ print "Size of matcher is ${matcher.size()} " println "with elements ${matcher[0]} and ${matcher[1]}."

// Pattern Operatordef quote = """Now is the time for all good men (and women) to come to the aid of their country"""

def pattern = ~/(\w+en)/ matcher = pattern.matcher(quote) println "Matches = ${matcher.getCount()}"for(i in matcher.iterator()) { println i}

Page 83: Gg Code Mash2009 20090106

Regular Expressions

Operators• match (==~)• find (=~)• pattern (~string)

// Matching Operators

assert "abc" ==~ 'abc' assert "abc" ==~ /abc/ assert !("abcabc" ==~ /abc/) // Fails – not an exact match assert "abc" ==~ /^a.c/ // Starts with a, 1 char, ends with c assert "abc" ==~ /^a../ // Starts with a, 2 chars assert "abc" ==~ /.*c$/ // One or more chars end with c assert "abc" ==~ ".*c\$" // Slashy string is better

// Find Operatordef matcher = 'Groovy is groovy' =~ /(G|g)roovy/ print "Size of matcher is ${matcher.size()} " println "with elements ${matcher[0]} and ${matcher[1]}."

// Pattern Operatordef quote = """Now is the time for all good men (and women) to come to the aid of their country"""

def pattern = ~/(\w+en)/ matcher = pattern.matcher(quote) println "Matches = ${matcher.getCount()}"for(i in matcher.iterator()) { println i}

Size of matcher is 2 with elements ["Groovy", "G"] and ["groovy", "g"].

Matches = 2menwomen

Page 84: Gg Code Mash2009 20090106

Operator OverloadingOperator Method

a + b a.plus(b)a - b a.minus(b)a * b a.multiply(b)a ** b a.power(b)a / b a.div(b)a % b a.mod(b)a | b a.or(b)a & b a.and(b)a ^ b a.xor(b)

a++ or ++a a.next()a-- or --a a.previous()

a[b] a.getAt(b)a[b] = c a.putAt(b,c)

Page 85: Gg Code Mash2009 20090106

a << b a.leftShift(b)a >> b a.rightShift(b)

switch(a) { case(b) : } b.isCase(a)~a a.bitwiseNegate()-a a.negative()+a a.positive()

class Person {String firstNameString lastNamePerson spouse

String toString() { "${lastName}, ${firstName}" }

Person leftShift(partner) {

partner.lastName = lastNamespouse = partnerpartner.spouse = this

}}

def husband = new Person(firstName:"Chris", lastName:"Judd")def wife = new Person(firstName: "Sue", lastName:"Smith")

// husband and wife get marriedhusband << wife

println wife

Page 86: Gg Code Mash2009 20090106

a << b a.leftShift(b)a >> b a.rightShift(b)

switch(a) { case(b) : } b.isCase(a)~a a.bitwiseNegate()-a a.negative()+a a.positive()

class Person {String firstNameString lastNamePerson spouse

String toString() { "${lastName}, ${firstName}" }

Person leftShift(partner) {

partner.lastName = lastNamespouse = partnerpartner.spouse = this

}}

def husband = new Person(firstName:"Chris", lastName:"Judd")def wife = new Person(firstName: "Sue", lastName:"Smith")

// husband and wife get marriedhusband << wife

println wife

Judd, Sue

Page 87: Gg Code Mash2009 20090106

Operators// Spread Operator

def strings = ['chris', 'jim', 'joseph']

println strings*.getAt(0)

// Elvis Operator

def value = nullprintln value == null ? "unknown" : value // Java ternaryprintln value ?: "unknown" // Elvis Operator value = "cool"println value ?: "unknown" // Elvis Operator // Safe Navigation/Dereference Operator

def string = nullprintln "String lenth is ${string?.size()}"

Page 88: Gg Code Mash2009 20090106

Operators// Spread Operator

def strings = ['chris', 'jim', 'joseph']

println strings*.getAt(0)

// Elvis Operator

def value = nullprintln value == null ? "unknown" : value // Java ternaryprintln value ?: "unknown" // Elvis Operator value = "cool"println value ?: "unknown" // Elvis Operator // Safe Navigation/Dereference Operator

def string = nullprintln "String lenth is ${string?.size()}"

["c", "j", "j"]unknownunknowncoolString length is null

Page 89: Gg Code Mash2009 20090106

Exception in thread "main" groovy.lang.MissingPropertyException: No such property: b for class: Asserts at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getGroovyObjectProperty(ScriptBytecodeAdapter.java:537) at Asserts.run(Asserts.groovy:5) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756) at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:778) at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:758) at org.codehaus.groovy.runtime.InvokerHelper.runScript(InvokerHelper.java:401) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230) at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1105) at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:749) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170) at Asserts.main(Asserts.groovy)

Interpreting Call Stacks

Find first occurrence of *.groovy

Page 90: Gg Code Mash2009 20090106

Lab 2

1.Create a list from 1-10. Then find all the odd numbers and print them out.

2.Print out the list of numbers separated by spaces.

Page 91: Gg Code Mash2009 20090106

Groovy Libraries

Page 92: Gg Code Mash2009 20090106

Basic unit testing

Page 93: Gg Code Mash2009 20090106

Groovy Unit TestsExtend GroovyTestCase which extends JUnit TestCase

class RangeTest extends GroovyTestCase { def lowerCaseRange = 'a'..'z' def upperCaseRange = 'A'..'Z' void testLowerCaseRange() {

assert 26 == lowerCaseRange.size() assertTrue(lowerCaseRange.contains('b')) assertFalse(lowerCaseRange.contains('B')) } void testUpperCaseRange() { assert 26 == upperCaseRange.size() assertTrue(upperCaseRange.contains('B')) assertFalse(upperCaseRange.contains('b')) } void testAlphaRange() { def alphaRange = lowerCaseRange + upperCaseRange assert 52 == alphaRange.size() assert alphaRange.contains('b') assert alphaRange.contains('B') } }

Page 94: Gg Code Mash2009 20090106

Groovy Unit TestsExtend GroovyTestCase which extends JUnit TestCase

class RangeTest extends GroovyTestCase { def lowerCaseRange = 'a'..'z' def upperCaseRange = 'A'..'Z' void testLowerCaseRange() {

assert 26 == lowerCaseRange.size() assertTrue(lowerCaseRange.contains('b')) assertFalse(lowerCaseRange.contains('B')) } void testUpperCaseRange() { assert 26 == upperCaseRange.size() assertTrue(upperCaseRange.contains('B')) assertFalse(upperCaseRange.contains('b')) } void testAlphaRange() { def alphaRange = lowerCaseRange + upperCaseRange assert 52 == alphaRange.size() assert alphaRange.contains('b') assert alphaRange.contains('B') } }

GroovyTestCase adds:• assertArrayEquals• assertContains• assertEquals• assertInspect• assertLength• assertScript• assertToString

Page 95: Gg Code Mash2009 20090106

Running Unit Tests

Runs in standard JUnit tools like Eclipse and Ant

Page 96: Gg Code Mash2009 20090106

Running Unit Tests

Groovy command-line is unit test aware

Page 97: Gg Code Mash2009 20090106

Database

Page 98: Gg Code Mash2009 20090106

import groovy.sql.Sql

// Create connectiondef sql = Sql.newInstance( /jdbc:derby:C:\Program Files\Sun\JavaDB\demo\databases\toursdb/, "APP", "APP", "org.apache.derby.jdbc.EmbeddedDriver")

// Execute SQL and iterate over result setsql.eachRow( "select * from CITIES where Language='English' order by COUNTRY") { println "${it.city_name}, ${it.country}"}

groovy.sql.SQL

Database convenience API

Page 99: Gg Code Mash2009 20090106

import groovy.sql.Sql

// Create connectiondef sql = Sql.newInstance(/jdbc:derby:C:\temp\blogs;create=true/, "APP", "APP", "org.apache.derby.jdbc.EmbeddedDriver")

// delete table if previously createdtry { sql.execute("drop table blogs")} catch(Exception e){}

// create tablesql.execute('''create table blogs ( id varchar(200) not null primary key, title varchar(500))''')

// populate the tabledef blogs = sql.dataSet("blogs")blogs.add( id:"1", title: 'title 1' )blogs.add( id:"2", title: 'title 2' )blogs.add( id:"3", title: 'title 3' )

sql.executeInsert("insert into blogs values('4', 'title 4')")

println "Blogs:"

//Execute SQL and iterate over result set.sql.eachRow("select * from blogs") { println "${it.id}, ${it.title}"}

Page 100: Gg Code Mash2009 20090106

I/O

Page 101: Gg Code Mash2009 20090106

// write filenew File(/C:\temp\states.txt/).text = "Ohio"

// append filedef file = new File(/C:\temp\states.txt/)file.append("\nTexas")

Write File

Page 102: Gg Code Mash2009 20090106

Read File

// read filenew File(/C:\temp\states.txt/).eachLine {line -> println line}

// read file into Stringdef contents = new File(/C:\temp\states.txt/).textprintln contents

// read file into Listdef lines = new File(/C:\temp\states.txt/).readLines()lines.each { println it }

Page 103: Gg Code Mash2009 20090106

Read URL

def feed = new URL( "http://juddsolutions.blogspot.com/feeds/posts/default").text

Page 104: Gg Code Mash2009 20090106

Builders

Page 105: Gg Code Mash2009 20090106

Groovy Builders

A combination of Groovy language features such as meta-programming, closures and simplified map syntax for

creating nested tree-like structures

Name DescriptionAntBuilder Enables the script and execution of Apache Ant tasks

DOMBuilder Generates W3C DOMs

MarkupBuilder GeneratesXML and HTML

NodeBuilder Creates nested trees of objects for handling arbitrary data

SwingBuilder Creates Java Swing UIs

Page 106: Gg Code Mash2009 20090106

def writer = new StringWriter() def builder = new groovy.xml.MarkupBuilder(writer) builder.setDoubleQuotes(true) builder.authors { author(id:"1") { firstName "Chris" lastName "Judd" } author(id:"2") { firstName "Jim" lastName "Shingler" } author(id:"3") { firstName "Joseph" lastName "Nusirat" } } println writer.toString()

MarkupBuilders

Page 107: Gg Code Mash2009 20090106

def writer = new StringWriter() def builder = new groovy.xml.MarkupBuilder(writer) builder.setDoubleQuotes(true) builder.authors { author(id:"1") { firstName "Chris" lastName "Judd" } author(id:"2") { firstName "Jim" lastName "Shingler" } author(id:"3") { firstName "Joseph" lastName "Nusirat" } } println writer.toString()

MarkupBuilders

<authors> <author id="1"> <firstName>Chris</firstName> <lastName>Judd</lastName> </author> <author id="2"> <firstName>Jim</firstName> <lastName>Shingler</lastName> </author> <author id="3"> <firstName>Joseph</firstName> <lastName>Nusirat</lastName> </author></authors>

Page 108: Gg Code Mash2009 20090106

XML Parsing

Page 109: Gg Code Mash2009 20090106

XML Slurping

def xml = """<authors> <author id="1"> <firstName>Chris</firstName> <lastName>Judd</lastName> </author> <author id="2"> <firstName>Jim</firstName> <lastName>Shingler</lastName> </author> <author id="3"> <firstName>Joseph</firstName> <lastName>Nusirat</lastName> </author></authors>"""

def authors = new XmlSlurper().parseText(xml)authors.author.each {author -> println "${author.@id} - ${author.lastName}, ${author.firstName}"}

Page 110: Gg Code Mash2009 20090106

XML Slurping

def xml = """<authors> <author id="1"> <firstName>Chris</firstName> <lastName>Judd</lastName> </author> <author id="2"> <firstName>Jim</firstName> <lastName>Shingler</lastName> </author> <author id="3"> <firstName>Joseph</firstName> <lastName>Nusirat</lastName> </author></authors>"""

def authors = new XmlSlurper().parseText(xml)authors.author.each {author -> println "${author.@id} - ${author.lastName}, ${author.firstName}"}

1 - Judd, Chris2 - Shingler, Jim3 - Nusirat, Joseph

Page 111: Gg Code Mash2009 20090106

Lab 31.Write a script that downloads and RSS feed and writes

the id and title to JavaDB.2.Write a script to read the JavaDB and create an XML

document.

Hint: When behind a you will have to set proxy properties:• http.proxyHost=myServer.net • http.proxyPort=80 • http.proxyUser=<user id>• proxyPassword=<user password>

Page 112: Gg Code Mash2009 20090106

Modern Java Web Development

Page 113: Gg Code Mash2009 20090106

Java Web ProjectsWhat do you need to start a Java?

Page 114: Gg Code Mash2009 20090106

Java Web Projects

• JDK

What do you need to start a Java?

Page 115: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server

What do you need to start a Java?

Page 116: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server

What do you need to start a Java?

Page 117: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System

What do you need to start a Java?

Page 118: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System

What do you need to start a Java?

Page 119: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack

What do you need to start a Java?

Page 120: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack

What do you need to start a Java?

Page 121: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework

What do you need to start a Java?

Page 122: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework

What do you need to start a Java?

Page 123: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework

What do you need to start a Java?

Page 124: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework

What do you need to start a Java?

Page 125: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework

What do you need to start a Java?

Page 126: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework

What do you need to start a Java?

Page 127: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework

What do you need to start a Java?

Page 128: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework

What do you need to start a Java?

Page 129: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework• Database

What do you need to start a Java?

Page 130: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework• Database

What do you need to start a Java?

Page 131: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework• Database• Scheduling Framework .

What do you need to start a Java?

Page 132: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework• Database• Scheduling Framework .• XML Framework

What do you need to start a Java?

Page 133: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework• Database• Scheduling Framework .• XML Framework• Logging Framework

What do you need to start a Java?

Page 134: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework• Database• Scheduling Framework .• XML Framework• Logging Framework• View

What do you need to start a Java?

Page 135: Gg Code Mash2009 20090106

Java Web Projects

• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework• Database• Scheduling Framework .• XML Framework• Logging Framework• View• IDE .

What do you need to start a Java?

Page 136: Gg Code Mash2009 20090106

Java Development Cycle

Page 137: Gg Code Mash2009 20090106

Code

Java Development Cycle

Takes too much time and is too complicated

Compile

Package

Deploy

Debug

Test

Page 138: Gg Code Mash2009 20090106

Conclusion

Java Web and J2EE development is too complicated and not very agile.

Page 139: Gg Code Mash2009 20090106

A Solution

Page 140: Gg Code Mash2009 20090106

A Solution

&

Page 141: Gg Code Mash2009 20090106

What is Grails

Page 142: Gg Code Mash2009 20090106

Grails is• Web Application Framework• Development Environment• Open Source under Apache 2.0 License• Current version 1.0.4 (1.1 is around the corner)• Best Practices

– Convention over configuration– Don’t repeat yourself (DRY)– Default is what you expect (DIWYE)– Agile– Scaffolding– AJAX– Plug-ins– Unit testing– Web Services

Page 143: Gg Code Mash2009 20090106

Grails Framework• JDK• Web Container/App Server• Build System• Application Stack• Persistence Framework• Web Framework• Unit Test Framework• AJAX Framework• Database• Scheduling Framework• XML Framework• Logging Framework• View• IDE

JDK 1.4

GORM

Page 144: Gg Code Mash2009 20090106

Grails Architecture

Java Virtual Machine

Java Language Groovy Language

Grails

Application

Libraries

Gan

t

Spring GORMSiteMesh

DomainControllers Views Services

Page 145: Gg Code Mash2009 20090106

MVC Application Design

Controller

GSP

Dom

ain DB

Page 146: Gg Code Mash2009 20090106

Service Applications

Controller

GSP

Dom

ain•Service DB

Dom

ain

•Service

Page 147: Gg Code Mash2009 20090106

Default Development Environment

JVMJetty (Web Container)

Controller

GSP

Dom

ain

HSQLDB

Page 148: Gg Code Mash2009 20090106

Production Environment

JVMWeb Container/App Server

Controller

GSP

Dom

ain DB

WAR

Page 149: Gg Code Mash2009 20090106

Conclusion

Java’s capability, flexibility, backwards compatibility and community have lead to it’s unprecedented success.

However, these same things have become it’s Achilles heal.

The combination of Groovy and Grails simplifies the Java web platform while making developers more

productive and agile.

Page 150: Gg Code Mash2009 20090106

Starting with the end in mind

Page 151: Gg Code Mash2009 20090106

Starting with the end in mind

• Stage 1 - Conventions, MVC• Stage 2 - View, Styling, Feeds, Search• Stage 3 - Security and Users

Page 152: Gg Code Mash2009 20090106

Prerequisites

• Install Grails (Grails 1.0.4)http://grails.org/Download pick the appropriate distribution for your platform.

• Unpack / install it.

• Set the GRAILS_HOME environment variable and and <GRAILS_HOME>/bin to your path.

Page 153: Gg Code Mash2009 20090106

Verify Install

• at a command / shell prompt type grails

Page 154: Gg Code Mash2009 20090106

Stage 1 - Conventions, MVC

• Grails Application in 60 Seconds or Less,creating your first application

• Exploring the Grails Application structure and Conventions

• Creating Models, Views, and Controllers

• Model Relationships and Constraints

• Next Steps

Page 155: Gg Code Mash2009 20090106

Grails App < 60 secs

• Create a working directory

• From command / shell prompt in that directory type: grails create-app blogcd bloggrails run-app

• In a browser goto: http://localhost:8080/blog

Page 156: Gg Code Mash2009 20090106

Grails App < 60 secs

Page 157: Gg Code Mash2009 20090106

Congratulationsyou are a

programmer

Page 158: Gg Code Mash2009 20090106

Christopher M. Judd

President, Consultant, Author685 Farrington Drive

Worthington, Ohio 43085Phone: (614) 378-4119

Email: [email protected]

SUMMARY

Chris has 12 years of professional experience in object-oriented, web and mobile technologies as well as technical education and leadership. He has experience with all phases of the software development life-cycle, including requirements, analysis, architecture and design, implementation, testing, performance tuning, support, training and project leadership. In addition, he has provided technical instruction to thousands of information technology professionals though instructor led training, mentoring, conferences, user group meetings and co-authoring “Beginning Groovy and Grails”, “Enterprise Java Development on a Budget” and “Pro Eclipse JST”. He has provided services to a diverse group of industries including manufacturing, transportation, government, insurance, publishing, retail, content management, entertainment, service, and technology consulting.

EXPERIENCE

Java User Group Leader! July 2002 – PresetCentral Ohio Java User Group (COJUG)

! Coordinate and advertise monthly meetings on Java related topics.

Consultant! Sept 2004 – Sept 2008Nationwide Insurance

! Assisted in developing, architecting and performance testing a service oriented architecture (SOA) for selling and servicing insurance agreements using IBM’s Insurance Application Architecture (IAA) as the canonical business model. The services coordinated and orchestrated thirty six integration points including three policy administrative systems. The services were used by three front ends that supported agents and customers on the Internet.

! Assisted in developing and architecting an implementation of IBM’s conceptual Insurance Application Architecture (IAA) framework using Rational Application Developer, WebSphere Application Server, DB2 and Rational Software Modeler for UML modeling

! Profiled and performance tested insurance framework using HP Diagnostics Software. ! Architected, Designed and Developed an IAA based product modeler build on top of the Eclipse

Platform including Eclipse Modeling Framework (EMF) and Graphical Editing Framework (GEF)! Mentored a team of developers with no Java or web development experience to build web applications

using Groovy and Grails.! Mentored a team of developers in Java, J2EE, unit testing, configuration management and agile

methodologies! Set up and administered a continuous integration build server which provides code quality and metrics

reports using ANT, Maven, Cruise Control, CVS, Subversion and other open source tools

Chief Technical O"cer! Jan 2008 – May 2008gwizMOBILE

! Assisted in developing and architecting a mobile auto trading application and advertisement tool using Groovy, Grails and J2ME.

Consultant! June 2003 – Sept 2004CINTAS

! Mentored a team of 4 developers with almost no Java experience to become productive J2EE developers! Archited and developed a multi-tier reusable service based J2EE application using JBuilder, WebLogic,

Struts, Together and SQL Server for a new document management line of business! Taught JBuilder, J2EE, StarTeam, Linux, Dreamweaver, Struts and Object-Oriented Programming

Grails

Don’t forget to update your

resume.

Page 159: Gg Code Mash2009 20090106

So What Happened

• grails create-app blogcreated application structure &copied some files

• grails run-appstarted up the Jetty applicationserver and ran the application

Page 160: Gg Code Mash2009 20090106

App Structure & Conventions

A pretty standard application structure, . . . you can pretty well guess the purpose of the files and

directories.

Page 161: Gg Code Mash2009 20090106

Grails commands

Page 162: Gg Code Mash2009 20090106

Domain Class

• Blog and BlogEntry domain class:grails create-domain-class Bloggrails create-domain-class BlogEntry

• What just happened?Grails created two domain classes (Blog, BlogEntry) and two unit tests (BlogTest, BlogEntryTest)

Page 163: Gg Code Mash2009 20090106

BlogProperties:

• blogid, title, byline, dateCreated, lastUpdated

Method:

• toString()

class blog { String blogid String title String byline Date dateCreated Date lastUpdated

String toString () { return "Blog ${id} = ${title}" }}

Page 164: Gg Code Mash2009 20090106

BlogEntryProperties:

• title, body, dateCreated, and lastUpdated

Methods:

• toString() class BlogEntry { String title String body Date dateCreated Date lastUpdated

String toString () { return "BlogEntry ${id} = ${title}" }}

Page 165: Gg Code Mash2009 20090106

Controller and View• Create the controller.

grails create-controller Bloggrails create-controller BlogEntry

• What Happened?Grails created controller stubs for the domain classes, Blog and BlogEntry, and the corresponding unit tests.

Using Convention, the classes are named BlogController, BlogControllerTest, BlogEntryController, and BlogEntryControllerTest

Page 166: Gg Code Mash2009 20090106

Controller and View• Scaffolding auto generates views and controllers that

support basic CRUD (Create, Read, Update, and Delete) operations on domain objects.

• Edit BlogController and BlogEntryController, scaffold them by replacing the contents of the controller with: def scaffold = true

class BlogController { def scaffold = true}

Page 167: Gg Code Mash2009 20090106

Controller and View

Page 168: Gg Code Mash2009 20090106

Controller and View

Page 169: Gg Code Mash2009 20090106

What’s Missing

Page 170: Gg Code Mash2009 20090106

What’s Missing

• Data validity

Page 171: Gg Code Mash2009 20090106

What’s Missing

• Data validity

• Relationships

Page 172: Gg Code Mash2009 20090106

What’s Missing

• Data validity

• Relationships

• Not Pretty (Stage 2)

Page 173: Gg Code Mash2009 20090106

What’s Missing

• Data validity

• Relationships

• Not Pretty (Stage 2)

• User & Security (Stage 3)

Page 174: Gg Code Mash2009 20090106

class Blog { String blogid String title String byline Date dateCreated Date lastUpdated static constraints = { title(blank: false, size: 1..128) byline(nullable: true) blogid(blank: false) dateCreated() lastUpdated(nullable: true) }

String toString () { return "Blog ${id} = ${title}" }}

Data Validation (Constraints)

http://www.grails.org/Validationhttp://www.grails.org/Validation+Reference

Page 175: Gg Code Mash2009 20090106

Relationships (GORM)

http://www.grails.org/GORMhttp://www.grails.org/GORM+-+Defining+relationships

Page 176: Gg Code Mash2009 20090106

class Blog { String blogid String title String byline Date dateCreated Date lastUpdated static hasMany = [ blogEntries : BlogEntry] static constraints = { title(blank: false, size: 1..128) byline(nullable: true) blogid(blank: false) lastUpdated(nullable: true) } String toString () { return "Blog ${id} = ${title}" }}

Relationships (GORM)

http://www.grails.org/GORMhttp://www.grails.org/GORM+-+Defining+relationships

Page 177: Gg Code Mash2009 20090106

class BlogEntry { String title String body Date dateCreated Date lastUpdated

static belongsTo = [ Blog ] Blog blog static constraints = { title(blank: false, maxSize: 128) body(blank: false, maxSize: 10000) dateCreated() lastUpdated(nullable: true) }

String toString () { return "BlogEntry ${id} - ${title}" }}

Relationships (GORM)

http://www.grails.org/GORMhttp://www.grails.org/GORM+-+Defining+relationships

Page 178: Gg Code Mash2009 20090106

Database ConfigurationdataSource { pooled = true driverClassName = "org.hsqldb.jdbcDriver" username = "sa" password = ""}hibernate { cache.use_second_level_cache=true cache.use_query_cache=true cache.provider_class='com.opensymphony.oscache.hibernate.OSCacheProvider'}// environment specific settingsenvironments { development { dataSource { dbCreate = "create-drop" // one of 'create', 'create-drop','update' url = "jdbc:hsqldb:mem:devDB" } } test { dataSource { dbCreate = "update" url = "jdbc:hsqldb:mem:testDb" } } production { dataSource { dbCreate = "update" url = "jdbc:hsqldb:file:prodDb;shutdown=true" } }}

Page 179: Gg Code Mash2009 20090106

Generate Views and Controllers

Page 180: Gg Code Mash2009 20090106

Generate Views and Controllers

• grails generate-all Bloggrails generate-all BlogEntry

Page 181: Gg Code Mash2009 20090106

Generate Views and Controllers

• grails generate-all Bloggrails generate-all BlogEntry

• What happened?Grails used templates to generate create.gsp, list.gsp, edit.gsp, show.gsp for Blog and BlogEntry. (Where are they)

Grails used templates to generate BlogController.groovy and BlogEntryController.groovy (Where are they)

Page 182: Gg Code Mash2009 20090106

GORM Sidebar

• Save, Update, Delete, Get

• Dynamic Finders

http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20(GORM).html#5.4%20Querying%20with%20GORM

Page 183: Gg Code Mash2009 20090106

Lab 41.Create the Blog Application.2.Create the Blog and Blog Entry Domain Classes.3.Create both controllers with Scaffolding.4.Run the application.5.Add Constraints to Blog and Blog Entry and the

relationships between them. 6.Run the application again.7.Generate the Views and Controllers for Blog and

BlogEntry. 8.Examine the views and controllers.

Page 184: Gg Code Mash2009 20090106

Recap• Installed Grails and validated

• Built firstapp in < 60 secs ;-)

• Explored application structure and conventions

• Create stage 1 of the Blog application, 2 Domain Classes with scaffolded Controllers and Views.

• Added Data Validation to the Domain Classes

• Created a 1:M relationship between Blog and BlogEntry

• Explored generated views and controllers

Page 185: Gg Code Mash2009 20090106

Stage 2 - View Styles• Layouts

• TagLibs

• Preview (AJAX)

• URL Mappings

• Feeds

• Search

Page 186: Gg Code Mash2009 20090106

Layout

Page 187: Gg Code Mash2009 20090106

Layout

Header

Sidebar

Footer

Body

Page 188: Gg Code Mash2009 20090106

SetupResources (Images, CSS, and JavaScript)

• Copy contents of <GrailsResources>/webapp to the blog project

Updating the layout (layouts/main.gsp, layouts/print.gsp, _sidebar.gsp)

• Copy contents of <GrailsResources>/views/layouts to blog project

• Copy contents of <GrailsResources>/views to blog project

Page 189: Gg Code Mash2009 20090106

TagLibs

• What is a taglib

• Previous Experiences with taglibs

• Grails Taglibs

• EntriesTagLib

Page 190: Gg Code Mash2009 20090106

BlogEntry ViewsList

• BlogEntryList.gsp

• Redirect BlogEntryController. Show to single list (Reuse)

• EntriesTagLib - Nice Dates

Page 191: Gg Code Mash2009 20090106

BlogEntry ViewsPrint

• Add Print output.Need a way to trigger print layoutNo Header, Footer, or sidebar

Page 192: Gg Code Mash2009 20090106

BlogEntry ViewsEdit

• BlogEntryEdit.gsp

Page 193: Gg Code Mash2009 20090106

BlogEntry ViewsAJAX Preview

• Add Ajax and Destination

• Add BlogEntryController.Preview to use preview template

• Create BlogEntry Preview Template

Page 194: Gg Code Mash2009 20090106

Lab 51.Copy Resources and Layouts2.Setup the new BlogEntry list display3.Redirect Show to use new list view4.Create EntriesTagLib for title and niceDate5.Review Print Layout and add Trigger to BlogEntry List6.Setup new BlogEntry Edit View7.Add Preview Functionality

Page 195: Gg Code Mash2009 20090106

URL Mappingclass UrlMappings { static mappings = { "/$controller/$action?/$id?"{ constraints { // apply constraints here } }

"/$blog/$year/$month?/$day?/$id?" { controller = "blogEntry" action = "displayEntry" constraints { year(matches: /\d{4}/) month(matches: /\d{2}/) day(matches: /\d{2}/) } } "/$blog/" { controller = "blogEntry" action = "list" } "500"(view:'/error') }}

Page 196: Gg Code Mash2009 20090106

UrlMapping

• Change the Header and Byline

• blog/list.gsp add to the linkparams="[blog: blogInstance.blogid]"

• blog/show.gsp add to the edit link<input type="hidden" name="blog" value="${blogInstance?.blogid}" />

Page 197: Gg Code Mash2009 20090106

Permalink• Add Permalink Generation to BlogEntry

public String toPermalink() { def sdf = new java.text.SimpleDateFormat("yyyy/MM/dd") return "/${blog?.blogid}/${sdf.format(dateCreated)}/${title.encodeAsNiceTitle()}.html"}

Page 198: Gg Code Mash2009 20090106

Permalink• Nice Title Codec

• Add BlogEntry Action DisplayEntryInsert from <GrailsResources>/controllers/BlogEntryController.displayEntry.txt

// strip all non word chars, convert to lowercase...class NiceTitleCodec { static encode = { str -> return str.toString().replaceAll("\\W", "-").toLowerCase() }}

Page 199: Gg Code Mash2009 20090106

PluginsA plugin is a Grails extension point. Conceptually, it is similar to the plugins found in modern IDEs.

A plugin is a technique to encapsulate functionality that can be reused across multiple applications.

Grails has a rich plugin community at last count, over 100 plugins for a partial list.

See: http://grails.org/Plugins

http://grails.org/Pluginshttp://www.grails.org/The+Plug-in+Developers+Guide

Page 200: Gg Code Mash2009 20090106

Feeds• Install the Feeds Plugin

grails install-plugin feeds

• Create a Feed Controllergrails create-controller feed

http://grails.org/Feeds+Plugin

def index = { redirect(action:list,params:params) } def list = { render(feedType:"rss", feedVersion:"2.0"){ title="CM Blogs" link="http://localhost:8080/blog/feed" description="Demo Blog Feed from CodeMash 2009" def blogs = BlogEntry.list([max: 5, sort: "dateCreated", order: "desc"]) blogs.each{blogEntry -> entry(blogEntry.title) { link="http://localhost:8080/blog/blogEntry/show/${blogEntry.id}" blogEntry.body } } } }

Page 201: Gg Code Mash2009 20090106

Feeds

• Add Link to sidebar

http://grails.org/Feeds+Plugin

<ul> <li><g:link controller='feed'> <img src="${createLinkTo(dir:'images',file:'feed-icon-16x16.jpg')}" alt="RSS"/>RSS </g:link> </li> <li><a class="home" href="${createLinkTo(dir:'')}">Home</a></li></ul>

Page 202: Gg Code Mash2009 20090106

Search• Install Grail’s Searchable Plugin

grails install-plugin searchable

• Make BlogEntry searchable

static searchable = { only = ["title", "body", "dateCreated", "blogs"] blog(component: true) } def indexedFields() { def fields = [:] // strip html before storing in index fields.title = title.replaceAll("\\<.*?\\>","") fields.body = body.replaceAll("\\<.*?\\>","") return fields }

Page 203: Gg Code Mash2009 20090106

Searchable• Make Blog Searchable

• http://localhost:8080/blog/seachable

static searchable = { only = ["blogid", "title", "byline"] root : false }

Page 204: Gg Code Mash2009 20090106

Searchable• Let’s Add a seach box to the application.

• Copy <GrailsResources>/view/blog/search.gsp

<div style="float: right; position: relative; margin-right: 7px; font-size: medium; "> <g:form url='[controller: "blog", action: "search"]' id="searchableForm" name="searchableForm" method="get"> <g:textField name="query" value="${params.query}" size="25"/> <input type="submit" value="Search" /> </g:form></div>

Page 205: Gg Code Mash2009 20090106

Lab 6

1.Setup UrlMappings http://localhost:8080/blog/jim and http://localhost:8080/blog/jim/yyyy/mm/dd

2.Create BlogEntry PermaLink 3.Setup RSS Feed4.Setup Search Functionality

Page 206: Gg Code Mash2009 20090106

Recap• Installed Grails and validated

• Built firstapp in < 60 secs ;-)

• Explored application structure and conventions

• Create stage 1 of the Blog application, 2 Domain Classes with scaffolded Controllers and Views.

• Added Data Validation to the Domain Classes

• Created a 1:M relationship between Blog and BlogEntry

• Explored generated views and controllers

Page 207: Gg Code Mash2009 20090106

Stage 3 - Security

• Discuss Security topics: User, Roles, Permissions, Realms

• Define User and Security Requirements

• Discuss Security Options

• Build it out

Page 208: Gg Code Mash2009 20090106

Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms

Page 209: Gg Code Mash2009 20090106

Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms

User / Subject

Page 210: Gg Code Mash2009 20090106

Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms

User / Subject Principals• Username: jim• Account Number• PGP Key

Page 211: Gg Code Mash2009 20090106

Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms

User / Subject Principals• Username: jim• Account Number• PGP Key

Role• User• Administrator

Page 212: Gg Code Mash2009 20090106

Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms

User / Subject Principals• Username: jim• Account Number• PGP Key

Role• User• Administrator

Permission• blog (jim) : create, update, delete

Page 213: Gg Code Mash2009 20090106

Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms

User / Subject Principals• Username: jim• Account Number• PGP Key

Role• User• Administrator

Permission• blog (jim) : create, update, delete

Realm: database, LDAP, . . .

Page 214: Gg Code Mash2009 20090106

User and Security Requirements

• User should have a name, email, password

• Blog has a User

• Only the User or an Administrator can modify a Blog / Blog Entry

• Users shouldn’t be able to modify each others blogs

Page 215: Gg Code Mash2009 20090106

Security Options• Spin your own (Loads of work & error prone)

• Use a Security Package

• Grails Plugins

• ACEGI (Spring Security)

• JSecurity

• . . .

• Integrate some other package

http://grails.org/Plugins#Security%20Pluginshttp://www.jsecurity.org

Page 216: Gg Code Mash2009 20090106

Security Options• Spin your own (Loads of work & error prone)

• Use a Security Package

• Grails Plugins

• ACEGI (Spring Security)

• JSecurity

• . . .

• Integrate some other package

http://grails.org/Plugins#Security%20Pluginshttp://www.jsecurity.org

Page 217: Gg Code Mash2009 20090106

Security Relationships

Page 218: Gg Code Mash2009 20090106

JSecurity Plugins• List available plugins:

grails list-plugins

• Install the JSecurity plugingrails install-plugin jsecurity 0.4-SNAPSHOT

• Setup JSecuritygrails quick-start

• Let’s ExploreDomain Classes, Views, Tag Libs

http://www.grails.org/JSecurity+Pluginhttp://www.grails.org/JSecurity+Plugin+-+Quick+Start

Page 219: Gg Code Mash2009 20090106

JSecurity Plugins• List available plugins:

grails list-plugins

• Install the JSecurity plugingrails install-plugin jsecurity 0.4-SNAPSHOT

• Setup JSecuritygrails quick-start

• Let’s ExploreDomain Classes, Views, Tag Libs

http://www.grails.org/JSecurity+Pluginhttp://www.grails.org/JSecurity+Plugin+-+Quick+Start

VERY IMPORTANT:We need this specific version.

Page 220: Gg Code Mash2009 20090106

Enhancing the User Class• User should have a name, email, password

Page 221: Gg Code Mash2009 20090106

Enhancing the User Class• User should have a name, email, password

class JsecUser { String username String passwordHash String fullName String email

static constraints = { username (blank: false) fullName (blank: false) email (blank: false, email: true) } String toString() { return "User ${id} - ${fullName}" }}

Page 222: Gg Code Mash2009 20090106

Enhancing Blog• Blog has a User

class Blog { String blogid String title String byline Date dateCreated Date lastUpdated JsecUser user static hasMany = [ blogEntries : BlogEntry] static constraints = { title(blank: false, size: 1..128) byline(nullable: true) blogid(blank: false) dateCreated() lastUpdated(nullable: true) } static searchable = { only = ["blogid", "title", "byline"] root : false } String toString () { return "Blog ${id} = ${title}" }}

Page 223: Gg Code Mash2009 20090106

Enhancing Blog• Blog has a User

class Blog { String blogid String title String byline Date dateCreated Date lastUpdated JsecUser user static hasMany = [ blogEntries : BlogEntry] static constraints = { title(blank: false, size: 1..128) byline(nullable: true) blogid(blank: false) dateCreated() lastUpdated(nullable: true) } static searchable = { only = ["blogid", "title", "byline"] root : false } String toString () { return "Blog ${id} = ${title}" }}

Page 224: Gg Code Mash2009 20090106

What’s missing

• No Predefined Admin User

Page 225: Gg Code Mash2009 20090106

Boot Strap Admin & Dilbertimport org.jsecurity.crypto.hash.Sha1Hashimport org.jsecurity.authz.permission.WildcardPermission

class BootStrap {

def init = { servletContext -> def basicPermission = new JsecPermission(type: "org.jsecurity.authz.permission.WildcardPermission", possibleActions: "*").save() def adminRole = new JsecRole(name: "administrator").save() def userRole = new JsecRole(name: "user").save() new JsecRolePermissionRel( role: adminRole, permission: basicPermission, target: "*", actions: "*").save() new JsecRolePermissionRel( role: userRole, permission: basicPermission, target: "blog:create,save", actions: "*").save() new JsecRolePermissionRel( role: userRole, permission: basicPermission, target: "blogEntry:create,save", actions: "*").save() new JsecRolePermissionRel( role: userRole, permission: basicPermission, target: "jsecUser:create,save", actions: "*").save()

Page 226: Gg Code Mash2009 20090106

Boot Strap Admin & Dilbertimport org.jsecurity.crypto.hash.Sha1Hashimport org.jsecurity.authz.permission.WildcardPermission

class BootStrap {

def init = { servletContext -> def basicPermission = new JsecPermission(type: "org.jsecurity.authz.permission.WildcardPermission", possibleActions: "*").save() def adminRole = new JsecRole(name: "administrator").save() def userRole = new JsecRole(name: "user").save() new JsecRolePermissionRel( role: adminRole, permission: basicPermission, target: "*", actions: "*").save() new JsecRolePermissionRel( role: userRole, permission: basicPermission, target: "blog:create,save", actions: "*").save() new JsecRolePermissionRel( role: userRole, permission: basicPermission, target: "blogEntry:create,save", actions: "*").save() new JsecRolePermissionRel( role: userRole, permission: basicPermission, target: "jsecUser:create,save", actions: "*").save()

Note:

If you are using a persistent datastore (DB), NON-Memory, Then you should put guard conditions around the bootstrapping of Permission, Roles, and Users

Page 227: Gg Code Mash2009 20090106

println "Building Admin User" def adminUser = new JsecUser(username: "admin",

passwordHash: new Sha1Hash("admin").toHex(), fullName: "Admin User", email: "[email protected]").save()new JsecUserRoleRel(user: adminUser, role: adminRole).save()

def blog = new Blog(title: "Blog: ${adminUser.fullName}", blogid: adminUser.username, user: adminUser)blog.save()

def dilbert = new JsecUser(username: "dilbert",

passwordHash: new Sha1Hash("password").toHex(), fullName: "Scott Adams", email: "[email protected]").save()new JsecUserRoleRel(user: dilbert, role: userRole).save()

new JsecUserPermissionRel(user: dilbert, permission: basicPermission,

target: "jsecUser:edit,update:${dilbert.id}",actions: "*").save() new JsecUserPermissionRel(user: dilbert, permission: basicPermission,

target: "blog:edit,update:${dilbert.id}", actions: "*").save()

new JsecUserPermissionRel(user: dilbert, permission: basicPermission,target: "blogEntry:edit,update:${dilbert.id}", actions: "*").save()

// Add Blognew Blog(title: "Blog: ${dilbert.fullName}",

blogid: dilbert.username, user: dilbert).save() }

. . .

Page 228: Gg Code Mash2009 20090106

What’s Missing

• Ability to create a new User

Page 229: Gg Code Mash2009 20090106

Views & Controller for JSecUser

Page 230: Gg Code Mash2009 20090106

Views & Controller for JSecUser• Do you remember how?

Page 231: Gg Code Mash2009 20090106

Views & Controller for JSecUser• Do you remember how?

• grails generate-all JSecUser

Page 232: Gg Code Mash2009 20090106

Views & Controller for JSecUser• Do you remember how?

• grails generate-all JSecUser

Page 233: Gg Code Mash2009 20090106

What’s missing

• Password should be hashed

• Auto create blog when new user saved

Page 234: Gg Code Mash2009 20090106

JsecUserController Enhancement• Hash the password

• On Save automatically create blog

Page 235: Gg Code Mash2009 20090106

JsecUserController Enhancement• Hash the password

• On Save automatically create blogimport org.jsecurity.crypto.hash.Sha1Hash

class JsecUserController {

. . .

def save = { def jsecUserInstance = new JsecUser(params) jsecUserInstance.passwordHash = new Sha1Hash(jsecUserInstance.passwordHash).toHex() if(!jsecUserInstance.hasErrors() && jsecUserInstance.save()) {

// Add Blognew Blog(title: "Blog: ${jsecUserInstance.fullName}",

blogid: jsecUserInstance.username, user: jsecUserInstance).save()

flash.message = "User ${jsecUserInstance.id} created" redirect(action:show,id:jsecUserInstance.id) } else { render(view:'create',model:[jsecUserInstance:jsecUserInstance]) } }

. . . }

Page 236: Gg Code Mash2009 20090106

What’s Missing

• Roles and Permissions aren’t being enforced.

Page 237: Gg Code Mash2009 20090106

Enforcement of Roles & Permissions

• Roles and Permissions are enforced using a Security Filter, . . . Yes, Filter as in Filter interceptor

• Also need to add Role and Permission when saving a new user.

Page 238: Gg Code Mash2009 20090106

Security Filterclass SecurityFilters {def filters = {

auth(controller: "(blog|blogEntry)", action: "(create|save)") {before = {

// This just means that the user must be authenticated. He does // not need any particular role or permission.accessControl { true }

} }

jsecUser(controller: "jsecUser", action: "(edit|update|delete)") {

before = {accessControl {

def userId = 0if (params.id) {

userId = JsecUser.get(params.id).id}role("administrator") || permission("jsecUser:${actionName ?: 'list'}:${userId}")

}}

}

blog(controller: "(blog|blogEntry)", action: "(edit|update|delete)") {before = {

accessControl {def userId = 0def blogId = 0def blogif (params.id) {

blog = Blog.get(params.id)userId = blog.user.id

}role("administrator") || permission("blog:${actionName ?: 'list'}:${userId}")

}}}}

http://grails.org/Filters

Page 239: Gg Code Mash2009 20090106

Security Filterclass SecurityFilters {def filters = {

auth(controller: "(blog|blogEntry)", action: "(create|save)") {before = {

// This just means that the user must be authenticated. He does // not need any particular role or permission.accessControl { true }

} }

jsecUser(controller: "jsecUser", action: "(edit|update|delete)") {

before = {accessControl {

def userId = 0if (params.id) {

userId = JsecUser.get(params.id).id}role("administrator") || permission("jsecUser:${actionName ?: 'list'}:${userId}")

}}

}

blog(controller: "(blog|blogEntry)", action: "(edit|update|delete)") {before = {

accessControl {def userId = 0def blogId = 0def blogif (params.id) {

blog = Blog.get(params.id)userId = blog.user.id

}role("administrator") || permission("blog:${actionName ?: 'list'}:${userId}")

}}}}

http://grails.org/Filters

Page 240: Gg Code Mash2009 20090106

JsecUserController Enchancementdef save = { def jsecUserInstance = new JsecUser(params) jsecUserInstance.passwordHash = new Sha1Hash(jsecUserInstance.passwordHash).toHex() if(!jsecUserInstance.hasErrors() && jsecUserInstance.save()) {

new Blog(title: "Blog: ${jsecUserInstance.fullName}", blogid: jsecUserInstance.username, user: jsecUserInstance).save()

def userRole = JsecRole.findByName("user")new JsecUserRoleRel(user: jsecUserInstance, role: userRole).save()

def basicPermission = JsecPermission.findByType("org.jsecurity.authz.permission.WildcardPermission")new JsecUserPermissionRel(

user: jsecUserInstance, permission: basicPermission, target: "jsecUser:edit,update:${jsecUserInstance.id}", actions: "*").save()

new JsecUserPermissionRel( user: jsecUserInstance, permission: basicPermission, target: "blog:edit,update:${jsecUserInstance.id}", actions: "*").save()

new JsecUserPermissionRel( user: jsecUserInstance, permission: basicPermission, target: "blogEntry:edit,update:${jsecUserInstance.id}", actions: "*").save()

flash.message = "User ${jsecUserInstance.id} created" redirect(action:show,id:jsecUserInstance.id) } else { render(view:'create',model:[jsecUserInstance:jsecUserInstance]) } }

Page 241: Gg Code Mash2009 20090106

JsecUserController Enchancementdef save = { def jsecUserInstance = new JsecUser(params) jsecUserInstance.passwordHash = new Sha1Hash(jsecUserInstance.passwordHash).toHex() if(!jsecUserInstance.hasErrors() && jsecUserInstance.save()) {

new Blog(title: "Blog: ${jsecUserInstance.fullName}", blogid: jsecUserInstance.username, user: jsecUserInstance).save()

def userRole = JsecRole.findByName("user")new JsecUserRoleRel(user: jsecUserInstance, role: userRole).save()

def basicPermission = JsecPermission.findByType("org.jsecurity.authz.permission.WildcardPermission")new JsecUserPermissionRel(

user: jsecUserInstance, permission: basicPermission, target: "jsecUser:edit,update:${jsecUserInstance.id}", actions: "*").save()

new JsecUserPermissionRel( user: jsecUserInstance, permission: basicPermission, target: "blog:edit,update:${jsecUserInstance.id}", actions: "*").save()

new JsecUserPermissionRel( user: jsecUserInstance, permission: basicPermission, target: "blogEntry:edit,update:${jsecUserInstance.id}", actions: "*").save()

flash.message = "User ${jsecUserInstance.id} created" redirect(action:show,id:jsecUserInstance.id) } else { render(view:'create',model:[jsecUserInstance:jsecUserInstance]) } }

Look Familiar?Take a look at:

BootStrap.groovy

Page 242: Gg Code Mash2009 20090106

What’s Missing

• User views (List, Show, Edit, Create) shouldn’t show the password in the clear

• Password label needs to be adjusted.

Page 243: Gg Code Mash2009 20090106

Enhance User Views. . .

<tr class="prop"> <td valign="top" class="name"><label for="username">Username:</label> </td> <td valign="top" class="value ${hasErrors(bean:jsecUserInstance,field:'username','errors')}"> <input type="text" id="username" name="username" value="${fieldValue(bean:jsecUserInstance,field:'username')}" /></td></tr>

<tr class="prop"> <td valign="top" class="name"><label for="passwordHash">Password:</label> </td> <td valign="top" class="value ${hasErrors(bean:jsecUserInstance,field:'passwordHash','errors')}"> <input type="password" id="passwordHash" name="passwordHash" value="${fieldValue(bean:jsecUserInstance,field:'passwordHash')}" /></td></tr>

. . .

Page 244: Gg Code Mash2009 20090106

Enhance User Views. . .

<tr class="prop"> <td valign="top" class="name"><label for="username">Username:</label> </td> <td valign="top" class="value ${hasErrors(bean:jsecUserInstance,field:'username','errors')}"> <input type="text" id="username" name="username" value="${fieldValue(bean:jsecUserInstance,field:'username')}" /></td></tr>

<tr class="prop"> <td valign="top" class="name"><label for="passwordHash">Password:</label> </td> <td valign="top" class="value ${hasErrors(bean:jsecUserInstance,field:'passwordHash','errors')}"> <input type="password" id="passwordHash" name="passwordHash" value="${fieldValue(bean:jsecUserInstance,field:'passwordHash')}" /></td></tr>

. . . Go ahead and make the corresponding adjustments to the other user views as appropriate.

(list.gsp, create.gsp, show.gsp, edit.gsp)

Page 245: Gg Code Mash2009 20090106

What’s Missing

• When creating a blog entry the user shouldn’t have to specify which user the blog is related to.

Page 246: Gg Code Mash2009 20090106

Blog / User automation

• Remove User fields from the Blog views.

• Update BlogEntryController save. def save = {

def blogEntryInstance = new BlogEntry(params) if (blogEntryInstance.hasErrors()) { render(view:'create',model:[blogEntryInstance:blogEntryInstance]) return } else { def subject = SecurityUtils.subject def user = JsecUser.findByUsername(subject.principal) def blog = Blog.findByUser(user) log.debug "Adding new entry to blog ${blog?.title}" blog?.addToBlogEntries(blogEntryInstance)?.save() blogEntryInstance.save() flash.message = "BlogEntry ${blogEntryInstance.id} created" redirect(action:show,id:blogEntryInstance.id) } }

Page 247: Gg Code Mash2009 20090106

Update Url Mapping

"/$blog/" { controller = "blogEntry" action = "homePage" }

Page 248: Gg Code Mash2009 20090106

What’s Missing

• Need a way to logout

• Should be able to Register a new user from the login screen.

Page 249: Gg Code Mash2009 20090106

Register New User<tr>

<td /><!--

<td><input type="submit" value="Sign in" /></td>--><td><g:actionSubmit value="Sign in" action="signIn" /><g:actionSubmit value="Register" action="register" /></td>

</tr></tbody>

login.gsp

. . .def register = {

redirect(controller: 'jsecUser', action: 'create')}

. . .

AuthController.groovy

Page 250: Gg Code Mash2009 20090106
Page 251: Gg Code Mash2009 20090106

Congratulations!!!

And to think, this morning you didn’t know Groovy and Grails.

Page 252: Gg Code Mash2009 20090106

Recap• Reviewed Security Concepts: Subject, Principals, Roles,

Permissions, and Realms

• Reviewed Security Options and setup JSecurity Plugin

• Enhanced the JsecUser Class and related it to Blog

• Boot Strapped the Admin user are setup Roles and Persmissions

• Generated JsecUser Views and Controller

• User SecurityFilters to enforce Roles and Permissions

• Created ability to Logout, Login / Register

Page 253: Gg Code Mash2009 20090106

Groovy & Grails Training

Groovy Essentials (2 days) Grails Essentials (2 days)•Groovy language basics

•Java Comparison •Tools and IDEs •Language constructs •Groovy Strings •Closures •Collections •Scripting

•Groovy Libraries•Unit Testing•XML (Markup Builders/Parsing)•JDBC•I/O

•Advanced Groovy language features •Meta-programming •Expando •Domain Specific Languages

•Advanced Unit Testing

Free Groovy & Grails Overview (1 1/2 hours)

•Grails basics •Conventions •MVC •Architecture •Environments

•Scaffolding •Domain Model

•GORM •Saving, deleting, updating •Dynamic finders •Querying •Constraints •Relationships

•Controllers •Writing actions •Binding data •Flash scope •Pagination •Interception and Filtering

•Views •Layouts and templates •Groovy Server Pages (GSP) •Adding AJAX

•Services and Jobs •Plug-ins

•Finding and Installing •Creating

•Web Services •Authentication and Authorization

Groovy & Grails JumpStart (30-60 days)

Page 254: Gg Code Mash2009 20090106

Resources• Introduction to Groovy• Groovy Basics• More Advanced Groovy• Introduction to Grails• Building the User Interface• Building Domains and Services• Security in Grails• Web 2.0—Ajax and Friends• Web Services• Reporting• Batch Processing• Deploying and Upgrading• Alternative Clients

Page 255: Gg Code Mash2009 20090106

Resources• Grails

–grails.codehaus.org or www.grails.org–Grails Quick Start

•grails.codehaus.org/Quick+Start–User Guide

•grails.org/doc/1.0.x/• Books Coming

Soon


Recommended