Advertisement
Advertisement

More Related Content

Advertisement

Gg Code Mash2009 20090106

  1. Chris Judd & Jim Shingler CodeMash 2009 Percompile &
  2. Christopher Judd President/Consultant of leader Creator of open source projects FallME and Fiddle
  3. Jim Shingler Chief Technical Architect President of Genuine Solutions Co-Creator Open Source Project of FallME Co-Author of Beginning Groovy and Grails
  4. 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
  5. Example Code http://github.com/jshingler/codemash2009precompile/tree/master
  6. 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
  7. Java Platform
  8. What is Java?
  9. What is Java?
  10. What is Java? Virtual Machine
  11. What is Java? Virtual Machine API/Library
  12. What is Java? Virtual Machine API/Library Java Language
  13. What is Java? Virtual Machine API/Library Java LanguageJavaScript
  14. What is Java? Virtual Machine API/Library Java LanguageJavaScript Groovy
  15. What is Java? Virtual Machine API/Library Java LanguageJavaScript Groovy Ruby
  16. What is Java? Virtual Machine API/Library Java LanguageJavaScript Groovy Ruby Python
  17. Language Stack
  18. Java Language Language Stack System (static)
  19. Java Language Language Stack Groovy System (static) Application (Dynamic)
  20. Java Language Language Stack Groovy Domain Specific Languages System (static) Application (Dynamic) Domain
  21. Groovy By Example
  22. 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 srcmainjavacomjuddsolutionsgroovybasicsStudent.java java -cp classes com.juddsolutions.groovy.basics.Student Student.class Students: Judd, Chris Shingler, Jim Nusairat, Joseph Java Example
  23. 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 srcmainjavacomjuddsolutionsgroovybasicsStudents.groovy Students: Judd, Chris Shingler, Jim Nusairat, Joseph
  24. Congratulations you are a programmer
  25. 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.
  26. Copy/Paste Compatibility
  27. idiomatic
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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()); } } }
  37. 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()); } } }
  38. Groovy Basics
  39. 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.
  40. 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
  41. 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
  42. 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
  43. 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
  44. def groovy = [] groovy << java groovy << ruby groovy << python groovy << smalltalk groovy << dynamic groovy << scripting groovy << agile
  45. Groovy is Java
  46. 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}" }
  47. 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
  48. 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); }
  49. 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); }
  50. Dynamic Static StrongWeak C++ JavaScript Scala
  51. Dynamic Static StrongWeak C++ JavaScript Scala Groovy is: • Strongly typed • Dynamically typed • Optionally typed • Duck typed
  52. 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
  53. 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
  54. 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
  55. 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
  56. Running Groovy scripts shell console groovyConsole groovysh groovy
  57. just include groovy-all-<version>.jar in classpath Deploying
  58. Note: Quality of Groovy support is represented by size
  59. 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>
  60. 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
  61. Web Application Framework Persistable Domains Objects Controllers Views (Groovy Server Pages) Development Environment Spring Hibernate (GORM) SiteMesh Jetty HSQLDB Prototype & Scriptaculous JUnit Gant
  62. Griffon Swing Application Framework
  63. Griffon Swing Application Framework
  64. How do you introduce Groovy to the Enterprise? Unit Testing Automation Builds Prototyping
  65. 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.
  66. 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!!!
  67. Language Basics
  68. 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}"
  69. 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
  70. GString def datetime = "Datetime: ${new Date()}" println "${datetime}" org.codehaus.groovy.runtime.GStringImpl String interpolation
  71. 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.
  72. 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
  73. Groovy Methods Implicitly returns last expression Access modifier is public by default def passwordtize(text) { def password = '' text.each {password += '*'} password }
  74. 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
  75. 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
  76. 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 }
  77. 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
  78. 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
  79. 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"]
  80. 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
  81. 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 }
  82. 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
  83. 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)
  84. 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
  85. 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
  86. 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()}"
  87. 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
  88. 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
  89. 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.
  90. Groovy Libraries
  91. Basic unit testing
  92. Groovy Unit Tests Extend 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') } }
  93. Groovy Unit Tests Extend 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
  94. Running Unit Tests Runs in standard JUnit tools like Eclipse and Ant
  95. Running Unit Tests Groovy command-line is unit test aware
  96. Database
  97. 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
  98. 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}" }
  99. I/O
  100. // write file new File(/C:tempstates.txt/).text = "Ohio" // append file def file = new File(/C:tempstates.txt/) file.append("nTexas") Write File
  101. 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 }
  102. Read URL def feed = new URL( "http://juddsolutions.blogspot.com/feeds/posts/default").text
  103. Builders
  104. 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
  105. 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
  106. 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>
  107. XML Parsing
  108. 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}" }
  109. 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
  110. 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>
  111. Modern Java Web Development
  112. Java Web Projects What do you need to start a Java?
  113. Java Web Projects • JDK What do you need to start a Java?
  114. Java Web Projects • JDK • Web Container/App Server What do you need to start a Java?
  115. Java Web Projects • JDK • Web Container/App Server What do you need to start a Java?
  116. Java Web Projects • JDK • Web Container/App Server • Build System What do you need to start a Java?
  117. Java Web Projects • JDK • Web Container/App Server • Build System What do you need to start a Java?
  118. Java Web Projects • JDK • Web Container/App Server • Build System • Application Stack What do you need to start a Java?
  119. Java Web Projects • JDK • Web Container/App Server • Build System • Application Stack What do you need to start a Java?
  120. Java Web Projects • JDK • Web Container/App Server • Build System • Application Stack • Persistence Framework What do you need to start a Java?
  121. Java Web Projects • JDK • Web Container/App Server • Build System • Application Stack • Persistence Framework What do you need to start a Java?
  122. Java Web Projects • JDK • Web Container/App Server • Build System • Application Stack • Persistence Framework • Web Framework What do you need to start a Java?
  123. Java Web Projects • JDK • Web Container/App Server • Build System • Application Stack • Persistence Framework • Web Framework What do you need to start a Java?
  124. 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?
  125. 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?
  126. 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?
  127. 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?
  128. 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?
  129. 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?
  130. 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?
  131. 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?
  132. 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?
  133. 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?
  134. 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?
  135. Java Development Cycle
  136. Code Java Development Cycle Takes too much time and is too complicated Compile Package Deploy Debug Test
  137. Conclusion Java Web and J2EE development is too complicated and not very agile.
  138. A Solution
  139. A Solution &
  140. What is Grails
  141. 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
  142. 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
  143. Grails Architecture Java Virtual Machine Java Language Groovy Language Grails Application Libraries Gant Spring GORMSiteMesh DomainControllers Views Services
  144. MVC Application Design Controller GSP Domain DB
  145. Service Applications Controller GSP Domain •Service DB Domain •Service
  146. Default Development Environment JVM Jetty (Web Container) Controller GSP Domain HSQL DB
  147. Production Environment JVM Web Container/App Server Controller GSP Domain DB WAR
  148. 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.
  149. Starting with the end in mind
  150. Starting with the end in mind • Stage 1 - Conventions, MVC • Stage 2 -View, Styling, Feeds, Search • Stage 3 - Security and Users
  151. 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.
  152. Verify Install • at a command / shell prompt type grails
  153. 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
  154. 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
  155. Grails App < 60 secs
  156. Congratulations you are a programmer
  157. 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.
  158. 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
  159. App Structure & Conventions A pretty standard application structure, . . . you can pretty well guess the purpose of the files and directories.
  160. Grails commands
  161. 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)
  162. 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}" } }
  163. 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}" } }
  164. 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
  165. 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 }
  166. Controller andView
  167. Controller andView
  168. What’s Missing
  169. What’s Missing • Data validity
  170. What’s Missing • Data validity • Relationships
  171. What’s Missing • Data validity • Relationships • Not Pretty (Stage 2)
  172. What’s Missing • Data validity • Relationships • Not Pretty (Stage 2) • User & Security (Stage 3)
  173. 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}" } } DataValidation (Constraints) http://www.grails.org/Validation http://www.grails.org/Validation+Reference
  174. Relationships (GORM) http://www.grails.org/GORM http://www.grails.org/GORM+-+Defining+relationships
  175. 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/GORM http://www.grails.org/GORM+-+Defining+relationships
  176. 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/GORM http://www.grails.org/GORM+-+Defining+relationships
  177. 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 settings environments { 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" } } }
  178. GenerateViews and Controllers
  179. GenerateViews and Controllers • grails generate-all Blog grails generate-all BlogEntry
  180. 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)
  181. 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
  182. 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.
  183. 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
  184. Stage 2 -View Styles • Layouts • TagLibs • Preview (AJAX) • URL Mappings • Feeds • Search
  185. Layout
  186. Layout Header Sidebar Footer Body
  187. 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
  188. TagLibs • What is a taglib • Previous Experiences with taglibs • Grails Taglibs • EntriesTagLib
  189. BlogEntryViews List • BlogEntryList.gsp • Redirect BlogEntryController. Show to single list (Reuse) • EntriesTagLib - Nice Dates
  190. BlogEntryViews Print • Add Print output. Need a way to trigger print layout No Header, Footer, or sidebar
  191. BlogEntryViews Edit • BlogEntryEdit.gsp
  192. BlogEntryViews AJAX Preview • Add Ajax and Destination • Add BlogEntryController.Preview to use preview template • Create BlogEntry Preview Template
  193. 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
  194. 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') } }
  195. 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}" />
  196. 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" }
  197. 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() } }
  198. 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
  199. 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 } } } }
  200. 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>
  201. 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 }
  202. Searchable • Make Blog Searchable • http://localhost:8080/blog/seachable static searchable = { only = ["blogid", "title", "byline"] root : false }
  203. 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>
  204. 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 Feed 4.Setup Search Functionality
  205. 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
  206. Stage 3 - Security • Discuss Security topics: User, Roles, Permissions, Realms • Define User and Security Requirements • Discuss Security Options • Build it out
  207. Security Topics High Level: User (Subject, Principals) Roles, Permissions, Realms
  208. Security Topics High Level: User (Subject, Principals) Roles, Permissions, Realms User / Subject
  209. Security Topics High Level: User (Subject, Principals) Roles, Permissions, Realms User / Subject Principals • Username: jim •Account Number • PGP Key
  210. Security Topics High Level: User (Subject, Principals) Roles, Permissions, Realms User / Subject Principals • Username: jim •Account Number • PGP Key Role • User •Administrator
  211. 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
  212. 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, . . .
  213. 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
  214. 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
  215. 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
  216. Security Relationships
  217. JSecurity Plugins • List available plugins: grails list-plugins • Install the JSecurity plugin grails install-plugin jsecurity 0.4-SNAPSHOT • Setup JSecurity grails quick-start • Let’s Explore Domain Classes,Views,Tag Libs http://www.grails.org/JSecurity+Plugin http://www.grails.org/JSecurity+Plugin+-+Quick+Start
  218. JSecurity Plugins • List available plugins: grails list-plugins • Install the JSecurity plugin grails install-plugin jsecurity 0.4-SNAPSHOT • Setup JSecurity grails quick-start • Let’s Explore Domain Classes,Views,Tag Libs http://www.grails.org/JSecurity+Plugin http://www.grails.org/JSecurity+Plugin+-+Quick+Start VERY IMPORTANT: We need this specific version.
  219. Enhancing the User Class • User should have a name, email, password
  220. 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}" } }
  221. 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}" } }
  222. 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}" } }
  223. What’s missing • No Predefined Admin User
  224. 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()
  225. 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
  226. 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() } . . .
  227. What’s Missing • Ability to create a new User
  228. Views & Controller for JSecUser
  229. Views & Controller for JSecUser • Do you remember how?
  230. Views & Controller for JSecUser • Do you remember how? •grails generate-all JSecUser
  231. Views & Controller for JSecUser • Do you remember how? •grails generate-all JSecUser
  232. What’s missing • Password should be hashed • Auto create blog when new user saved
  233. JsecUserController Enhancement • Hash the password • On Save automatically create blog
  234. JsecUserController Enhancement • Hash the password • On Save automatically create blog import 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 Blog new 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]) } } . . . }
  235. What’s Missing • Roles and Permissions aren’t being enforced.
  236. 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.
  237. 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
  238. 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
  239. 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]) } }
  240. 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
  241. What’s Missing • User views (List, Show, Edit, Create) shouldn’t show the password in the clear • Password label needs to be adjusted.
  242. 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> . . .
  243. 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)
  244. What’s Missing • When creating a blog entry the user shouldn’t have to specify which user the blog is related to.
  245. 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) } }
  246. Update Url Mapping "/$blog/" { controller = "blogEntry" action = "homePage" }
  247. What’s Missing • Need a way to logout • Should be able to Register a new user from the login screen.
  248. 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
  249. Congratulations!!! And to think, this morning you didn’t know Groovy and Grails.
  250. 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
  251. 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)
  252. 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
  253. 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
  254. Conclusion • Blog: http://juddsolutions.blogspot.com http://jshingler.blogspot.com • Email: CJudd@JuddSolutions.com ShinglerJim@gmail.com • LinkedIn: http://www.linkedin.com/in/christophermjudd http://www.linkedin.com/in/jimshingler • Twitter: http://www.twitter.com/jshingler ThankYou for your time
Advertisement