SlideShare a Scribd company logo
1 of 33
Grails webflow


 Ivo Houbrechts
       Ixor
About Ixor
•   Since 2002
•   40 experienced ICT professionals
•   Software development for the JVM
•   Consultancy and product development
•   Loyal customers in Finance, Telecom and Government




•   www.ixor.be
Agenda
• Grails webflow plugin
   • Demo app
   • Spring webflow framework
   • Flow states
   • Subflows
   • Scopes
   • Ajax
   • Testing
   • Tips & pitfalls
   • Alternatives
• Extended validation plugin
• Questions
Demo app
• Simple domain model:
    • Project
    • Developer
    • UserStory


• Wizard for creating a project
Spring webflow framework
• Manage page flows
  • Wizards
• Manage objects
  • Scopes
• Manage states
• Back-button hell
• Grails webflow plugin
  • Subset of features
Defining a grails webflow
def newProjectWizardCleanedUpFlow = {
        onStart doOnStart

       projectInfo {
           on("next", doBindProjectInfo).to("lead")
       }

       lead {
           subflow(controller: "developer", action: "getDeveloper",
                   input: [experience: Experience.SENIOR])
           on("selected", doSetLead).to(selectLeadOrTeam)
           on("cancel", doFlashLeadMandatoryMessage).to("lead")
       }

       team {
           on("add").to("addTeamMember")
           on("remove", doRemoveTeamMember).to("team")
           on("next").to("stories")
       }

       addTeamMember {
           subflow(controller: "developer", action: "getDeveloper”)
       …
Flow states
• View states
• Action states
• Start and end states
• Subflow states
View state: definition
• Renders a view
• Definition:
    projectInfo {
        on("next").to("lead")
    }




• Default view
   /controllerName/flowName/viewstateId


• Override with
   render(view: "myview")
View state: events
• Triggered by user
  • Link
     <g:link action="newProjectWizard” event="remove">Remove</g:link>


  • Button
    <g:form action="newProjectWizard">
        <g:submitButton name="add" value="Add developer"/>
    </g:form>



• Transition
    team {
        on("add").to("addTeamMember")
        on("remove").to("team")
    }
View state: transition actions
• Used for binding and validation
   on("next") {
       flow.projectInstance.properties = params
       if (!flow.projectInstance.validate(["name", "description"])) {
           error()
       }
   }.to("lead")

  • Supports command objects
• Dynamic transitions
   on("selected“).to {
       if (!flow.projectInstance.validate(["lead"])) {
           return "lead"
       } else {
           return "team"
       }
   }
Action state: definition
saveProject {
    action {
        if (flow.projectInstance.save()) {
             end()
        } else {
             projectInfo()
        }
    }
    on("end").to("end")
    on("projectInfo").to("projectInfo")
}
Action state: events
• Events
  • Explicit
     • call missing method
  • Implicit
     • success
     • exception
  saveProject {
      action {
          def project= projectService.save(flow.projectInstance)
          return [project: project]
      }
      on("success").to("end")
      on("ValidationException").to("retry")
      on("Exception").to("fatalError")
  }
Action state: returning a model

  saveProject {
      action {
          def project= projectService.save(flow.projectInstance)
          return [project: project]
      }
      on("success").to("end")
      on("ValidationException").to("retry")
      on("Exception").to("fatalError")
  }

• Merged into flow scope
• Used in next state or view
Start and end states
• Start state: first state in flow definition
• End state
  • Empty
       cancel()

  • Redirect
     end {
         redirect(action: "show", id: flow.projectInstance.id)
     }
Subflow states
• Like method calls
  • Reusable (parts of) flows
• Definition
    lead {
        subflow(controller: "developer", action: "getDeveloper",
                        input: [experience: Experience.SENIOR])
            on("selected“).to("team")
            on("cancel").to("lead")
    }


• Events
  • Last state of subflow
Subflow input (grails 1.4.0)
• Declare input arguments
  • Like method arguments (contract)
   def getDeveloperFlow = {
       input {
           experience()
           title(required: true)
       }
   …


• Provide values in subflow call
   subflow(controller: "developer", action: "getDeveloper",
          input: [experience: Experience.SENIOR, title: "Select lead"])
Subflow input (grails 1.4.0)
• Required arguments
  • Exception if not provided
  • Not possible to use flow standalone
• Default values
   def mySubFlow = {
       input {
           foo() // optional input with no default value
           bazz(required: false, value: someConstantValue)
           dynamic { flow.someProperty }
           dynamicBis (value: someNamedClosure)
       }
   …
Subflow output (grails 1.4.0)
• Define output in end state
  selected {
      output {
          developer {flow.developer}
      }
  }…




• Retrieve output in calling flow
  on("selected") {
      flow.projectInstance.lead = currentEvent.attributes.developer
  }.to(…)
Subflow input and output values
• Constant values
  • Defined at flow definition time (application startup)
  • Refer to (controller) variables or literal expressions
• Dynamic values
  • Evaluated at flow execution time
  • Defined with closures
• Applicable in:
  • Default input values
  • Input values in subflow call
  • Output values
Scopes
• Standard scopes
• Webflow scopes
  • flow
     • flow execution, only visible in one flow
     • serialized
  • conversation
     • flow execution, visible for all flows and subflows
     • Cf. class members ↔ method arguments (subflow input)
     • serialized
  • flash
     • semantics like grails flash, but different instance
     • merged with request scope → omit ‘flash.’ prefix
Ajax
• Define transition to current state
  • Render template in transition action
   stories {
       on("remove") {
           …
           render(template: "newProjectWizard/editStories",
                      model: [projectInstance: flow.projectInstance])
       }.to("stories")
   …

• Use remoteLink or formRemote
   <g:remoteLink update="editStories" controller="project“
         action="newProjectWizard" event="remove"
         params="${[name: userStory.name,
                    ajaxSource: true, execution: params.execution]}">
   Remove</g:remoteLink>
Testing
• Integration test flows
  class ProjectControllerTests extends WebFlowTestCase {

      @Override Object getFlow() {
          return controller.newProjectWizardFlow
      }

      protected void setUp() {
          //register all subflows
          registerFlow("developer/getDeveloper",
            new DeveloperController().getDeveloperFlow)
      }

      void testHappyFlow() {
          startFlow()
          assert "projectInfo" == flowExecution.activeSession.state.id
          controller.params.name = "project name“
          signalEvent("next")
          assert "x" == flowScope.projectInstance.lead.name
  …
Tip 1
• Returning flow output to other controller actions
  • Use standard grails flash scope
   RequestContextHolder.currentRequestAttributes().flashScope.message =
      "Project was successfully created"
Tip 2
• Create clean readable flow definitions
     • Use closure variables
 def newProjectWizardCleanedUpFlow = {
         onStart doOnStart

         projectInfo {
             on("next", doBindProjectInfo).to("lead")
         }
 …



     • Define private closures
 private def doBindProjectInfo = {
     …
 }
Tip 3
• Flow diagrams (intellij)
  • Demo app: grails generate-xml-flow-definitions
Tip 4
• Kick start flow views
  • grails generate-views
  • Change
     • action attribute in forms and links
     • explicitly fill in the controller attribute in forms and links when
       using subflows
     • add an event attribute to links
     • remove the flash prefix in flash.message
     • use submitButton in stead of actionSubmit
Tip 5
• Bread crumbs
  • <flow:breadCrumbs/>
  • Tag source code: see demo app
Pitfalls
• Implement java.io.Serializable
  • Objects in flow and conversation scope
  • Events don’t get fired
        • Missing methods are not missing (f.e. scaffold actions)
  • Limited execution history
     • Back navigation
     • Ajax calls increase state count
  • Last state is subflow state
     • Back navigation after flow completes redirects to subflow
Alternatives
• Ad hoc flows
  • Where to store state?
  • What if user quits in the middle and starts again?
• One-page wizards with ajax
  • One page
  • One controller action for each step
  • Where to store state?
  • Subflows with overlays
Extended validation plugin
• Validation for non-grails domain classes
  • Particularly useful in combination with webflow
• Cascade constraint
   static constraints = {
       customer(cascade: true)
   …


• Instance constraint
   static constraints = {
       creditCheck(validator: {order ->
           if (order.customer.creditScore == CreditScore.BAD
               && order.orderLines.size() > 1) {
                   return "order.creditCheck.BAD"
           }
       })
   …
Extended validation plugin
• Constraint groups
   static constraints = {
       invoiceData {
           customer(cascade: true)
           contactPerson(nullable: false, blank: false)
       }
   …


• Partial validation
   order.validate(groups: ["invoiceData"])
   order.validate(
       includes: ["orderLines"],
       excludes: ["orderLines.deliveryAddress"])


• getAllErrorsRecursive() dynamic method
Livesnippets
• groovy & grails related documentation
  • Demo application
  • Code snippets
     • Directly linked to demo code
• Github:
  https://github.com/houbie/livesnippets
• Cloudfoundry:
   http://livesnippets.cloudfoundry.com
Questions



  ?

More Related Content

What's hot

JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter PilgrimJavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
HUJAK - Hrvatska udruga Java korisnika / Croatian Java User Association
 

What's hot (20)

Ngrx: Redux in angular
Ngrx: Redux in angularNgrx: Redux in angular
Ngrx: Redux in angular
 
What's new in jQuery 1.5
What's new in jQuery 1.5What's new in jQuery 1.5
What's new in jQuery 1.5
 
React with Redux
React with ReduxReact with Redux
React with Redux
 
Ngrx
NgrxNgrx
Ngrx
 
React, Redux, ES2015 by Max Petruck
React, Redux, ES2015   by Max PetruckReact, Redux, ES2015   by Max Petruck
React, Redux, ES2015 by Max Petruck
 
Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2
 
Vaadin+Scala
Vaadin+ScalaVaadin+Scala
Vaadin+Scala
 
Gerenciamento de estado no Angular com NgRx
Gerenciamento de estado no Angular com NgRxGerenciamento de estado no Angular com NgRx
Gerenciamento de estado no Angular com NgRx
 
Wix Automation - Core
Wix Automation - CoreWix Automation - Core
Wix Automation - Core
 
Wix Automation - DIY - Testing BI Events
Wix Automation - DIY - Testing BI EventsWix Automation - DIY - Testing BI Events
Wix Automation - DIY - Testing BI Events
 
Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3
 
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter PilgrimJavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
 
«От экспериментов с инфраструктурой до внедрения в продакшен»​
«От экспериментов с инфраструктурой до внедрения в продакшен»​«От экспериментов с инфраструктурой до внедрения в продакшен»​
«От экспериментов с инфраструктурой до внедрения в продакшен»​
 
How to perform debounce in react
How to perform debounce in reactHow to perform debounce in react
How to perform debounce in react
 
Rxjs marble-testing
Rxjs marble-testingRxjs marble-testing
Rxjs marble-testing
 
Phoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるPhoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってる
 
Google Web Toolkits
Google Web ToolkitsGoogle Web Toolkits
Google Web Toolkits
 
Introduction to react and redux
Introduction to react and reduxIntroduction to react and redux
Introduction to react and redux
 
React & Redux
React & ReduxReact & Redux
React & Redux
 
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...
Universal JS Web Applications with React - Web Summer Camp 2017, Rovinj (Work...
 

Similar to GR8Conf 2011: Grails Webflow

Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
Skills Matter
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
IndicThreads
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
vhazrati
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App Engine
Yared Ayalew
 

Similar to GR8Conf 2011: Grails Webflow (20)

Spring Web Flow. A little flow of happiness.
Spring Web Flow. A little flow of happiness.Spring Web Flow. A little flow of happiness.
Spring Web Flow. A little flow of happiness.
 
Introduction to Angular JS
Introduction to Angular JSIntroduction to Angular JS
Introduction to Angular JS
 
Dancing with websocket
Dancing with websocketDancing with websocket
Dancing with websocket
 
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
 
Automating Research Data with Globus Flows and Compute
Automating Research Data with Globus Flows and ComputeAutomating Research Data with Globus Flows and Compute
Automating Research Data with Globus Flows and Compute
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
 
Ajax Under The Hood
Ajax Under The HoodAjax Under The Hood
Ajax Under The Hood
 
Overview Of Lift Framework
Overview Of Lift FrameworkOverview Of Lift Framework
Overview Of Lift Framework
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
 
BPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep DiveBPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep Dive
 
[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless
 
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
 
2006 - Basta!: Advanced server controls
2006 - Basta!: Advanced server controls2006 - Basta!: Advanced server controls
2006 - Basta!: Advanced server controls
 
Javascript
JavascriptJavascript
Javascript
 
27javascript
27javascript27javascript
27javascript
 
Dropwizard Introduction
Dropwizard IntroductionDropwizard Introduction
Dropwizard Introduction
 
Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App Engine
 

More from GR8Conf

More from GR8Conf (20)

DevOps Enabling Your Team
DevOps Enabling Your TeamDevOps Enabling Your Team
DevOps Enabling Your Team
 
Creating and testing REST contracts with Accurest Gradle
Creating and testing REST contracts with Accurest Gradle Creating and testing REST contracts with Accurest Gradle
Creating and testing REST contracts with Accurest Gradle
 
Mum, I want to be a Groovy full-stack developer
Mum, I want to be a Groovy full-stack developerMum, I want to be a Groovy full-stack developer
Mum, I want to be a Groovy full-stack developer
 
Metaprogramming with Groovy
Metaprogramming with GroovyMetaprogramming with Groovy
Metaprogramming with Groovy
 
Scraping with Geb
Scraping with GebScraping with Geb
Scraping with Geb
 
How to create a conference android app with Groovy and Android
How to create a conference android app with Groovy and AndroidHow to create a conference android app with Groovy and Android
How to create a conference android app with Groovy and Android
 
Ratpack On the Docks
Ratpack On the DocksRatpack On the Docks
Ratpack On the Docks
 
Groovy Powered Clean Code
Groovy Powered Clean CodeGroovy Powered Clean Code
Groovy Powered Clean Code
 
Cut your Grails application to pieces - build feature plugins
Cut your Grails application to pieces - build feature pluginsCut your Grails application to pieces - build feature plugins
Cut your Grails application to pieces - build feature plugins
 
Performance tuning Grails applications
 Performance tuning Grails applications Performance tuning Grails applications
Performance tuning Grails applications
 
Ratpack and Grails 3
 Ratpack and Grails 3 Ratpack and Grails 3
Ratpack and Grails 3
 
Grails & DevOps: continuous integration and delivery in the cloud
Grails & DevOps: continuous integration and delivery in the cloudGrails & DevOps: continuous integration and delivery in the cloud
Grails & DevOps: continuous integration and delivery in the cloud
 
Functional testing your Grails app with GEB
Functional testing your Grails app with GEBFunctional testing your Grails app with GEB
Functional testing your Grails app with GEB
 
Deploying, Scaling, and Running Grails on AWS and VPC
Deploying, Scaling, and Running Grails on AWS and VPCDeploying, Scaling, and Running Grails on AWS and VPC
Deploying, Scaling, and Running Grails on AWS and VPC
 
The Grails introduction workshop
The Grails introduction workshopThe Grails introduction workshop
The Grails introduction workshop
 
Idiomatic spock
Idiomatic spockIdiomatic spock
Idiomatic spock
 
The Groovy Ecosystem Revisited
The Groovy Ecosystem RevisitedThe Groovy Ecosystem Revisited
The Groovy Ecosystem Revisited
 
Groovy 3 and the new Groovy Meta Object Protocol in examples
Groovy 3 and the new Groovy Meta Object Protocol in examplesGroovy 3 and the new Groovy Meta Object Protocol in examples
Groovy 3 and the new Groovy Meta Object Protocol in examples
 
Integration using Apache Camel and Groovy
Integration using Apache Camel and GroovyIntegration using Apache Camel and Groovy
Integration using Apache Camel and Groovy
 
CRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual MachineCRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual Machine
 

Recently uploaded

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Recently uploaded (20)

Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 

GR8Conf 2011: Grails Webflow

  • 1. Grails webflow Ivo Houbrechts Ixor
  • 2. About Ixor • Since 2002 • 40 experienced ICT professionals • Software development for the JVM • Consultancy and product development • Loyal customers in Finance, Telecom and Government • www.ixor.be
  • 3. Agenda • Grails webflow plugin • Demo app • Spring webflow framework • Flow states • Subflows • Scopes • Ajax • Testing • Tips & pitfalls • Alternatives • Extended validation plugin • Questions
  • 4. Demo app • Simple domain model: • Project • Developer • UserStory • Wizard for creating a project
  • 5. Spring webflow framework • Manage page flows • Wizards • Manage objects • Scopes • Manage states • Back-button hell • Grails webflow plugin • Subset of features
  • 6. Defining a grails webflow def newProjectWizardCleanedUpFlow = { onStart doOnStart projectInfo { on("next", doBindProjectInfo).to("lead") } lead { subflow(controller: "developer", action: "getDeveloper", input: [experience: Experience.SENIOR]) on("selected", doSetLead).to(selectLeadOrTeam) on("cancel", doFlashLeadMandatoryMessage).to("lead") } team { on("add").to("addTeamMember") on("remove", doRemoveTeamMember).to("team") on("next").to("stories") } addTeamMember { subflow(controller: "developer", action: "getDeveloper”) …
  • 7. Flow states • View states • Action states • Start and end states • Subflow states
  • 8. View state: definition • Renders a view • Definition: projectInfo { on("next").to("lead") } • Default view /controllerName/flowName/viewstateId • Override with render(view: "myview")
  • 9. View state: events • Triggered by user • Link <g:link action="newProjectWizard” event="remove">Remove</g:link> • Button <g:form action="newProjectWizard"> <g:submitButton name="add" value="Add developer"/> </g:form> • Transition team { on("add").to("addTeamMember") on("remove").to("team") }
  • 10. View state: transition actions • Used for binding and validation on("next") { flow.projectInstance.properties = params if (!flow.projectInstance.validate(["name", "description"])) { error() } }.to("lead") • Supports command objects • Dynamic transitions on("selected“).to { if (!flow.projectInstance.validate(["lead"])) { return "lead" } else { return "team" } }
  • 11. Action state: definition saveProject { action { if (flow.projectInstance.save()) { end() } else { projectInfo() } } on("end").to("end") on("projectInfo").to("projectInfo") }
  • 12. Action state: events • Events • Explicit • call missing method • Implicit • success • exception saveProject { action { def project= projectService.save(flow.projectInstance) return [project: project] } on("success").to("end") on("ValidationException").to("retry") on("Exception").to("fatalError") }
  • 13. Action state: returning a model saveProject { action { def project= projectService.save(flow.projectInstance) return [project: project] } on("success").to("end") on("ValidationException").to("retry") on("Exception").to("fatalError") } • Merged into flow scope • Used in next state or view
  • 14. Start and end states • Start state: first state in flow definition • End state • Empty cancel() • Redirect end { redirect(action: "show", id: flow.projectInstance.id) }
  • 15. Subflow states • Like method calls • Reusable (parts of) flows • Definition lead { subflow(controller: "developer", action: "getDeveloper", input: [experience: Experience.SENIOR]) on("selected“).to("team") on("cancel").to("lead") } • Events • Last state of subflow
  • 16. Subflow input (grails 1.4.0) • Declare input arguments • Like method arguments (contract) def getDeveloperFlow = { input { experience() title(required: true) } … • Provide values in subflow call subflow(controller: "developer", action: "getDeveloper", input: [experience: Experience.SENIOR, title: "Select lead"])
  • 17. Subflow input (grails 1.4.0) • Required arguments • Exception if not provided • Not possible to use flow standalone • Default values def mySubFlow = { input { foo() // optional input with no default value bazz(required: false, value: someConstantValue) dynamic { flow.someProperty } dynamicBis (value: someNamedClosure) } …
  • 18. Subflow output (grails 1.4.0) • Define output in end state selected { output { developer {flow.developer} } }… • Retrieve output in calling flow on("selected") { flow.projectInstance.lead = currentEvent.attributes.developer }.to(…)
  • 19. Subflow input and output values • Constant values • Defined at flow definition time (application startup) • Refer to (controller) variables or literal expressions • Dynamic values • Evaluated at flow execution time • Defined with closures • Applicable in: • Default input values • Input values in subflow call • Output values
  • 20. Scopes • Standard scopes • Webflow scopes • flow • flow execution, only visible in one flow • serialized • conversation • flow execution, visible for all flows and subflows • Cf. class members ↔ method arguments (subflow input) • serialized • flash • semantics like grails flash, but different instance • merged with request scope → omit ‘flash.’ prefix
  • 21. Ajax • Define transition to current state • Render template in transition action stories { on("remove") { … render(template: "newProjectWizard/editStories", model: [projectInstance: flow.projectInstance]) }.to("stories") … • Use remoteLink or formRemote <g:remoteLink update="editStories" controller="project“ action="newProjectWizard" event="remove" params="${[name: userStory.name, ajaxSource: true, execution: params.execution]}"> Remove</g:remoteLink>
  • 22. Testing • Integration test flows class ProjectControllerTests extends WebFlowTestCase { @Override Object getFlow() { return controller.newProjectWizardFlow } protected void setUp() { //register all subflows registerFlow("developer/getDeveloper", new DeveloperController().getDeveloperFlow) } void testHappyFlow() { startFlow() assert "projectInfo" == flowExecution.activeSession.state.id controller.params.name = "project name“ signalEvent("next") assert "x" == flowScope.projectInstance.lead.name …
  • 23. Tip 1 • Returning flow output to other controller actions • Use standard grails flash scope RequestContextHolder.currentRequestAttributes().flashScope.message = "Project was successfully created"
  • 24. Tip 2 • Create clean readable flow definitions • Use closure variables def newProjectWizardCleanedUpFlow = { onStart doOnStart projectInfo { on("next", doBindProjectInfo).to("lead") } … • Define private closures private def doBindProjectInfo = { … }
  • 25. Tip 3 • Flow diagrams (intellij) • Demo app: grails generate-xml-flow-definitions
  • 26. Tip 4 • Kick start flow views • grails generate-views • Change • action attribute in forms and links • explicitly fill in the controller attribute in forms and links when using subflows • add an event attribute to links • remove the flash prefix in flash.message • use submitButton in stead of actionSubmit
  • 27. Tip 5 • Bread crumbs • <flow:breadCrumbs/> • Tag source code: see demo app
  • 28. Pitfalls • Implement java.io.Serializable • Objects in flow and conversation scope • Events don’t get fired • Missing methods are not missing (f.e. scaffold actions) • Limited execution history • Back navigation • Ajax calls increase state count • Last state is subflow state • Back navigation after flow completes redirects to subflow
  • 29. Alternatives • Ad hoc flows • Where to store state? • What if user quits in the middle and starts again? • One-page wizards with ajax • One page • One controller action for each step • Where to store state? • Subflows with overlays
  • 30. Extended validation plugin • Validation for non-grails domain classes • Particularly useful in combination with webflow • Cascade constraint static constraints = { customer(cascade: true) … • Instance constraint static constraints = { creditCheck(validator: {order -> if (order.customer.creditScore == CreditScore.BAD && order.orderLines.size() > 1) { return "order.creditCheck.BAD" } }) …
  • 31. Extended validation plugin • Constraint groups static constraints = { invoiceData { customer(cascade: true) contactPerson(nullable: false, blank: false) } … • Partial validation order.validate(groups: ["invoiceData"]) order.validate( includes: ["orderLines"], excludes: ["orderLines.deliveryAddress"]) • getAllErrorsRecursive() dynamic method
  • 32. Livesnippets • groovy & grails related documentation • Demo application • Code snippets • Directly linked to demo code • Github: https://github.com/houbie/livesnippets • Cloudfoundry: http://livesnippets.cloudfoundry.com