Jim Shingler
Chief Technical Architect
President of Genuine Solutions
Co-Creator Open Source Project of FallME
Co-Author of Beginning Groovy and Grails
Goal:
Gain enough Groovy and Grails knowledge to
be able to build a modest Grails applications.
Install Groovy and Grails
Create and Run Groovy Scripts
Understand basic Groovy Language Features
Create a Scaffolded Web Application
Apply a Custom Layout and Styling
Install and use Plugins
Enable Security
Christopher M. Judd
President, Consultant, Author
685 Farrington Drive
Worthington, Ohio 43085
Phone: (614) 378-4119
Email: cjudd@juddsolutions.com
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 – Preset
Central Ohio Java User Group (COJUG)
! Coordinate and advertise monthly meetings on Java related topics.
Consultant! Sept 2004 – Sept 2008
Nationwide 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 2008
gwizMOBILE
! Assisted in developing and architecting a mobile auto trading application and advertisement tool using
Groovy, Grails and J2ME.
Consultant! June 2003 – Sept 2004
CINTAS
! 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.
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
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 constructor
Remove accessors and mutators
Use named parameter constructor
Use properties
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 methods
Flexible Strings
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 methods
Flexible Strings
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
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
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
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
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());
}
}
}
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());
}
}
}
What is Groovy?
Groovy is an expressive, dynamic, object oriented language
built for the JavaVirtual Machine (JVM) with lots of agile
and modern language features.
What is Groovy?
Groovy is an expressive, dynamic, object oriented language
built for the JavaVirtual Machine (JVM) with lots of agile
and modern language features.
Better Java
What is Groovy?
Groovy is an expressive, dynamic, object oriented language
built for the JavaVirtual Machine (JVM) with lots of agile
and modern language features.
Java 3.0Better Java
What is Groovy?
Groovy is an expressive, dynamic, object oriented language
built for the JavaVirtual Machine (JVM) with lots of agile
and modern language features.
Java 3.0Better Java
• Properties
• Closures
• Optional Typing
• Cool Operators
• Operator Overloading
What is Groovy?
Groovy is an expressive, dynamic, object oriented language
built for the JavaVirtual 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
Groovy is Java
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}"
}
Groovy is Java
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}"
}
javap Studentgroovyc Student
Groovy is Java
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}"
}
javap Studentgroovyc Student
public 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);
}
Groovy is Java
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}"
}
javap Student
But Java is not Groovy
groovyc Student
public 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);
}
Also known as the Groovy JDK
extends 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
Also known as the Groovy JDK
extends 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:devlworkspacesgroovy-classgroovy-language-basics
12/15/2008 02:40 PM <DIR> .
12/15/2008 02:40 PM <DIR> ..
12/09/2008 03:12 AM 373 .classpath
12/02/2008 04:42 AM 588 .project
12/02/2008 04:42 AM <DIR> .settings
12/15/2008 02:42 PM <DIR> bin-groovy
12/09/2008 03:12 AM <DIR> build
12/02/2008 06:58 PM <DIR> src
2 File(s) 961 bytes
6 Dir(s) 30,512,635,904 bytes free
Installing Groovy
1. Download from http://groovy.codehaus.org/Download
• 1.5.7 - Stable Release
• 1.6 beta 2 - Development Release
2. Unzip archive
3. Set GROOVY_HOME environment variable
4. Add %GROOVY_HOME%bin to system path
Depends on JDK 1.4 or greater
Installing Groovy
1. Download from http://groovy.codehaus.org/Download
• 1.5.7 - Stable Release
• 1.6 beta 2 - Development Release
2. Unzip archive
3. Set GROOVY_HOME environment variable
4. Add %GROOVY_HOME%bin to system path
Don’t use the installer!!!
Depends on JDK 1.4 or greater
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 deploy
grails 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>
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
Web Application Framework
Persistable Domains Objects
Controllers
Views (Groovy Server Pages)
Development Environment
Spring
Hibernate (GORM)
SiteMesh
Jetty
HSQLDB
Prototype & Scriptaculous
JUnit
Gant
How do you introduce
Groovy to the
Enterprise?
Unit Testing
Automation
Builds
Prototyping
Lab 1
1.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.
Lab 1
1.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!!!
Strings
Quote
def 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
Multiline
def multiline = """select * from table
where name=value"""
println "${multiline} is a ${multiline.class.name}"
Strings
Quote
def 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
Multiline
def multiline = """select * from table
where name=value"""
println "${multiline} is a ${multiline.class.name}"
Don’t have to escape
Asserts
assert a != null
assert 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.
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
Groovy Methods
Implicitly returns last expression
Access modifier is public by default
def passwordtize(text) {
def password = ''
text.each {password += '*'}
password
}
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
Lists
def authors = []
authors.add 'Chris'
authors += 'Jim'
authors << 'Joseph'
println "Authors:"
authors.each{ println it }
println "type: ${authors.class.name}" // java.util.ArrayList
println "first author is ${authors[0]}"
println "last author is ${authors.last()}"
Array like syntax
Connivence methods and operators
def books = [] as Set
books << "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
Ranges
A list of sequential values.
def numbers = 1..10
assert numbers.size() == 10
numbers.each{ print it }
assert numbers.contains(5)
println()
('a'..'z').each{ print it }
println()
for(i in 'a'..'z') {
print i
}
Ranges
A list of sequential values.
def numbers = 1..10
assert numbers.size() == 10
numbers.each{ print it }
assert numbers.contains(5)
println()
('a'..'z').each{ print it }
println()
for(i in 'a'..'z') {
print i
} 12345678910
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
Maps
An unordered collection of key/value pair where the key is unique.
def map = ['a':'A', 'b':'B', 'c':'C' ]
println map
println map.getClass().name // java.util.LinkedHashMap
println map['a']
println map.'a'
println map.a
println 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.LinkedHashMap
A
A
A
A
A
D
["a":"A", "b":"B", "c":"C", "d":"D",
"e":"E", "f":"F", "g":"G", "h":"H"]
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 set
println "nKeys:"
map.keySet().each { println it }
// Print the value set
println "nValues:"
map.values().each { println it }
def numbers = [1:'one', 2: 'two', 3:'three']
def all = map + numbers
println all
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 Operator
def matcher = 'Groovy is groovy' =~ /(G|g)roovy/
print "Size of matcher is ${matcher.size()} "
println "with elements ${matcher[0]} and ${matcher[1]}."
// Pattern Operator
def 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
}
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 Operator
def matcher = 'Groovy is groovy' =~ /(G|g)roovy/
print "Size of matcher is ${matcher.size()} "
println "with elements ${matcher[0]} and ${matcher[1]}."
// Pattern Operator
def 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 = 2
men
women
Operator Overloading
Operator 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)
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 firstName
String lastName
Person spouse
String toString() { "${lastName}, ${firstName}" }
Person leftShift(partner) {
partner.lastName = lastName
spouse = partner
partner.spouse = this
}
}
def husband = new Person(firstName:"Chris", lastName:"Judd")
def wife = new Person(firstName: "Sue", lastName:"Smith")
// husband and wife get married
husband << wife
println wife
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 firstName
String lastName
Person spouse
String toString() { "${lastName}, ${firstName}" }
Person leftShift(partner) {
partner.lastName = lastName
spouse = partner
partner.spouse = this
}
}
def husband = new Person(firstName:"Chris", lastName:"Judd")
def wife = new Person(firstName: "Sue", lastName:"Smith")
// husband and wife get married
husband << wife
println wife
Judd, Sue
Operators
// Spread Operator
def strings = ['chris', 'jim', 'joseph']
println strings*.getAt(0)
// Elvis Operator
def value = null
println value == null ? "unknown" : value //
Java ternary
println value ?: "unknown" // Elvis Operator
value = "cool"
println value ?: "unknown" // Elvis Operator
// Safe Navigation/Dereference Operator
def string = null
println "String lenth is ${string?.size()}"
Operators
// Spread Operator
def strings = ['chris', 'jim', 'joseph']
println strings*.getAt(0)
// Elvis Operator
def value = null
println value == null ? "unknown" : value //
Java ternary
println value ?: "unknown" // Elvis Operator
value = "cool"
println value ?: "unknown" // Elvis Operator
// Safe Navigation/Dereference Operator
def string = null
println "String lenth is ${string?.size()}"
["c", "j", "j"]
unknown
unknown
cool
String length is null
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
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.
import groovy.sql.Sql
// Create connection
def sql = Sql.newInstance(
/jdbc:derby:C:Program FilesSunJavaDBdemodatabasestoursdb/,
"APP", "APP", "org.apache.derby.jdbc.EmbeddedDriver")
// Execute SQL and iterate over result set
sql.eachRow(
"select * from CITIES where Language='English' order by COUNTRY") {
println "${it.city_name}, ${it.country}"
}
groovy.sql.SQL
Database convenience API
import groovy.sql.Sql
// Create connection
def sql = Sql.newInstance(/jdbc:derby:C:tempblogs;create=true/, "APP",
"APP", "org.apache.derby.jdbc.EmbeddedDriver")
// delete table if previously created
try {
sql.execute("drop table blogs")
} catch(Exception e){}
// create table
sql.execute('''create table blogs (
id varchar(200) not null primary key,
title varchar(500)
)''')
// populate the table
def 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}"
}
// write file
new File(/C:tempstates.txt/).text = "Ohio"
// append file
def file = new File(/C:tempstates.txt/)
file.append("nTexas")
Write File
Read File
// read file
new File(/C:tempstates.txt/).eachLine {line ->
println line
}
// read file into String
def contents = new File(/C:tempstates.txt/).text
println contents
// read file into List
def lines = new File(/C:tempstates.txt/).readLines()
lines.each { println it }
Read URL
def feed = new URL(
"http://juddsolutions.blogspot.com/feeds/posts/default").text
Groovy Builders
A combination of Groovy language features such as meta-
programming, closures and simplified map syntax for
creating nested tree-like structures
Name Description
AntBuilder 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
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, Chris
2 - Shingler, Jim
3 - Nusirat, Joseph
Lab 3
1.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>
Java Web Projects
• JDK
• Web Container/App Server
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
• Build System
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
• Build System
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
• Build System
• Application Stack
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
• Build System
• Application Stack
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
• Build System
• Application Stack
• Persistence Framework
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
• Build System
• Application Stack
• Persistence Framework
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
• Build System
• Application Stack
• Persistence Framework
• Web Framework
What do you need to start a Java?
Java Web Projects
• JDK
• Web Container/App Server
• Build System
• Application Stack
• Persistence Framework
• Web Framework
What do you need to start a Java?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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
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
Grails Architecture
Java Virtual Machine
Java Language Groovy Language
Grails
Application
Libraries
Gant
Spring GORMSiteMesh
DomainControllers Views Services
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.
Starting with the end in mind
• Stage 1 - Conventions, MVC
• Stage 2 -View, Styling, Feeds, Search
• Stage 3 - Security and Users
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.
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
Grails App < 60 secs
• Create a working directory
• From command / shell prompt in that directory type:
grails create-app blog
cd blog
grails run-app
• In a browser goto: http://localhost:8080/blog
Christopher M. Judd
President, Consultant, Author
685 Farrington Drive
Worthington, Ohio 43085
Phone: (614) 378-4119
Email: cjudd@juddsolutions.com
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 – Preset
Central Ohio Java User Group (COJUG)
! Coordinate and advertise monthly meetings on Java related topics.
Consultant! Sept 2004 – Sept 2008
Nationwide 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 2008
gwizMOBILE
! Assisted in developing and architecting a mobile auto trading application and advertisement tool using
Groovy, Grails and J2ME.
Consultant! June 2003 – Sept 2004
CINTAS
! 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.
So What Happened
• grails create-app blog
created application structure &
copied some files
• grails run-app
started up the Jetty application
server and ran the application
App Structure & Conventions
A pretty standard application
structure, . . . you can pretty well
guess the purpose of the files and
directories.
Domain Class
• Blog and BlogEntry domain class:
grails create-domain-class Blog
grails create-domain-class BlogEntry
• What just happened?
Grails created two domain classes (Blog, BlogEntry)
and two unit tests (BlogTest, BlogEntryTest)
Blog
Properties:
• 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}"
}
}
BlogEntry
Properties:
• title, body, dateCreated, and lastUpdated
Methods:
• toString()
class BlogEntry {
String title
String body
Date dateCreated
Date lastUpdated
String toString () {
return "BlogEntry ${id} = ${title}"
}
}
Controller andView
• Create the controller.
grails create-controller Blog
grails 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
Controller andView
• 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
}
GenerateViews and Controllers
• grails generate-all Blog
grails 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)
Lab 4
1.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 theViews and Controllers for Blog and
BlogEntry.
8.Examine the views and controllers.
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 andViews.
• Added DataValidation to the Domain Classes
• Created a 1:M relationship between Blog and
BlogEntry
• Explored generated views and controllers
Setup
Resources
(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
TagLibs
• What is a taglib
• Previous Experiences with taglibs
• Grails Taglibs
• EntriesTagLib
BlogEntryViews
AJAX Preview
• Add Ajax and Destination
• Add BlogEntryController.Preview to use
preview template
• Create BlogEntry Preview Template
Lab 5
1.Copy Resources and Layouts
2.Setup the new BlogEntry list display
3.Redirect Show to use new list view
4.Create EntriesTagLib for title and niceDate
5.Review Print Layout and add Trigger to BlogEntry List
6.Setup new BlogEntry EditView
7.Add Preview Functionality
UrlMapping
• Change the Header and Byline
• blog/list.gsp add to the link
params="[blog: blogInstance.blogid]"
• blog/show.gsp add to the edit link
<input type="hidden" name="blog" value="${blogInstance?.blogid}" />
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"
}
Permalink
• Nice Title Codec
• Add BlogEntry Action DisplayEntry
Insert 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()
}
}
Plugins
A 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/Plugins
http://www.grails.org/The+Plug-in+Developers+Guide
Feeds
• Install the Feeds Plugin
grails install-plugin feeds
• Create a Feed Controller
grails 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
}
}
}
}
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>
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
}
Searchable
• Make Blog Searchable
• http://localhost:8080/blog/seachable
static searchable = {
only = ["blogid", "title", "byline"]
root : false
}
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 andViews.
• Added DataValidation to the Domain Classes
• Created a 1:M relationship between Blog and
BlogEntry
• Explored generated views and controllers
Stage 3 - Security
• Discuss Security topics:
User, Roles, Permissions, Realms
• Define User and Security Requirements
• Discuss Security Options
• Build it out
Security Topics
High Level: User (Subject, Principals) Roles, Permissions, Realms
User / Subject Principals
• Username: jim
•Account Number
• PGP Key
Security Topics
High Level: User (Subject, Principals) Roles, Permissions, Realms
User / Subject Principals
• Username: jim
•Account Number
• PGP Key
Role
• User
•Administrator
Security Topics
High 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
Security Topics
High 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, . . .
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
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%20Plugins
http://www.jsecurity.org
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%20Plugins
http://www.jsecurity.org
Boot Strap Admin & Dilbert
import org.jsecurity.crypto.hash.Sha1Hash
import 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()
Boot Strap Admin & Dilbert
import org.jsecurity.crypto.hash.Sha1Hash
import 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
println "Building Admin User"
def adminUser = new JsecUser(username: "admin",
passwordHash: new Sha1Hash("admin").toHex(),
fullName: "Admin User", email: "admin@admin.com").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: "dilbert@dilbert.com").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 Blog
new Blog(title: "Blog: ${dilbert.fullName}",
blogid: dilbert.username, user: dilbert).save()
}
. . .
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.
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 = 0
if (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 = 0
def blogId = 0
def blog
if (params.id) {
blog = Blog.get(params.id)
userId = blog.user.id
}
role("administrator") || permission("blog:${actionName ?: 'list'}:${userId}")
}}}}
http://grails.org/Filters
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 = 0
if (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 = 0
def blogId = 0
def blog
if (params.id) {
blog = Blog.get(params.id)
userId = blog.user.id
}
role("administrator") || permission("blog:${actionName ?: 'list'}:${userId}")
}}}}
http://grails.org/Filters
Enhance UserViews. . .
<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)
What’s Missing
• When creating a blog entry the user shouldn’t
have to specify which user the blog is related to.
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)
}
}
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 JsecUserViews and Controller
• User SecurityFilters to enforce Roles and Permissions
• Created ability to Logout, Login / Register
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)
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