Date post: | 25-May-2015 |
Category: |
Entertainment & Humor |
Upload: | jim-shingler |
View: | 34,495 times |
Download: | 1 times |
Chris Judd & Jim Shingler
CodeMash 2009 Percompile
&
Christopher JuddPresident/Consultant of
leader
Creator of open source projects FallME and Fiddle
Jim ShinglerChief 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 GrailsCreate and Run Groovy ScriptsUnderstand basic Groovy Language FeaturesCreate a Scaffolded Web ApplicationApply a Custom Layout and StylingInstall and use PluginsEnable Security
Example Codehttp://github.com/jshingler/codemash2009precompile/tree/master
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
Java Platform
What is Java?
What is Java?
What is Java?
Virtual Machine
What is Java?
Virtual Machine
API/Library
What is Java?
Virtual Machine
API/Library
Java Language
What is Java?
Virtual Machine
API/Library
Java LanguageJavaScript
What is Java?
Virtual Machine
API/Library
Java LanguageJavaScript Groovy
What is Java?
Virtual Machine
API/Library
Java LanguageJavaScript Groovy Ruby
What is Java?
Virtual Machine
API/Library
Java LanguageJavaScript Groovy Ruby Python
Language Stack
Java Language
Language Stack
System (static)
Java Language
Language Stack
Groovy
System (static)
Application (Dynamic)
Java Language
Language Stack
Groovy
Domain Specific Languages
System (static)
Application (Dynamic)
Domain
Groovy By Example
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
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
Congratulationsyou are a
programmer
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.
Copy/Paste Compatibility
idiomatic
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 constructorRemove 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 methodsFlexible 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 methodsFlexible 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()); } }}
Groovy Basics
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.
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
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
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
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
def groovy = []groovy << javagroovy << rubygroovy << pythongroovy << smalltalkgroovy << dynamicgroovy << scriptinggroovy << agile
Groovy is Java
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}"}
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
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);}
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);}
Dynamic
Static
StrongWeakC++
JavaScript
Scala
Dynamic
Static
StrongWeakC++
JavaScript
Scala
Groovy is:• Strongly typed• Dynamically typed• Optionally typed• Duck typed
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
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
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
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
Running Groovy
scripts
shell
console groovyConsole
groovysh
groovy
just include groovy-all-<version>.jar in classpath
Deploying
Note: Quality of Groovy support is represented by size
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>
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 FrameworkPersistable Domains ObjectsControllersViews (Groovy Server Pages)
Development EnvironmentSpringHibernate (GORM)SiteMeshJettyHSQLDBPrototype & ScriptaculousJUnitGant
Griffon
Swing Application Framework
Griffon
Swing Application Framework
How do you introduceGroovy to the Enterprise?
Unit TestingAutomationBuildsPrototyping
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.
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!!!
Language Basics
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}"
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 \
GString
def datetime = "Datetime: ${new Date()}"println "${datetime}"
org.codehaus.groovy.runtime.GStringImpl
String interpolation
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.
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 expressionAccess 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.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
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}
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
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
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"]
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
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}
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
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)
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
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
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()}"
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
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.
Groovy Libraries
Basic unit testing
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') } }
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
Running Unit Tests
Runs in standard JUnit tools like Eclipse and Ant
Running Unit Tests
Groovy command-line is unit test aware
Database
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
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}"}
I/O
// write filenew File(/C:\temp\states.txt/).text = "Ohio"
// append filedef file = new File(/C:\temp\states.txt/)file.append("\nTexas")
Write File
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 }
Read URL
def feed = new URL( "http://juddsolutions.blogspot.com/feeds/posts/default").text
Builders
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
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
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>
XML Parsing
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}"}
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
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>
Modern Java Web Development
Java Web ProjectsWhat do you need to start a Java?
Java Web Projects
• JDK
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
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?
Java Development Cycle
Code
Java Development Cycle
Takes too much time and is too complicated
Compile
Package
Deploy
Debug
Test
Conclusion
Java Web and J2EE development is too complicated and not very agile.
A Solution
A Solution
&
What is Grails
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
Gan
t
Spring GORMSiteMesh
DomainControllers Views Services
MVC Application Design
Controller
GSP
Dom
ain DB
Service Applications
Controller
GSP
Dom
ain•Service DB
Dom
ain
•Service
Default Development Environment
JVMJetty (Web Container)
Controller
GSP
Dom
ain
HSQLDB
Production Environment
JVMWeb Container/App Server
Controller
GSP
Dom
ain DB
WAR
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
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.
Verify Install
• at a command / shell prompt type grails
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 blogcd bloggrails run-app
• In a browser goto: http://localhost:8080/blog
Grails App < 60 secs
Congratulationsyou are a
programmer
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.
So What Happened
• grails create-app blogcreated application structure &copied some files
• grails run-appstarted up the Jetty applicationserver and ran the application
App Structure & Conventions
A pretty standard application structure, . . . you can pretty well guess the purpose of the files and
directories.
Grails commands
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)
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}" }}
BlogEntryProperties:
• title, body, dateCreated, and lastUpdated
Methods:
• toString() class BlogEntry { String title String body Date dateCreated Date lastUpdated
String toString () { return "BlogEntry ${id} = ${title}" }}
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
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}
Controller and View
Controller and View
What’s Missing
What’s Missing
• Data validity
What’s Missing
• Data validity
• Relationships
What’s Missing
• Data validity
• Relationships
• Not Pretty (Stage 2)
What’s Missing
• Data validity
• Relationships
• Not Pretty (Stage 2)
• User & Security (Stage 3)
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
Relationships (GORM)
http://www.grails.org/GORMhttp://www.grails.org/GORM+-+Defining+relationships
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
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
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" } }}
Generate Views and Controllers
Generate Views and Controllers
• grails generate-all Bloggrails generate-all BlogEntry
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)
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
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.
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
Stage 2 - View Styles• Layouts
• TagLibs
• Preview (AJAX)
• URL Mappings
• Feeds
• Search
Layout
Layout
Header
Sidebar
Footer
Body
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
TagLibs
• What is a taglib
• Previous Experiences with taglibs
• Grails Taglibs
• EntriesTagLib
BlogEntry ViewsList
• BlogEntryList.gsp
• Redirect BlogEntryController. Show to single list (Reuse)
• EntriesTagLib - Nice Dates
BlogEntry ViewsPrint
• Add Print output.Need a way to trigger print layoutNo Header, Footer, or sidebar
BlogEntry ViewsEdit
• BlogEntryEdit.gsp
BlogEntry ViewsAJAX Preview
• Add Ajax and Destination
• Add BlogEntryController.Preview to use preview template
• Create BlogEntry Preview Template
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
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') }}
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}" />
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 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() }}
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
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 } } } }
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 }
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>
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
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
Stage 3 - Security
• Discuss Security topics: User, Roles, Permissions, Realms
• Define User and Security Requirements
• Discuss Security Options
• Build it out
Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms
Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms
User / Subject
Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms
User / Subject Principals• Username: jim• Account Number• PGP Key
Security TopicsHigh Level: User (Subject, Principals) Roles, Permissions, Realms
User / Subject Principals• Username: jim• Account Number• PGP Key
Role• User• Administrator
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
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, . . .
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%20Pluginshttp://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%20Pluginshttp://www.jsecurity.org
Security Relationships
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
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.
Enhancing the User Class• User should have a name, email, password
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}" }}
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}" }}
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}" }}
What’s missing
• No Predefined Admin User
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()
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
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() }
. . .
What’s Missing
• Ability to create a new User
Views & Controller for JSecUser
Views & Controller for JSecUser• Do you remember how?
Views & Controller for JSecUser• Do you remember how?
• grails generate-all JSecUser
Views & Controller for JSecUser• Do you remember how?
• grails generate-all JSecUser
What’s missing
• Password should be hashed
• Auto create blog when new user saved
JsecUserController Enhancement• Hash the password
• On Save automatically create blog
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]) } }
. . . }
What’s Missing
• Roles and Permissions aren’t being enforced.
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 = 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
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
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]) } }
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
What’s Missing
• User views (List, Show, Edit, Create) shouldn’t show the password in the clear
• Password label needs to be adjusted.
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>
. . .
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)
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) } }
Update Url Mapping
"/$blog/" { controller = "blogEntry" action = "homePage" }
What’s Missing
• Need a way to logout
• Should be able to Register a new user from the login screen.
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
Congratulations!!!
And to think, this morning you didn’t know Groovy and Grails.
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
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
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
Conclusion
• Blog: http://juddsolutions.blogspot.comhttp://jshingler.blogspot.com
• Email: [email protected]@gmail.com
• LinkedIn: http://www.linkedin.com/in/christophermjuddhttp://www.linkedin.com/in/jimshingler
• Twitter: http://www.twitter.com/jshingler
Thank You for your time