Title: Flowscript
1Flowscript WoodyWebapps made easy with Cocoon
- Sylvain Wallezhttp//apache.org/sylvain
2Flowscript intro
- Flow control in Cocoon
- Aren't actions enough ?
- Yes, but they require state management
- Quickly becomes complex, hard to understand and
to maintain - ? Actions are the traditional "MVC" controller
- Flowscript is a controller
- Calls business logic and chooses the view
- but also more
- Keeps the application state
- Describes page flow as a sequential program
- Easily defines complex interactions
3Flowscript intro
var cart var user function checkout()
while(user null) cocoon.sendPageAndWait("
login.html") user UserRegistry.getUser(coc
oon.request.get("name"))
cocoon.sendPageAndWait("shippingAddress.html",
who user) var address cocoon.request.get(
"address") cocoon.sendPageAndWait("creditCard.h
tml") var creditCard cocoon.request.get("cre
ditCard") cocoon.sendPageAndWait("confirmOrder.
html") EnterpriseSystem.placeOrder(user,
cart, address, creditCard) cocoon.sendPage("ord
erPlaced.html")
4Flowscript intro
- Why JavaScript ?
- Simpler than Java, although powerful
- Integrates well with Java
- Well-known in the web world
- Allows faster roundtrips (save and reload)
- Supports continuations
5Calling the view
- cocoon.sendPage()
- cocoon.sendPage invokes the output page (view)
with two arguments - The view URL, relative to current sitemap
- A context object made available to the view
- ? Can be a Java or JavaScript object
- cocoon.sendPage("view.html") is like redirecting
to "cocoon/view.html" - Control then comes back to the script
- ? Should normally terminate
cocoon.sendPage("checkout.html", user
loggedUser, email address)
6Calling the view
- cocoon.sendPageAndWait()
- Similar to cocoon.sendPage
- Invoke the view with a context object
- The script is suspended after the view is
generated - ? the whole execution stack saved in a
continuation object - Flow between pages becomes sequential code
- ? No more complicated state automata
7Continuations
- What is it ?
- Contents of a continuation
- Stack of function calls
- Value of local variables
- ? Most often a lightweight object
- ? Creating a continuation does not halt a thread
!! - A continuation object is associated with a unique
identifier available to the view - ? Later used to "resurrect" it
8Continuations
- Sample flow script revisited
var cart var user function checkout()
while(user null) cocoon.sendPageAndWait("
login.html") user UserRegistry.getUser(coc
oon.request.get("name"))
cocoon.sendPageAndWait("shippingAddress.html",
who user) var address cocoon.request.get(
"address") cocoon.sendPageAndWait("creditCard.h
tml") var creditCard cocoon.request.get("cre
ditCard") cocoon.sendPageAndWait("confirmOrder.
html") EnterpriseSystem.placeOrder(user,
cart, address, creditCard) cocoon.sendPage("ord
erPlaced.html")
9View layer
- How to define the view ?
- It's a regular Cocoon pipeline
- ? Preferably in an internal-only"true" pipeline
- Two generators providing tight integration
- JXTemplateGenerator
- JPath XSP logicsheet
- ? Easy access to the context object
10View layer
- JXTemplateGenerator
- An XML template language inspired by JSTL
- Doesn't allow code, but only access to context
variables - ? Simpler than XSP
- Flow values are provided as variables
- Two expressions languages
- Jexl with and JXPath with
sendPage("checkout.html", "customer"
user, "cart" cart)
ltpgtWelcome, customer/firstNamelt/pgt
11View layer
Your cart ltulgt ltjxforEach var"item"
items"cart.items"gt ltligtitem.quantity
item.namelt/ligt lt/jxforEachgt lt/ulgt lta
href"kont/continuation.id"gtContinuelt/agt
Your cart ltulgt ltligt3 Cocoon T-Shirtlt/ligt
ltligt1 Washing machinelt/ligt lt/ulgt lta
href"kont/bf6c433aa3148f8ca083f18a83813f81"gtConti
nuelt/agt
Will "resurrect" the flow script
12Putting it all together
ltmappipelinesgt ltmappipelinegt ltmapmatch
pattern"checkout"gt ltmapcall
function"checkout"/gt lt/mapmatchgt
ltmapmatch pattern"kont/"gt ltmapcall
continuation"1"/gt lt/mapmatchgt
lt/mappipelinegt ltmappipeline
internal-only"true"gt ltmapmatch
pattern".html"/gt ltmapgenerate type"jxt"
src"1.xml"/gt ltmaptransform
src"page2html.xsl"/gt ltmapserialize/gt
lt/mapmatchgt /
? Call a flow function
? Resurrect a continuation
? View called by the flow
13Putting it all together
- FOM the Flow Object Model
- Provided by the "cocoon" global object
- Access to the environment
- "request", "response", "session" "context"
properties - "parameters" sitemap parameters
- Access to the framework
- Logging, using Avalon components
- Page flow control
- cocoon.sendPage(), cocoon.sendPageAndWait()
- cocoon.redirectTo()
14Session variables
- Global scope session scope
- Global variables are attached to the session
- Saved across top-level function invocations
- Specific to each user
- ? Removes most of the needs for session
attributes !
15Session variables
var user null function login() while
(user null) sendPageAndWait("login.html")
user UserRegistry.getUser(
cocoon.request.getParameter("name"),
cocoon.request.getParameter("password") )
function placeOrder() login()
Accounting.placeOrder(user) sendPage("orderPlac
ed.html") function logout() user null
sendPage("bye.html")
Shows the login screenonly if needed
Won't pass through if not logged in !
Just clear user info to log out
16Managing continuations
- Continuation trees
- Browser "back" or "new window"
var cart var user function checkout()
while(user null) cocoon.sendPageAndWait("
login.html") user UserRegistry.getUser(coc
oon.request.get("name"))
cocoon.sendPageAndWait("shippingAddress.html",
who user) var address cocoon.request.get(
"address") cocoon.sendPageAndWait("creditCard.h
tml") var creditCard cocoon.request.get("cre
ditCard") cocoon.sendPageAndWait("confirmOrder.
html") EnterpriseSystem.placeOrder(user,
cart, address, creditCard) cocoon.sendPage("ord
erPlaced.html")
17Managing continuations
- Continuation trees
- Browser "back" the previous path is lost
- No fear a continuation is lightweight
- ? Reference to the parent continuation
- ? Local variables since the parent continuation
- Browser "new window"
- Creates a new branch
- ? Allows "what if ?" navigation in the application
18Managing continuations
- Expiring continuations
- Manual expiration
- sendPageAndWait() returns its continuation
- k.invalidate() invalidates the continuation and
its subtree - ? Again, avoids complicated state management
- Automatic expiration
- An inactive continuation expires after a delay
var k sendPageAndWait("start.html") ... Busines
sService.commit() // Cannot go back
again k.invalidate()
19Conclusion
- Flow script
- Gives control back to the server
- ? We always know "where" the browser is
- Allows sophisticated flow screens
- ? No need for state automata
- Increases security and robustness
- ? Forbids direct access to form submission URLs
- ? Handles "back" and "new window"
20Questions ? Answers ! (next Woody)
21Woody intro
- The need for form handling
- Cocoon started as a publication framework
- ? Many pages, limited user feedback
- ? Content was mostly written "outside"
- Evolution towards a general-purpose web framework
- ? Published content has to be managed
- ? Used for more and more data-centric
applications - ? Need for good form handling features
- Various attempts before Woody
- FormValidatorAction, Precept, XMLForm, JXForms
22Woody principles
23Woody principles
- The form object model
- Composed of "widgets"
- Represents "something" that appears in the form
- Can read, parse and validate itself
- Can output its XML representation
- Some widgets are non-terminal
- ? Support for tables and rows
24Woody principles
ltwdform xmlnswd"http//apache.org/cocoon/woody/
definition/1.0"gt ltwdfield id"name"
required"true"gt ltwdlabelgtNamelt/wdlabelgt
ltwddatatype base"string"gt
ltwdvalidationgt ltwdlength min"2"/gt
lt/wdvalidationgt lt/wddatatypegt
lt/wdfieldgt ltwdfield id"email"
required"true"gt ltwdlabelgtEmail
addresslt/wdlabelgt ltwddatatype
base"string"gt ltwdvalidationgt
ltwdemail/gt lt/wdvalidationgt
lt/wddatatypegt lt/wdfieldgt / lt/wdformgt
25Woody principles
- Form template overview
- Embeds widget references in target markup
lthtml xmlnswt"http//apache.org/cocoon/woody/tem
plate/1.0"gt ltheadgt lttitlegtRegistrationlt/titl
egt lt/headgt ltbodygt lth1gtRegistrationlt/h1gt
ltwtform-template action"registration"
method"POST"gt ltwtwidget-label
id"name"/gt ltwtwidget id"name"/gt
ltbr/gt ltwtwidget-label id"email"/gt
ltwtwidget id"email"/gt ltbr/gt /
ltinput type"submit"/gt lt/wtform-templategt
lt/bodygt lt/htmlgt
26The form definition file
- Widgets
- Available widgets
- ltwdformgt the main form widget
- ltwdfieldgt "atomic" input field
- ltwdbooleanfieldgt boolean input
- ltwdmutivaluefieldgt multiple selection in a
list - ltwdrepeatergt collection of widgets
- ltwdoutputgt non-modifiable value
- ltwdactiongt action button (intra-form)
- ltwdsubmitgt submit button (exits the form)
- They're all defined in cocoon.xconf
- ? Add your own if needed
27The form definition file
- The ltwdfieldgt widget
- Definition overview
- The label can contain abitrary markup
- Including i18n references
ltwdfield id"..." required"truefalse"gt
ltwdlabelgt...lt/wdlabelgt ltwddatatype
base"..."gt ... lt/wddatatypegt
ltwdselection-listgt ...
lt/wdselection-listgt lt/wdfieldgt
ltwdlabelgtYour ltbgtnamelt/bgtlt/wdlabelgt
ltwdlabelgt lti18ntext key"name-field-label"/gt lt
/wdlabelgt
28The form definition file
- Defining the data type of a field
- Mandatory "base" type
- Defines the Java type
- "string", "long", "decimal", "date", "boolean"
- ? Pluggable components add your own !
- Optional conversion and validation
ltwddatatype base"..."gt ltwdconvertorgt
... lt/wdconvertorgt ltwdvalidationgt
... lt/wdvalidationgt lt/wddatatypegt
Parsing and formatting
Validation
29The form definition file
- Data type parsing and formatting
- Each base type has a set of converters
- ? Pluggable components add your own !
- Example date's "formatting" converter
- based on java.text.SimpleDateFormat
- ? locale-dependent patterns
ltwddatatype base"date"gt ltwdconvertor
type"formatting"gt ltwdpatternsgt
ltwdpatterngtyyyy-MM-ddlt/wdpatterngt
ltwdpattern locale"en"gtMM/dd/yyyylt/wdpatterngt
ltwdpattern locale"fr"gtdd/MM/yyyylt/wdpattern
gt ltwdpattern locale"nl-BE"gtdd/MM/yyyylt/wd
patterngt ltwdpattern locale"de"gtdd.MM.yyyylt
/wdpatterngt lt/wdpatternsgt
lt/wdconvertorgt lt/wddatatypegt
30The form definition file
- Data type validation
- A validation rule checks value validity
- length, range, regexp, creditcard, assert, email
- ? Pluggable components add your own !
- A datatype can have several validation rules
ltwdfield id"email"gt ltwddatatype
base"string"gt ltwdvalidationgt
ltwdemail/gt ltwdlength max'100'gt
ltwdfailmessagegtYour address it too
long!lt/wdfailmessagegt lt/wdlengthgt
lt/wdvalidationgt lt/wddatatypegt lt/wdfieldgt
31The form definition file
- Selection lists
- Provide enumerations to the user
- List of items having a value, with optional label
- Selection lists can be external and dynamic
ltwdfield name"OS"gt ltwddatatype
base"string"/gt ltwdselection-listgt
ltwditem value"Linux"/gt ltwditem
value"Windows"/gt ltwditem value"Mac OS"/gt
ltwditem value"Solaris"/gt ltwditem
value"other"gt ltwdlabelgtlti18ntext
key"other"/gtlt/wdlabelgt lt/wditemgt
lt/wdselection-listgt lt/wdfieldgt
ltwdselection-list src"cocoon/build-list.xml"gt
32The form definition file
- The ltwdrepeatergt widget
- Repeats a number of child widgets
- ? Used to manage collections, tables, etc.
- Specialized ltrepeater-actiongt widgets
- ? Automatic row addition/deletion
ltwdrepeater id"contacts"gt ltwdfield
id"firstname"gt ltwdlabelgtFirstnamelt/wdlabelgt
ltwddatatype base"string"/gt lt/wdfieldgt
ltwdfield id"lastname"gt ltwdlabelgtLastnamelt/
wdlabelgt ltwddatatype base"string"/gt
lt/wdfieldgt lt/wdrepeatergt
33The form template
34The form template
- Role of the WoodyTransformer
lthtml xmlnswt"http//apache.org/cocoon/woody/tem
plate/1.0"gt ltheadgt lttitlegtRegistration
formlt/titlegt lt/headgt ltbodygt
lth1gtRegistrationlt/h1gt ltwtform-template
action"registration" method"POST"gt
ltwtwidget-label id"name"/gt ltwtwidget
id"name"/gt ltbr/gt ltwtwidget-label
id"email"/gt ltwtwidget id"email"/gt
ltbr/gt / ltinput type"submit"/gt
lt/wtform-templategt lt/bodygt lt/htmlgt
lthtml xmlnswt"http//apache.org/cocoon/woody/ins
tance/1.0"gt ltheadgt lttitlegtRegistration
formlt/titlegt lt/headgt ltbodygt
lth1gtRegistrationlt/h1gt ltwiform-template
action"registration" method"POST"gt Name
ltwifield id"name"gt
ltwilabelgtNamelt/wilabelgt
ltwivaluegtCocoonlt/wivaluegt lt/wifieldgt
ltbr/gt Email address ltwiwidget
id"email"gt ltwilabelgtEmail
addresslt/wilabelgt ltwivaluegtfoolt/wivalu
egt ltwivalidation-messagegt
Invalid email address lt/wivalidation-mess
agegt lt/wiwidgetgt ltbr/gt /
ltinput type"submit"/gt lt/wiform-templategt
lt/bodygt lt/htmlgt
Expanded widget
Expanded widgets
Validation failed
35The form template
- Role of the WoodyTransformer
- Expand all "wt" elements in their "wi"
counterpart - ? "wt" Woody template
- ? "wi" Woody instance
- Output of the transformer goes to styling
- Provided HTML styling
- Other stylings are possible (e.g. WML)
- ? Woody does not hardcode the presentation !
36The form template
- The ltwtwidgetgt element
- Produces the corresponding widget instance
- Markup depends on the actual widget
- For fields ltwilabelgt, ltwivaluegt,
ltwiselection-listgt - ltwtwidgetgt can contain styling information
- Drives the styling stylesheet
- ? Contents of ltwistylinggt depends on the
stylesheet !
ltwtwidget id"fourchars"gt ltwistyling
list-type"listbox"
listbox-size"4"/gt lt/wtwidgetgt
ltwtwidget id"fourchars"gt ltwistyling
list-type"radio"/gt lt/wtwidgetgt
37The form template
lttablegt lttrgt ltthgtNamelt/thgt ltthgtEmail
addresslt/thgt lt/trgt lttrgt lttdgt
ltwifield id"contacts.0.firstname"gt
ltwilabelgtNamelt/wilabelgt
ltwivaluegtHarrylt/wivaluegt lt/wifieldgt
lt/tdgt lttdgt ltwifield id"contacts.0.emai
l"gt ltwilabelgtEmail addresslt/wilabelgt
ltwivaluegtharry_at_potter.comlt/wivaluegt
lt/wifieldgt lt/tdgt lt/trgt lttrgt lttdgt
ltwifield id"contacts.1.firstname"gt
ltwilabelgtNamelt/wilabelgt
ltwivaluegtAnakinlt/wivaluegt lt/wifieldgt
lt/tdgt lttdgt ltwifield id"contacts.1.emai
l"gt ltwilabelgtEmail addresslt/wilabelgt
ltwivaluegtanakin_at_skywalker.comlt/wivaluegt
lt/wifieldgt lt/tdgt lt/trgt lt/tablegt
- The ltwtrepeater-widgetgt element
- Iterates on the contents of a ltwdrepeatergt
lttablegt lttrgt ltthgt ltwtrepeater-widget-
label id"contacts" widget-id"firstname
"/gt lt/thgt ltthgt ltwtrepeater-widget-l
abel id"contacts" widget-id"email"/gt
lt/thgt lt/trgt ltwtrepeater-widget
id"contacts"gt lttrgt lttdgt
ltwtwidget id"firstname"/gt lt/tdgt
lttdgt ltwtwidget id"email"/gt lt/tdgt
lt/trgt lt/wtrepeater-widgetgt lt/tablegt
38Built in HTML styling
- Field styling
- Basic styling html input
- ltwistyling type""gt
- "password", "hidden", "textarea", "date"
- "listbox", "radio" for selection-lists
39Built in HTML styling
- ltwigroupgt styling
- Instance-only widget providing high-level styling
- ? No corresponding ltwdgt nor ltwtgt
type"fieldset"
ltwigroupgt ltwilabelgtProfile headerlt/wilabelgt
ltwistyling type"fieldset" layout"columns"/gt
ltwiitemsgt ltwtwidget id"revision"/gt
ltwtwidget id"identification"/gt ltwtwidget
id"name"/gt ltwtwidget id"author"/gt
ltwtwidget id"classID"/gt ltwtwidget
id"releaseDate"gt ltwistyling
type"date"/gt lt/wtwidgetgt
lt/wiitemsgt lt/wigroupgt
layout"columns"
40Built in HTML styling
- ltwigroupgt styling
- Container rendering
- ? "type" attribute "fieldset", "tabs", "choice"
- ? Tabs defined with CSS
type"choice"
type"tabs"
41Interactive forms
- Server-side event handler,client-side trigger
ltwdfield id"make" required"true"gt
ltwdlabelgtMakelt/wdlabelgt ltwddatatype
base"string"/gt ltwdselection-list
src"cocoon/cars" dynamic"true"/gt
ltwdon-value-changedgt ltjavascriptgt var
value event.newValue var type
event.source.parent.getWidget("type") if
(value null) type.setSelectionList(ne
w EmptySelectionList("Select a maker
first")) else
type.setSelectionList("cocoon/cars/"value)
typewidget.setValue(null)
lt/javascriptgt lt/wdon-value-changedgt lt/wdfieldgt
ltwtwidget id"make"gt ltwistyling
submit-on-change"true"/gt lt/wtwidgetgt
Change the type selection list
42Linking forms to application data
- An additional binding definition file
- Associates widget names to XPath expressions on
the data model - Example binding to an XML document
ltwbcontext xmlnswb"http//apache.org/cocoon/
woody/binding/1.0" xmlnswd"http//apache.org/
cocoon/woody/definition/1.0" path"user" gt
ltwbvalue id"email" path"email"
readonly"true"/gt ltwbvalue id"number"
path"number/_at_value"gt ltwdconvertor
datatype"long"/gt lt/wbvaluegt ltwbvalue
id"choose" path"choose/_at_value"gt
ltwdconvertor datatype"boolean"/gt
lt/wbvaluegt lt/wbcontextgt
Set the context of included paths
Read-only widget
Associates a widget to a path
Binding convertor (XML is text)
43Putting it all together
- The woody.js library
- Provides a Form class
- Constructor takes a form definition file
- Method Form.showForm() to display the form
- Returns when validation ok or non-validating
submit - ? Internal loop on sendPageAndWait()
function edit_header() var data
Application.getData() var form new
Form("forms/profile-header-def.xml")
form.createBinding("forms/profile-header-binding.x
ml") form.load(data) form.showForm("view-pr
ofile-header.html", foo bar) if
(form.submitId "ok") form.save(data)
sendDialog("Thanks a lot") else
sendDialog("Bye bye")
Loadapp. data
Show form and wait
Test submit button
Saveapp. data
44Putting it all together
Selection by http method form's action is ""
(same URL)
ltmapmatch pattern"edit-.html"gt ltmapselect
type"method"gt lt!-- GET start the flow for
this screen --gt ltmapwhen test"GET"gt
ltmapcall function"editor_1"/gt
lt/mapwhengt lt!-- POST (form submission)
continue the flow --gt ltmapwhen test"POST"gt
ltmapcall continuation"request-paramcontin
uation-id"/gt lt/mapwhengt
lt/mapselectgt lt/mapmatchgt ltmapmatch
pattern"view-.html"gt ltmapgenerate
type"jxtemplate" src"forms/1-tmpl.xml"/gt
ltmaptransform type"woody"/gt ltmaptransform
type"i18n"/gt ltmaptransform type"xslt"
src"resources/editor-styling.xsl"/gt
ltmapserialize type"html"/gt lt/mapmatchgt
"editor_" prefix restricts access to flowscript
functions
JXTemplate to use showForm's context data
45Conclusion
- A powerful form framework
- Rich datatypes and validation rules
- Easy extension to specific needs
- Event handling for sophisticated interaction
- Fancy builtin stylesheets
- Easy to use with flowscript
- A community development
- Initiated by Outerthought
- Welcomes additions and contributions
- ? Woody will be the form framework for Cocoon
See also http//wiki.cocoondev.org/Wiki.jsp?pageW
oody
46Questions ? Answers !