59
Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 1 © Copyright 2010, Software Alchemy Getting Groovy with Grails Bryan Basham Software Alchemy [email protected] http://www.linkedin.com/in/SoftwareAlchemist Grails Architecture Getting Groovy w/ Grails Domain Modeling Getting Started

Getting Groovy With Grails

Embed Size (px)

DESCRIPTION

Grails is an advanced web application development framework focused on rapid prototyping. It uses the Groovy language and runs on a standard JVM. This presentation will provide a hands-on introduction to using Grails and then provides examples of Grails applications. Grails is based upon a plugin architecture and several significant plugins will be described, such as the Spring Security plugin for web authentication and authorization.

Citation preview

Page 1: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 1

© Copyright 2010, Software Alchemy

Getting Groovy with Grails

Bryan BashamSoftware Alchemy

[email protected]

http://www.linkedin.com/in/SoftwareAlchemist

GrailsArchitecture

GettingGroovy w/

Grails

DomainModeling

GettingStarted

Page 2: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 2

© Copyright 2010, Software Alchemy

GrailsArchitecture

DomainModeling

GettingGroovy w/

Grails

InstallGrails

CreateApp

CreateEntity GUI Scaffolding

BasicDomainModeling

GettingStarted

Getting Started

Page 3: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 3

© Copyright 2010, Software Alchemy

Install Grails

● Download Grails at http://www.grails.org/ – I am using version 1.3.4 for this tech talk

● Unpack ZIP file on computer● Set GRAILS_HOME environment variable● Add $GRAILS_HOME/bin to PATH

Page 4: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 4

© Copyright 2010, Software Alchemy

Create a Grails App

● Execute command, eg:grails create-app MyApp

Page 5: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 5

© Copyright 2010, Software Alchemy

MyApp Use Cases

List employees

Update employee

Create employee

Retrieve employee

Delete employee

Classic CRUDOperations

Page 6: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 6

© Copyright 2010, Software Alchemy

Create a Domain Entity

● Create the Employee domain class, eg:grails create-domain-class com.example.Employee

package com.example

class Employee {

String firstName String lastName Integer age

static constraints = { }}

«entity»Employee

{from com.example}

firstName : StringlastName : Stringage : Integer

Page 7: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 7

© Copyright 2010, Software Alchemy

Create a GUI Controller

● Create the Employee controller class, eg:grails create-controller com.example.Employee

package com.example

class EmployeeController { def scaffold = Employee}

● Grails scaffolding provides all basic CRUD operations and GUI Views

Page 8: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 8

© Copyright 2010, Software Alchemy

Default GUI Scaffolding

Page 9: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 9

© Copyright 2010, Software Alchemy

Default GUI Scaffolding (2)

Page 10: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 10

© Copyright 2010, Software Alchemy

Default GUI Scaffolding (3)

Page 11: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 11

© Copyright 2010, Software Alchemy

Behind the Looking Glass

● Create the Employee GUI controller class:grails generate-controller com.example.Employee

class EmployeeController { def index = { redirect(action: "list", params: params) } def list = { params.max = Math.min(params.max ? params.int('max') : 10, 100) [employeeList: Employee.list(params), employeeTotal: Employee.count()] } def save = { def employee = new Employee(params) if (employee.save(flush: true)) { flash.message = "Employee ${employee.id} created." redirect(action: "show", id: employee.id) } else { render(view: "create", model: [employeeInstance: employee]) } }

Page 12: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 12

© Copyright 2010, Software Alchemy

Behind the Looking Glass (2)

● Create the Employee GUI views:grails generate-views com.example.Employee

Page 13: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 13

© Copyright 2010, Software Alchemy

Behind the Looking Glass (3)

● The list.gsp View: <table> <tbody> <g:each in="${employeeList}" status="i" var="employee"> <tr class="${(i % 2) == 0 ? 'odd' : 'even'}"> <td><g:link action="show" id="${employee.id}"> ${fieldValue(bean: employee, field: "id")}</g:link> </td> <td>${fieldValue(bean: employee, field: "age")}</td> <td>${fieldValue(bean: employee, field: "firstName")}</td> <td>${fieldValue(bean: employee, field: "lastName")}</td> </tr> </g:each> </tbody></table>

Page 14: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 14

© Copyright 2010, Software Alchemy

Behind the Looking Glass (4)

● The create.gsp View: <g:form action="save" > <table> <tbody>

<tr class="prop"> <td valign="top" class="name"> <label for="age"><g:message code="employee.age.label" default="Age" /></label> </td> <td valign="top" class="value ${hasErrors(bean: employeeInstance, field: 'age', 'errors')}"> <g:textField name="age" value="${fieldValue(bean: employeeInstance, field: 'age')}" /> </td> </tr>

...

</tbody> </table></g:form>

Page 15: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 15

© Copyright 2010, Software Alchemy

A Simple Relationship

class Employee {

String firstName String lastName Integer age Department department

static constraints = { }}

«entity»Department

{from com.example}

name : String

«entity»Employee

{from com.example}

firstName : StringlastName : Stringage : Integer

department

10..*

class Department {

String name

static constraints = { }}

Page 16: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 16

© Copyright 2010, Software Alchemy

Create GUI components

● Create Department GUIs and recreate Employee GUIs

A drop-down list of department objects, but the names are weird.

Page 17: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 17

© Copyright 2010, Software Alchemy

Fix Department Display

● Add a simple toString method:class Department {

String name

String toString() { name }

static constraints = { }}

The toString method is used to create a useful display name. You could also create custom GSP code for the drop-down list widget.

Page 18: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 18

© Copyright 2010, Software Alchemy

GrailsArchitecture

Conv/Config

Buildtools

Web techPlugins

Groovy

GettingGroovy w/

Grails

DomainModeling

InstallGrails

CreateApp

CreateEntity GUI Scaffolding

BasicDomainModeling

GettingStarted

Grails Architecture

Page 19: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 19

© Copyright 2010, Software Alchemy

Grails Technology Stack

The Java Virtual Machine

Groovy

Java Lang / JRE JDK

Grails

JavaEE Spring Hibernate SiteMesh

Plugins...

Your Grails Application

Page 20: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 20

© Copyright 2010, Software Alchemy

Groovy Quick Look

● Groovy is a scripting langage on top of Java● Syntax for lists and maps:

– [1, 2, 3]

– [foo:1, bar:2, baz:3]

● Closures:– [1, 2, 3].collect { it * it } => [1, 4, 9]

● Fancy Strings:– 'foo' is a Java String– “foo is ${map.foo}” is a GString

Page 21: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 21

© Copyright 2010, Software Alchemy

Groovy Quick Look (2)

● Groovy classes are JavaBeansclass Employee { String name Integer age}

● Setter/Getters are auto created unless specified:

class Employee { String name Date dateOfBirth Integer getAge() { /* calc age from DoB */ }}

Page 22: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 22

© Copyright 2010, Software Alchemy

Convention over Configuration

● Configuration is kept to a bare minimum● Convention abounds:

– Entities– Controllers and URL patterns– Services and dependency injection– Tag libraries– Scaffolding– and much more

Page 23: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 23

© Copyright 2010, Software Alchemy

Logging

● Configure logging in grails-app/conf/ Config.groovy file:

log4j = { root { info 'stdout' additivity = true } info 'com.example' // more configuration snipped}

● Log objects automatically available:if (employeeInstance.save(flush: true)) { log.info "Employee ${employeeInstance.id} created." redirect(action: "show", id: employeeInstance.id)}

Page 24: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 24

© Copyright 2010, Software Alchemy

Data Sources

● Configured in the grails-app/conf/ DataSource.groovy file

● Database driver JAR file configured in the grails-app/conf/BuildConfig.groovy file

● Must create the database before using, but schema creation is handled by Grails

– Use create-drop to create the DB on every run– This option destroys any data stored– Typically used during rapid prototyping

Page 25: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 25

© Copyright 2010, Software Alchemy

Example: MySQL

● DataSource.groovy:environments { development { dataSource { dbCreate = "create-drop" // one of 'create', 'create-drop','update' url = "jdbc:mysql://localhost:8889/my-app-db" driverClassName = "com.mysql.jdbc.Driver" username = "root" password = "root" } }

● BuildConfig.groovy: dependencies { runtime 'mysql:mysql-connector-java:5.1.12' }

Page 26: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 26

© Copyright 2010, Software Alchemy

Pre-populate DB

● Pre-populate the database using the grails-app/conf/BootStrap.groovy file:

import com.example.Department;

class BootStrap {

def init = { servletContext -> if ( Department.count() == 0 ) { new Department(name:"Accounting").save() new Department(name:"Marketing").save() new Department(name:"Development").save() new Department(name:"Sales").save() } } def destroy = { }}

The count() method is like the SQL statement:SELECT count(*) FROM department

The save() method is like an SQL INSERT statement.

Page 27: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 27

© Copyright 2010, Software Alchemy

Eclipse Integration

● Install the Groovy plugin:http://dist.springsource.org/release/GRECLIPSE/e3.6/

● Groovy support in Eclipse is spotty but workable

– Hard to find all necessary libraries– No obvious access to source or javadocs– Debugging Grails apps is very difficult

● Maven helps with some of these issues

Page 28: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 28

© Copyright 2010, Software Alchemy

Maven Integration

● Creating a Grails app with Maven 2:mvn archetype:generate -DarchetypeGroupId=org.grails \

-DarchetypeArtifactId=grails-maven-archetype \-DarchetypeVersion=1.3.4 \-DgroupId=com.example -Dversion=0.1 -DartifactId=MyMavenApp

cd MyMavenApp/

mvn initialize

● Supporting Eclipse:mvn -DdownloadSources=true -DdownloadJavadocs=true \

eclipse:eclipse

Page 29: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 29

© Copyright 2010, Software Alchemy

Ant Integration

● You can use Grails scripts in an Ant script● You can use Ant tasks in your own Grails

scripts, Example:ant.property(file:"${basedir}/application.properties")def appName = "${Ant.project.properties['app.name']}"def appVersion = "${Ant.project.properties['app.version']}"def appPath = "${appName}-${appVersion}"

target(main: "Create an archive of the complete project source.") { ant.zip(destfile: "../${appPath}-dist.zip") { zipfileset(dir:"${basedir}", prefix:"${appPath}") { exclude(name:"target/**") exclude(name:"web-app/WEB-INF/classes/**") } }}

setDefaultTarget(main)

Page 30: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 30

© Copyright 2010, Software Alchemy

External Deployment

● Build a WAR file using this command:grails dev war

● Deploy to your JavaEE compilant web container

– WAR includes all Groovy and Grails JARs– WAR includes all infrastructure JARs– WAR includes DB driver JAR– WAR includes all plugins

Page 31: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 31

© Copyright 2010, Software Alchemy

Web Technologies

● Controllers● Views: GSPs● Tag libraries● Filters

Page 32: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 32

© Copyright 2010, Software Alchemy

Controllers

● Controllers are Groovy classes that reside in the grails-app/controllers source directory

● Method names map to URL patterns, eg: http://localhost:8080/MyApp/employee/list

– Maps to EmployeeController and list method● View selection:

– Use render to render a specific View component– Use redirect to tell the browser to redirect– Return a model Map to render this method's

View, eg. list action renders list.gsp

Page 33: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 33

© Copyright 2010, Software Alchemy

Views: GSPs

● Very much like JSPs but uses Groovy as the scripting language; cavet: don't script!

● Use custom tags for view logic– Large built-in library– Easy to create your own

● GSP attributes:– standard JSP attribute scopes plus flash scope– named values in the action method's model Map

● Grails uses SiteMesh for layout control

Page 34: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 34

© Copyright 2010, Software Alchemy

Tag Libraries

● Tag libraries are Groovy classes that reside in the grails-app/taglib source directory

● Each method provides a custom tag, eg:class MyTags { def isAdmin = { attrs, body -> def user = attrs['user'] if ( user != null && checkUserPrivs(user) ) { out << body() } }}

● No configuration required● Automatically available in all GSPs, eg:<g:isAdmin user=”${theUser}”>ADMIN CONTENT</g:isAdmin>

Page 35: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 35

© Copyright 2010, Software Alchemy

Request Filters

● Filters are Groovy classes that reside in the grails-app/conf source directory that end in Filters

class SecurityFilters { def filters = { loginCheck(controller:'*', action:'*') { before = { if (params.controller == null) { redirect(action:'login') return true } else if(!session.user && !actionName.equals('login')) { redirect(action:'login') return false } } } }}

Page 36: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 36

© Copyright 2010, Software Alchemy

Transactions and Services

● Controller actions can be made transactional– Use Spring SessionFactory injection– Or use the withTransaction method

● Service components are a better solution– All classes that reside in the grails-

app/services source directory– Use the def transactional = true for Spring

transaction AOP wrapping– Inject the service into the controller:

def storeService // auto-injects StoreService

Page 37: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 37

© Copyright 2010, Software Alchemy

Plugins

● Grails is a framework built on plugins● Default plugins:

– Hibernate: the Grails ORM (aka GORM)– Tomcat: the Grails default runtime environment

● Hundreds of additional plugins– Security (40)– Services (117)– JavaScript frameworks (74)– many more...

Page 38: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 38

© Copyright 2010, Software Alchemy

Spring Security Plugin

● Install the plugin:grails install-plugin spring-security-core

● Create the User and Role entities:grails s2-quickstart com.example.security User Role

«javaPackage»com.example.security

«entity»Role

authority : String

«entity»User

username : Stringpassword : Stringenabled : boolean role

1

0..*

«entity»UserRoleuser

1

/+authorities

Page 39: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 39

© Copyright 2010, Software Alchemy

BootStrap Roles and Users

import com.example.security.*;class BootStrap { def springSecurityService def init = { servletContext -> // Define user role's def hrRepRole = Role.findByAuthority('ROLE_HR_REP') ?: new Role(authority: 'ROLE_HR_REP').save(failOnError: true) def hrMgrRole = Role.findByAuthority('ROLE_HR_MANAGER') ?: new Role(authority: 'ROLE_HR_MANAGER').save(failOnError: true) def adminRole = Role.findByAuthority('ROLE_ADMIN') ?: new Role(authority: 'ROLE_ADMIN').save(failOnError: true) // a few users: def adminUser = User.findByUsername('admin') ?: new User( username: 'admin', password: springSecurityService.encodePassword('admin'), enabled: true).save(failOnError: true) if (!adminUser.authorities.contains(adminRole)) { UserRole.create adminUser, adminRole } // and so on }}

Page 40: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 40

© Copyright 2010, Software Alchemy

Define Security Constraints

● Use annotations on controller actions, eg:import grails.plugins.springsecurity.Securedclass DepartmentController { @Secured(['ROLE_HR_MANAGER', 'ROLE_HR_REP']) def list = { ... } @Secured(['ROLE_HR_MANAGER']) def create = { ... } @Secured(['ROLE_ADMIN']) def delete = { ... }}

● Or static URL rules in the Config.groovy file● Or store the rules in the database

Page 41: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 41

© Copyright 2010, Software Alchemy

GrailsArchitecture

Conv/Config

Buildtools

Web techPlugins

Groovy

GettingGroovy w/

Grails

InstallGrails

CreateApp

CreateEntity GUI Scaffolding

BasicDomainModeling

GettingStarted

DomainModeling

Relationships

Validation

Enumeratedtypes

Derivedproperties

Embeddedproperties

Inheritance

Domain Modeling

Page 42: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 42

© Copyright 2010, Software Alchemy

HrApp Use Cases

View HR action historyEmployee

Manager

HR Rep

HR Mgr

View department staff

Promote employee

Issue pay raise for employee

Confirm employee promotion

Confirm employee pay raise

Issue cost-of-living raise to department

Hire employee

Terminate employeeConfirm employee hire

Confirm employee termination

Confirm department COL raise

Create/update job roles

Page 43: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 43

© Copyright 2010, Software Alchemy

Domain Model is King!

Page 44: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 44

© Copyright 2010, Software Alchemy

Property Validations

● Property constraints are defined in the Domain model, eg:

class Employee { // skipping property definitions static constraints = { firstName(nullable:false, blank:false, maxSize:32) lastName(nullable:false, blank:false, maxSize:64) dateOfBirth(nullable:true) homeAddress(nullable:false) homePhone(nullable:false) cellPhone(nullable:true) department(nullable:false) jobRole(nullable:true) salary(nullable:true, min:10000) proposedChange(nullable:true) // workflow properties user(nullable:false) status(nullable:false) }

Page 45: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 45

© Copyright 2010, Software Alchemy

Basic Enumerated Types

● Grails supports Java-style enums, eg:class Employee { // other properties Status status enum Status { CREATED, HIRED, DISCIPLINARY_REVIEW, TERMINATED; static def getActiveStatuses = { return [HIRED, DISCIPLINARY_REVIEW] } } // more code}

● ...but the enum name is stored in the DB field which is a bit wasteful, so...

«enumeratedType»Status

+CREATED+HIRED+DISCIPLARY_REVIEW+TERMINATED

«entity»Employee

firstName : StringlastName : String...status : Status

Page 46: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 46

© Copyright 2010, Software Alchemy

Enumerated Types with Ids

● You can define an id field in the enum, eg:class EmployeeAction { // other properties enum ActionType { HIRE('HI'), RAISE('RA'), COL_RAISE('CR'), PROMOTE('PO'), TERMINATE('TE'); final String id ActionType(String id) { this.id = id } } // more code}

● ...so now the DB field is a two-char value.

«enumeratedType»Status

+HIRE('HI')+RAISE('RA')+COL_RAISE('CR')+PROMOTE('PO')+TERMINATE('TE')

id : String

«entity»EmployeeAction

type : ActionTypeemployee : EmployeenewRole : JobRole...

Page 47: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 47

© Copyright 2010, Software Alchemy

Derived Properties

● Also know as transient properties, eg:class Employee { // Properties Date dateOfBirth

// Derived properties Integer getAge() { // corner case if ( dateOfBirth == null ) return null; // calculate and memoize the employee's age _age = _age ?: DateUtils.dateDiffYears(new Date(), dateOfBirth) return _age } private Integer _age

// GORM constraints static transients = [ 'age', ... ]

}

«entity»Employee

dateOfBirth : Date/age : Integer...

Page 48: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 48

© Copyright 2010, Software Alchemy

Derived Relationships

● You can do the same with computed relationships, eg:

class Employee {

// Derived properties List<EmployeeAction> getHistory() { // calculate and memoize the employee's HR history _history = _history ?: EmployeeAction.findAllByEmployee( this, [sort:'proposedDate', order:'asc'] ) return _history } private List<EmployeeAction> _history

// GORM constraints static transients = [ 'age', 'history', ... ]

}

«entity»EmployeeAction/history

*«entity»Employee

Page 49: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 49

© Copyright 2010, Software Alchemy

Embedded Properties

● Grails encourages rich object models even for non-Entity objects, eg:

class Employee { // Properties Address homeAddress PhoneNumber homePhone PhoneNumber cellPhone

// GORM constraints static embedded = [ 'homeAddress', 'homePhone', 'cellPhone' ]

}

class PhoneNumber { // Properties String areaCode String prefix String number // GORM constraints...}

«entity»Employee

homeAddress : AddresshomePhone : PhoneNumbercellPhone : PhoneNumber

«valueObject»PhoneNumber

areaCode : Stringprefix : Stringnumber : String

Page 50: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 50

© Copyright 2010, Software Alchemy

Embedded Properties (2)

● GORM creates a DB schema with each field of the Value Object embedded in the fields of the Entity.

class Employee { // Properties Address homeAddress PhoneNumber homePhone PhoneNumber cellPhone

}

Page 51: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 51

© Copyright 2010, Software Alchemy

Relationships

● Grails supports: one-to-one, one-to-many and many-to-many

● Grails supports uni- and bi-directional relationships

● Grails support ownership, with cascading deletes

● Grails supports unordered sets, sorted sets, and lists (with ordering index)

Page 52: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 52

© Copyright 2010, Software Alchemy

One-to-One Relationships

class Employee { // Properties Department department JobRole jobRole User user

// GORM constraints static constraints = { department(nullable:false) jobRole(nullable:true) user(nullable:false)}

«entity»JobRole

jobRole

0..1

«entity»User

{from com.example.security}user1

«entity»Employee

user : UserjobRole : JobRoledepartment : Department

«entity»Department department

1

Page 53: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 53

© Copyright 2010, Software Alchemy

One-to-Many

class HRRepresentative extends Employee {// Properties

Set<Department> departments // GORM constraints static hasMany = [ 'departments' : Department ]}

«entity»HRRepresentative

departments : Set<Department>

«entity»Department

departments

*

Page 54: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 54

© Copyright 2010, Software Alchemy

Inheritance

● Inheritance is supported with little to no configuration

● By default, the whole hierarchy is stored in one table

● You can configure Grails to use multiple tables● ...but be aware of the DB performance impact

of multiple selects and table joins

Page 55: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 55

© Copyright 2010, Software Alchemy

Inheritance (2)

class Employee { ... }

class HRRepresentative extends Employee { ... }

class Manager extends Employee { ... }

class Engineer extends Employee { ... }

«entity»Employee

«entity»HRRepresentative

«entity»Manager

«entity»Engineer

Page 56: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 56

© Copyright 2010, Software Alchemy

Inheritance (3)

● The resulting DB table:

Page 57: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 57

© Copyright 2010, Software Alchemy

GrailsArchitecture

Conv/Config

Buildtools

Web techPlugins

Groovy

GettingGroovy w/

Grails

InstallGrails

CreateApp

CreateEntity GUI Scaffolding

BasicDomainModeling

GettingStarted

DomainModeling

Relationships

Validation

Enumeratedtypes

Derivedproperties

Embeddedproperties

Inheritance

Q & A

Page 58: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 58

© Copyright 2010, Software Alchemy

Ten Great Topics Not Covered

1) Supports unit and integration testing

2) Supports RESTful URL patterns

3) Supports Java and Spring integration

4) Supports multiple environments

5) Integration to legacy DBs using Hibernate mappings

6) Supports turning Service components into Web Services

7) Easy to create your own plugins for cross-team sharing

8) Supports other continuous integration tools: Hudson, Ivy, etc

9) Supports data auditing and time stamping w/ GORM event model

10) Supports Ajax and Spring Web Flows

Page 59: Getting Groovy With Grails

Rochester JUG: 9-Nov-2010

Bryan Basham – Getting Groovy with Grails Slide 59

© Copyright 2010, Software Alchemy

Resources

● Groovy (http://groovy.codehaus.org/)– Reference docs (click here)– Reference card (click here)

● Grails (http://www.grails.org/)– Reference docs (click here)

● Eclipse plugin(http://dist.springsource.org/release/GRECLIPSE/e3.6/)

● The Definitive Guide to Grails (by Rocher and Brown, Apress)