Taming cocoon
This presentation is the property of its rightful owner.
Sponsored Links
1 / 190

Taming Cocoon PowerPoint PPT Presentation


  • 81 Views
  • Uploaded on
  • Presentation posted in: General

Taming Cocoon. ApacheCon Europe 2005 Gianugo Rabellino. Agenda. Introduction Installing Cocoon Dissecting Cocoon Management and configuration A sitemap tour Cocoon components and blocks Understanding continuations and flow Dealing with forms Patterns, best practices, pitfalls.

Download Presentation

Taming Cocoon

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Taming cocoon

Taming Cocoon

ApacheCon Europe 2005

Gianugo Rabellino


Agenda

Agenda

  • Introduction

  • Installing Cocoon

  • Dissecting Cocoon

  • Management and configuration

  • A sitemap tour

  • Cocoon components and blocks

  • Understanding continuations and flow

  • Dealing with forms

  • Patterns, best practices, pitfalls


Introduction web developer nightmares

Introduction: web developer nightmares

out.println(“<table border=\”0\”>\n\t<tr>\n\t\t” +

“<td align=\”left\”><font size=\”+1\”>” +

request.getParameter(“lousyjob”) +

“Does your boss know you\'re typing HTML?” +

“</td>\n\t</tr>\n</table>\n”);


Nightmare managing html

Nightmare: managing HTML

  • Your IDE can't deal with HTML

  • Dreamweaver can't deal with business logic

  • Period.

  • Oh, and JSPs suck. Big time.

    “Separate concerns” - Edsger Dijkstra - 1974


Nightmare handling state

Nightmare: handling state

  • HTTP is stateless (did you notice already?)

  • Where am I now?

  • Restart required

  • Sessions == overpopulated mess of dictionaries


Nightmare managing user input

Nightmare: managing user input

  • Validation hell

  • Conversion ordeal

  • Binding torture

  • The infamous Back button, oh my!


There has to be a better way

There has to be a better way

“Never let a man do what a machine can do for him”

Blaise Pascal


Apache cocoon

Apache Cocoon

A fast-paced overview


Apache cocoon facts and figures

Apache Cocoon: facts and figures

  • Origins

    • Started by the Italian student Stefano Mazzocchi

      • Redesign of Apache.org

    • Frustrated by the limitations of HTML

    • Wanted to use emerging technologies (XML/XSL)

  • Today

    • Now one of the most important Apache projects

    • Incorporates technologies from various project

    • Just under 2000 registered on all mailing lists

    • Includes major companies such as HP, IBM


Tucking web devs in kissing them goodnight

Tucking web devs in, kissing them goodnight


10 000ft overview

10.000ft overview


Key cocoon concepts

Key Cocoon concepts

  • URI space decoupling

  • Componentized resource assembling

  • Datasource connections and decoupling

  • Stateful applications


And their implementation

And their implementation...

  • URI space decoupling

    • Sitemap

  • Componentized resource assembling

    • Pipelines

  • Datasource connections and decoupling

    • Source interface and implementations (file, URL, database, WebDAV, XMLDB...)

  • Stateful applications

    • Web continuations


Uri space decoupling the sitemap

URI space decoupling: the sitemap

  • Think <servlet-mapping> on steroids

  • Pattern freaks think FrontController

  • Uses pluggable algorithms:

    • Wildcard

    • Regexp

    • Your own

  • Matching the whole HTTP environment:

    • Request URI/parameters/attributes

    • Session attributes

    • Cookies, context, etc...

  • Welcome to the sitemap


A sitemap example

A sitemap example

  • <map:match pattern="news/*" type="wildcard">

  • <map:generate src="newsfeeds/{1}.xml" type="file"/>

  • <map:transform src="news2html.xsl" type="xslt"/>

  • <map:serialize type="html"/>

  • </map:match>

  • <map:match pattern="products/*" type="wildcard">

  • <map:generate src="products/infos/product_{1}.xml" type="file"/>

  • <map:transform src="products2html.xsl" type="xslt"/>

  • <map:serialize type="html"/>

  • </map:match>


Resource assembling the pipeline

Resource assembling: the pipeline

  • Task: find the total number of unique hosts visiting the home page of your site

    • Windows solution:

      #include <stdlib.h>

      ...

    • Unix solution:

      $ grep index.html access.log | awk '{print $2 }' | sort | uniq | wc -l

  • Welcome to the pipeline: specialized components glued together


The cocoon pipeline

The Cocoon pipeline

  • Two simple rules:

    • Data stream is based on SAX events

    • Pipelines start with one Generator (and only one), have 0-n Transformers, end with one (and only one) Serializer

  • Generators: adapters from the outside world to SAX events

  • Transformers: SAX event manglers

  • Serializers: adapters from SAX events to the outside world


A pipeline example

A pipeline example

<map:matchpattern="*.html">

<map:generatesrc=”xdocs/{1}.xml"/>

<map:transformsrc=“style/xdocs2html.xsl”/>

<map:serialize/>

</map:match>


Datasource virtualization

Datasource virtualization

  • Virtualization layer over stream-based data sources

  • Provides a java.io.File like interface for a number of data sources

  • Think URLs on steroids


The source interface

The Source interface


A datasource example

A datasource example

  • <map:match pattern="news/*" type="wildcard">

  • <map:generate src="webdav://repo/newsfeeds/{1}.xml" type="file"/>

  • <map:transform src="xmldb://localhost/db/news2html.xsl" type="xslt"/>

  • <map:serialize type="html"/>

  • </map:match>

  • <map:match pattern="products/*" type="wildcard">

  • <map:generate src="cocoon://products/infos/product_{1}.xml"/>

  • <map:transform src="resource://products2html.xsl" type="xslt"/>

  • <map:serialize type="html"/>

  • </map:match>


Summing it up

Summing it up

  • The sitemap decouplesURI space from physical resources

  • The pipelinedecouplesresults from the way they're built

  • XML decouplescontent from presentation

  • The source abstractiondecouplesdata sources from physical locations

    Result:full Separation of Concerns

    (and you ain’t seen nothing yet...)


Web continuations

Web Continuations

The next revolution


Web applications are easy

Web applications are easy!


But wait this is stateless http

But wait, this is stateless HTTP

  • Webapps are finite state machines

  • Upon every click, processing starts from the beginning

  • Again, and again, and again


A typical web application clutter

A typical web application clutter


What are continuations

What are continuations?

“A continuation is an entire set of closures that make up a point of execution”

“A continuation is an object that, for a given point in your program, contains a snapshot of the stack trace, including all the local variables, and the program counter”

Hmmm... so what?


A flowscript example where the magic happens

A flowscript example: where the magic happens

var cart;

var user;

function checkout()

{

while(user == null) {

cocoon.sendPageAndWait("login.html");

user = UserRegistry.getUser(cocoon.request.get("name"));

}

cocoon.sendPageAndWait("shippingAddress.html", {who: user});

var address = cocoon.request.get("address");

cocoon.sendPageAndWait("creditCard.html");

var creditCard = cocoon.request.get("creditCard");

cocoon.sendPageAndWait("confirmOrder.html");

EnterpriseSystem.placeOrder(user, cart, address, creditCard);

cocoon.sendPage("orderPlaced.html");

}


What are continuations again

What are continuations, again?

  • 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


Flowscript example revisited

Flowscript example, revisited

saved continuations

var cart;

var user;

function checkout()

{

while(user == null) {

cocoon.sendPageAndWait("login.html");

user = UserRegistry.getUser(cocoon.request.get("name"));

}

cocoon.sendPageAndWait("shippingAddress.html", {who: user});

var address = cocoon.request.get("address");

cocoon.sendPageAndWait("creditCard.html");

var creditCard = cocoon.request.get("creditCard");

cocoon.sendPageAndWait("confirmOrder.html");

EnterpriseSystem.placeOrder(user, cart, address, creditCard);

cocoon.sendPage("orderPlaced.html");

}


Continuations tree

Continuations tree

var cart;

var user;

function checkout()

{

while(user == null) {

cocoon.sendPageAndWait("login.html");

user = UserRegistry.getUser(cocoon.request.get("name"));

}

cocoon.sendPageAndWait("shippingAddress.html", {who: user});

var address = cocoon.request.get("address");

cocoon.sendPageAndWait("creditCard.html");

var creditCard = cocoon.request.get("creditCard");

cocoon.sendPageAndWait("confirmOrder.html");

EnterpriseSystem.placeOrder(user, cart, address, creditCard);

cocoon.sendPage("orderPlaced.html");

}

Don't fear the Back button anymore!


Summing it up1

Summing it up

  • Continuations give control back to the server

    •  We always know "where" the browser is

  • Allow sophisticated flow screens

    •  No need for state automata

  • Increase security and robustness

    •  Forbids direct access to form submission URLs

    •  Handling of "back" and "new window"


A word about forms

A word about forms

Managing user input


Cocoon forms nightmares solved

Cocoon Forms: nightmares solved!

  • MVC based form framework

  • Provides:

    • Strongly-typed data: a date field is a java.util.Date. Automatically.

    • Validation: declarative. Handled for you. Automatically.

    • Binding: to objects (EJB, POJOs...) or to XML, your choice. Automatically.


Cocoon forms a functional view

Cocoon Forms, a functional view

  • Separation of Concerns in forms:

    • Model: data typing, validation rules

    • View: widget presentation

      • selections could be drop down lists or checkboxes

    • Controller:

      • flowscript (continuations based)

      • custom actions (à la Struts) – not recommended

    • Data binding:

      • declarative

      • JXPath based


Cocoon forms a rich framework

Cocoon Forms: a rich framework

  • Powerful widget library

    • Fields, aggregated fields, dates, selectors, trees and repeaters

  • AJAX compliant infrastructure

    • Boosts perceived performance

  • Integrated add-ons

    • HTML editor

    • calendar pop-ups

    • dynamic double selection lists


Summing it up rad development

Summing it up: RAD development

  • Configure, don't code

  • Continuations make webapp development a breeze

  • Powerful form frameworks ease managing user input

  • Separation of Concerns brings maintainability

    ... and they lived happily ever after.


Installing cocoon

Installing Cocoon

Finding your way through compilation and blocks


Downloading cocoon

Downloading Cocoon

  • http://cocoon.apache.org

  • Subversion for the latest version:

    http://svn.apache.org/repos/asf/cocoon/branches/BRANCH_2.1.X

    http://svn.apache.org/repos/asf/cocoon/trunk

    • … or even WebDAV


Preparing cocoon

Preparing Cocoon

  • Task list:

    • Edit local.build.properties

      • Exclude unneeded and heavy tasks (e.g. javadocs / documentation)

    • Edit local.blocks.properties

      • Beware of dependencies

  • All done, now run:

    $ ./build.sh (Unix)

    C\> build.bat (Windows)


Testing the install

Testing the install

  • Embedded Jetty:

    • Run

      $ ./cocoon.sh servlet (Unix)

      C\> cocoon.bat servlet (Windows)

    • Point your browser to http://localhost:8888/

  • Other servlet engines:

    • Run

      $ ./build.sh war (Unix)

      C\> build.bat war (Windows)

    • Deploy dist/cocoon*.war


Beware the classloader

Beware the classloader

  • Cocoon uses its own version of Rhino (Javascript engine)

  • Might clash with vendor-provided ones (e.g. Websphere/BEA)

  • Make sure that your appserver is configured to run Cocoon in an isolated classloader (as per servlet spec):

    • ask your vendor to fix his bug if it doesn’t work

  • If it doesn’t work, use the “paranoid” block and the ParanoidCocoonServlet (but you shouldn’t)

  • Mind redirects on WebSphere!


Eclipse integration

Eclipse integration

  • Run:

    $ ./build.sh eclipse-project (Unix)

    C\> build.bat eclipse-project (Windows)

  • Inside Eclipse:

    • New Java Project

    • Navigate to $COCOON_HOME

  • Your project will appear automagically!


Files you want to know

Files you want to know

  • Main sitemap:

    $COCOON_HOME/build/webapp/sitemap.xmap

  • Log configuration:

    $COCOON_HOME/build/webapp/WEB-INF/logkit.xconf

  • Component configuration:

    $COCOON_HOME/build/webapp/WEB-INF/cocoon.xconf

  • Mount table:

    $COCOON_HOME/mount-table.xml


Management and configuration

Management and configuration

Handling Cocoon in production


Configuring cocoon

Configuring Cocoon

  • Web Application Configuration

    • Cocoon runs as a servlet

    • Configuration controlled by web.xml

    • Find it in the WEB-INF directory

  • Most important entry

    • Name and location of the actual configuration file

      • Default: WEB-INF/cocoon.xconf

        <!--

        This parameter points to the main configuration file for Cocoon. Note that the path is specified in absolute notation but it will be resolved relative to the servlets webapp context path

        -->

        <init-param>

        <param-name>configurations</param-name>

        <param-value>/WEB-INF/cocoon.xconf</param-value>

        </init-param>


Configuring cocoon1

Configuring Cocoon

  • cocoon.xconf

    • XML format

    • Contains Avalon component configuration

    • But not (!!) the sitemap components

      • They are in the sitemap

    • cocoon.xconf rarely needs changing

      • Moving from test to production

      • Replacing the XML parser


Configuring cocoon2

Configuring Cocoon

  • cocoon.xconf

    <?xml version="1.0"?>

    <cocoon version="2.0">

    <parser class="org.apache.cocoon.components.parser.XercesParser"/>

    <hsqldb-server class="org.apache.cocoon.components.hsqldb.ServerImpl"

    pool-max="1" pool-min="1">

    <parameter name="port" value="9002"/>

    <parameter name="silent" value="true"/>

    <parameter name="trace" value="false"/>

    </hsqldb-server>...

    </cocoon>


Configuring cocoon3

Configuring Cocoon

  • cocoon.xconf

    • No namespace

    • Each component defined inside <cocoon>

    • Logical names matched to implementations

      • e.g. parser; hsqldb-server

    • Configuration using <parameter>

      • Contains name-value pairs

    • pool-min and pool-max

      • We will look at those later (pooling)


Configuring cocoon4

Configuring Cocoon

  • cocoon.xconf

    • Another important piece of information

      • Location and name of the sitemap

        <sitemap file="context://sitemap.xmap"

        check-reload="yes"/>

    • Reloading

      • Triggers on incoming request

      • Synchronous

        • New sitemap will be generated and then handles the request

  • What do you do if an error occurs ............


Configuring cocoon5

Configuring Cocoon

  • LogKit Configuration

    • Each component in Cocoon logs using LogKit

    • There are five log levels

      • DEBUG

      • INFO

      • WARNING

      • ERROR

      • FATAL_ERROR

    • In testing: DEBUG

    • In production: ERROR or FATAL_ERROR

    • Location of the LogKit configuration file

      • Is in the web.xml:

        <init-param>

        <param-name>logkit-config</param-name>

        <param-value>/WEB-INF/logkit.xconf</param-value>

        </init-param>


Configuring cocoon6

Configuring Cocoon

  • LogKit Configuration

    • Consists of several parts

      • Factories for logging targets

        • Implementations are not "hard-wired"

        • Defines components that are to receive the log messages

      • Targets

        • Configured with Factory

        • And file name, output format, size/rotation information

      • Categories

        • Actual "receiver" of the log messages

        • Configured with (multiple) targets

        • And log level


Configuring cocoon7

Configuring Cocoon

  • LogKit Configuration

<logkit>

<factories>

<factory type="cocoon" class="org.apache.cocoon.util.log.CocoonTargetFactory"/>

</factories>

<targets>

<cocoon id="cocoon">

<filename>${context-root}/WEB-INF/logs/cocoon.log</filename>

<format type="cocoon">

%7.7{priority} %{time} [%8.8{category}] (%{uri}) %{thread}/%{class:short}:

%{message}\n%{throwable}

</format>

<append>true</append>

<rotation type="revolving" init="1" max="4">

<or>

<size>100m</size>

<time>01:00:00</time>

</or>

</rotation>

</cocoon>

<filter/>

</targets>

<categories>

<category name="cocoon" log-level="DEBUG">

<log-target id-ref="cocoon"/>

<log-target id-ref="filter"/>

</category>

</categories>

</logkit>


Configuring cocoon8

Configuring Cocoon

  • LogKit Configuration

    • (Normally) No need to change the setting

      • Apart from log-levels

      • Not reflected automatically

      • Touch cocoon.xconf

    • DEBUG logfiles can become very large

      • Hard drives have a limited capacity 

      • And slow performance down

    • Default level: ERROR for all categories


Dissecting cocoon

Dissecting Cocoon

A sitemap tour


Cocoon anatomy

Cocoon anatomy


Cocoon physiology

Cocoon physiology


The sitemap disemboweled

The sitemap disemboweled

  • The sitemap contains:

    • Component definitions and configurations

    • Views

    • Resources

    • Action sets

    • Flow

    • Pipelines

  • … all neatly packaged as a namespaced XML file

    <map:sitemap xmlns:map="http://xml.apache.org/cocoon/sitemap/1.0">

    <map:components/>

    <map:views/>

    <map:resources/>

    <map:action-sets/>

    <map:flow/>

    <map:pipelines/>

    </map:sitemap>


Sitemap components

Sitemap components

  • Configured as children of the <map:components> section

  • Contains:

    • Generators

    • Transformers

    • Serializers

    • Readers

    • Matchers

    • Selectors

    • Actions

    • Pipes

    • …and their configuration

  • Each section declaration can have a default component


Sitemap components tour

Sitemap components Tour

  • Generator, Transformers and Serializers are typical Cocoon components for pipelines

  • Readers are used for binary resources

    • Think of a “collapsed” Generator and Serializer

  • Matchers are used to route requests

  • Selectors implement branching (if… then… else) logic

  • Actions implement business logic based switching (old fashioned, flow is now the preferred way)

  • Pipes define different pipeline implementation (which differ mainly for caching policies)

  • Examples will follow


A word about actions

A word about Actions

  • Actions are reusable snippets of business logic

  • Actions wrap pipeline snippets

  • Actions can return either:

    • null: the pipeline snippet is skipped

    • A Map containing business values, which can be reused in the pipeline snippet

      <map:act type="clear-cache"><map:generate src="status"type="status"/><map:transform src="context://stylesheets/system/status2html.xslt"><map:parameter name="contextPath"value="{request:contextPath}"/></map:transform><map:serialize/>

      </map:act>


Sitemap components example

Sitemap components example

<map:components><map:generators/><map:transformers default="xslt"><map:transformer logger="sitemap.transformer.xslt"name="xslt"pool-max="32"src="org.apache.cocoon.transformation.TraxTransformer"><use-request-parameters>false</use-request-parameters><use-session-parameters>false</use-session-parameters><use-cookie-parameters>false</use-cookie-parameters><xslt-processor-role>xalan</xslt-processor-role><check-includes>true</check-includes></map:transformer></map:transformers><map:serializers/><map:readers/><map:actions/><map:pipes/></map:components>


Tip reusing components

Tip: reusing components

  • Components can be re-defined with different configurations,

  • Names have to be unique

    <map:transformer logger="sitemap.transformer.xalan"name="xalan"pool-max="32"src="org.apache.cocoon.transformation.TraxTransformer"><use-request-parameters>false</use-request-parameters><use-session-parameters>false</use-session-parameters><use-cookie-parameters>false</use-cookie-parameters><xslt-processor-role>xalan</xslt-processor-role><check-includes>true</check-includes></map:transformer><map:transformer logger="sitemap.transformer.xsltc"name="xsltc"pool-max="32"src="org.apache.cocoon.transformation.TraxTransformer"><use-request-parameters>false</use-request-parameters><use-session-parameters>false</use-session-parameters><use-cookie-parameters>false</use-cookie-parameters><xslt-processor-role>xsltc</xslt-processor-role><check-includes>true</check-includes></map:transformer>


Understanding views

Understanding views

  • Views are “exit points” in pipeline processing

  • Original motivation: semantic search

  • Current use: mainly debug

  • Configuration:

    • name: unique identifier

    • from-label: explicit exit point

    • from-position: implicit (automatic) exit point

      • first: right after the generator

      • last: right before the serializer

  • Activated by cocoon-view=view-name

  • Warning! Views are not inherited by subsitemaps

  • Warning! Views can be a security concern


More on views placing labels

More on views: placing labels

  • Labels are set using the label attribute on either:

    • A Generator or Transformer declaration in the components section (will work anywhere)

    • A Generate or Transform directive in a pipeline (specific to the pipeline)

    • An Aggregate or Part directive (more on this later)


View examples

View examples

  • Defining views:

    <map:views><map:view from-label="content"name="content"><map:serialize type="xml"/></map:view><map:view from-label="content"name="pretty-content"><map:transform src="stylesheets/system/xml2html.xslt"/><map:serialize type="html"/></map:view></map:views>

  • Defining labels:

    <map:generator label="content"logger="sitemap.generator.file"

    name="file"pool-max="32”

    src="org.apache.cocoon.generation.FileGenerator"/>


Resources

Resources

  • Reusable pipeline fragments

  • Useful for repetitive tasks

  • Will be (mostly) replaced by Virtual Sitemap Components

  • Warning! Resources are not inherited by subsitemaps


A resource example

A resource example

  • Defining a resource:

    <map:resources><map:resource name="simple-page2html"><map:transform src="context://samples/common/style/xsl/html/simple-page2html.xsl"><map:parameter name="contextPath"value="{request:contextPath}"/><map:parameter name="servletPath"value="{request:servletPath}"/><map:parameter name="sitemapURI"value="{request:sitemapURI}"/><map:parameter name="file"value="{file}"/><map:parameter name="remove"value="{../0}"/></map:transform></map:resource></map:resources>

  • Calling a resource

    <map:call resource="simple-page2html"><map:parameter name="file"value="forms/form1_success.xsp"/>

    </map:call>


Action sets

Action-sets

  • Define a set of actions to be executed as a unit of work either:

    • Unconditionally (upon every invocation)

    • When explicitely called, using a cocoon-action parameter

      <map:action-sets><map:action-set name="shop-actions"><map:act type="session-invalidator"action="logoff"/><map:act type="session-validator"/> <!-- Always executed --><map:act type="cart-add"action="addItem"/><map:act type="cart-remove"action="removeItem"/><map:act type="cart-remove-all"action="removeAll"/><map:act type="cart-update"action="updateQty"/><map:act type="order-add"action="addOrder"/><map:act type="order-verify"action="verifyOrder"/><map:act type="navigator"src="{1}"/> <!-- Always executed -->

      </map:action-set></map:action-sets>


Declaring flow scripts

Declaring flow scripts

  • Flow is a new way to insert page flow control in your application (much more on that later)

  • Scripts and/or classes are declared in the flow section of the sitemap

    <map:flow language="javascript">

    <map:script src="calc.js"/>

    </map:flow>

    <map:flow language="java"><map:script

    src="org.apache.cocoon.samples.flow.java.CalculatorFlow"/><map:script src="org.apache.cocoon.samples.flow.java.FormFlow"/><map:script

    src="org.apache.cocoon.samples.flow.java.PersistenceFlow"/>

    </map:flow>


The pipelines section

The pipelines section

  • The “heart” of Cocoon, where things get done

  • Contains 1+ <map:pipeline> declarations

  • Any pipeline section represents a logical division

  • Different pipelines serve different purposes:

    • Visibility: internal-only pipelines can only be just using the cocoon: protocol;

    • Caching, as pipelines can be:

      • non-cached (always executed)

      • cached delegating validity to the pipeline components (executed if nothing has changed in the pipeline)

      • cached beforehand using the expires directive (executed only once during the validity period)


Cocoon pipelines dissected

Cocoon pipelines dissected

  • Pipelines are “recipes” building resources

  • SAX events travel through the pipeline

  • The TLA is GTS: Generator, Transformer, Serializer

  • Generators are adapters from the outside world to SAX events

  • Transformers are SAX filters

  • Serializers are the opposite of Generators, adapting SAX events to the outside world

  • The obligatory diagram:


What s in a pipeline

What’s in a pipeline?

  • Well, components in action: from nouns to verbs

  • Content production:

    • generate [- transform ] - serialize

    • aggregate - part [ - part …]

    • read

  • Branching:

    • match

    • select

    • act

    • call


So what s the sitemap again

So what’s the sitemap, again?

  • Central switchboard (or FrontController, if you like patterns)

  • Contains component declarations (yes, even business components)

  • Locates (match) and builds (pipelines) the final result

  • In most cases, it’s the only file you’ll need to touch


A typical request cycle in cocoon

A typical request cycle in Cocoon

  • The environment is checked for the proper pipeline to use (normally via matching/selecting)

  • The pipeline is evaluated:

    • Sitemap components are looked up via type references or default assignment

    • The pipeline is setup.

  • The pipeline is executed

    Warning: no dynamic sitemap routing!


Zen and the art of matching

Zen and the art of matching


A perfectly valid pipeline example

A perfectly valid pipeline example

<map:pipeline>

<map:generate src=”hello.xml" type="file"/>

<map:transform src=”hello2html.xsl" type="xslt"/>

<map:serialize type="html"/>

</map:pipeline>

  • Would match any request and greet the user

  • … which is probably not what you want


Matchers kick in

Matchers kick in

  • Matchers associate the actual environment to a pipeline

    <map:pipeline>

    <map:match pattern=”hello” type="wildcard">

    <map:generate src=”hello.xml" type="file"/>

    <map:transform src=”hello2html.xsl" type="xslt"/>

    <map:serialize type="html"/>

    </map:match>

    <map:pipeline>

  • Hit http://localhost:8888/hello


Semantic problem

Semantic problem

  • Warning, pitfall ahead!

    • Formally a pipeline is everything included in <map:pipeline>

    • Colloquially, though, a pipeline is normally the G-T-S part

      <map:pipeline>

      <map:match pattern=”hello” type="wildcard">

      <map:generate src=”hello.xml" type="file"/>

      <map:transform src=”hello2html.xsl" type="xslt"/>

      <map:serialize type="html"/>

      </map:match>

      <map:match pattern=”goodbye” type="wildcard">

      <map:generate src=”goodbye.xml" type="file"/>

      <map:transform src=”bye2html.xsl" type="xslt"/>

      <map:serialize type="html"/>

      </map:match>

      <map:pipeline>


Why the fuss

Why the fuss?

  • A pipeline, formally, is everything that starts with a Generator and ends with a Serializer

  • This sample, then, is perfectly valid:

    1:<map:pipeline>

    2: <map:match pattern=”hello” type="wildcard">

    3:<map:generate src=”hello.xml" type="file"/>

    4: </map:match>

    5: <map:match pattern=”goodbye” type="wildcard">

    5: <map:generate src=”goodbye.xml" type="file"/>

    7: </map:match>

    8: <map:transform src=”greeting2html.xsl" type="xslt"/>

    9:<map:serialize type="html"/>

    10:<map:pipeline>


To make things further complicated

To make things further complicated…

  • This one is valid as well:

    1:<map:pipeline>

    2: <map:match pattern=”hello” type="wildcard">

    3:<map:generate src=”hello.xml" type="file"/>

    4; <map:transform src=”greeting2html.xsl" type="xslt"/>

    5:<map:serialize type="html"/>

    6: </map:match>

    7: <map:match pattern=”goodbye” type="wildcard">

    8: <map:generate src=”goodbye.xml" type="file"/>

    9: </map:match>

    10: <map:transform src=”greeting2html.xsl" type="xslt"/>

    11:<map:serialize type="html"/>

    12:<map:pipeline>


Argh where is my aspirin

Argh! Where is my aspirin?

  • … but this one could not be:

    1:<map:pipeline>

    2: <map:generate src=”hello.xml" type="file"/>

    3: <map:match pattern=”hello” type="wildcard">

    4:<map:generate src=”hello.xml" type="file"/>

    5: <map:transform src=”greeting2html.xsl" type="xslt"/>

    6:<map:serialize type="html"/>

    7: </map:match>

    8: <map:match pattern=”goodbye” type="wildcard">

    9: <map:generate src=”goodbye.xml" type="file"/>

    10: </map:match>

    11: <map:transform src=”greeting2html.xsl" type="xslt"/>

    12:<map:serialize type="html"/>

    13:<map:pipeline>


Bottom line

Bottom line

  • Cocoon will process the sitemap and try to build a G-[T]-S pipeline

  • Cocoon will stop processing when a Serializer is met

  • Beware the “Generator already set” errors!

  • You can’t have a “Serializer already set” error


Understanding matchers

Understanding matchers

  • Matchers will “route” a user request through Cocoon pipelines

  • Matchers are evaluated in order: first match wins

  • Matchers are available for the whole environment, matching on:

    • Request URI

    • Request parameters

    • Request Attributes

    • Session Attributes

    • Cookies

    • … and more

  • Matchers are pluggable: write your own!


Using matchers

Using matchers

  • A basic example:

    <map:match pattern=""><map:generate src="welcome.xml"/><map:transform src="welcome.xslt"/><map:serialize type="xhtml"/></map:match>

  • Captures an empty URI


Wildcard based matching

Wildcard-based matching

  • Wildcard match part of the URI using special chars (*/**)

  • A single asterisk matches everything up to the first forward slash

    <map:match pattern=”welcome-*"><map:generate src="welcome.xml"/><map:transform src="welcome.xslt"/><map:serialize type="xhtml"/></map:match>

    • Matches http://localhost:8888/welcome-friend

  • A double asterisk matches everything

    <map:match pattern=”welcome**"><map:generate src="welcome.xml"/><map:transform src="welcome.xslt"/><map:serialize type="xhtml"/></map:match>

    • Matches http://localhost:8888/welcome/friend


Capturing matcher results

Capturing matcher results

  • Captured parts of a URI are available for later use

  • Ordered list, denoted by position number in curly braces

  • Starts at 1

    <map:match pattern=”welcome-*"><map:generate src="welcome-files/{1}.xml"/><map:transform src="welcome.xslt"/><map:serialize type="xhtml"/></map:match>

    • Matches http://localhost:8888/welcome-friend

    • Uses welcome-files/friend.xml as the generator input

  • Can be arbitrarily complex:

    <map:match pattern="linkstatus/*/*/**"><map:generate src="http://{1}:{2}/{3}"type="linkstatus"/><map:transform src="stylesheets/system/linkstatus2html.xslt"/><map:serialize/></map:match>


Nesting matchers

Nesting matchers

  • Matchers can be nested:

    <map:match pattern=”welcome-**">

    <map:match pattern=”friend-*">

    <map:generate src="welcome-files/ {1}.xml"/>

    </map:match>

    <map:match pattern=”foe-*">

    <map:generate src=”goaway/{1}.xml"/>

    </map:match> <map:transform src="welcome.xslt"/><map:serialize type="xhtml"/></map:match>


Nesting matchers capturing parent results

Nesting matchers: capturing parent results

  • The matched expression on the child matcher doesn’t take into account the part already matched

  • “Parent” captured expressions are available with a tree navigation syntax:

    <map:match pattern=”welcome-**">

    <map:match type=”host-matcher” pattern=”localhost">

    <map:generate src=”local-files/{../1}.xml"/>

    </map:match>

    <map:match type=”host-matcher” pattern=”*.mydomain.com">

    <map:generate src=”remote-files/{1}/{../1}.xml"/>

    </map:match> <map:transform src="welcome.xslt"/><map:serialize type="xhtml"/></map:match>


Dealing with sources

Dealing with Sources


The source abstraction

The Source abstraction

  • Abstracts a stream based data source

  • Sub interfaces define write mode and tree-like navigation (à lajava.io.File)

  • URL-like syntax (with some bastardization)


The source interface1

The Source interface


Available sources

Available sources

  • Remote sources:

    • URLSource: deals with every protocol available for java.net.URL

    • FileSource: manages local files

    • WebDAVSource: interoperates with WebDAV repositories

    • XMLDBSource: connects to NXDs

    • BlobSource: uses databases blobs

  • “Meta” sources:

    • SitemapSource: uses Cocoon pipelines as data stream sources

    • ResourceSource: grabs data from classpath

    • ContextSource: accessed streams from the webapp context

    • ModuleSource: converts modules into sources

    • CachedSource: decorates sources adding passive caching


The sitemap source

The Sitemap Source

  • Calls cocoon pipelines

  • Weirdo:

    • When used in a generator or transformer, the called pipeline serializer will be ignored

    • When used in a reader, the serializer will be honored

  • More weirdos: URL bastardization

    • cocoon:/ will call a pipeline starting from the current sitemap

    • cocoon:// will call a pipeline starting from the root sitemap


Cocoon components tour

Cocoon Components Tour

A journey through Generators, Transformers, Serializers, Readers, Matchers, Sub-sitemaps, Modules, Error handling and more


Components tour

Components Tour

  • Cocoon has roughly 400 components:

    • 66 Generators

    • 65 Transformers

    • 23 Serializers

    • 10 Readers

    • 37 Matchers

    • 31 Selectors

    • 88 Actions

    • 59 Input/Output Modules

  • And you might want to write your own

  • No way to cover them all… we’ll see the most useful


Useful stuff filegenerator

Useful stuff: FileGenerator

  • Actually it’s a SourceGenerator: can deal with every Source data stream

  • … which includes cocoon:// URIs

  • Probably the most used generator in Cocoon


Useful stuff directory traversal

Useful stuff: Directory Traversal

  • Operate on TraversableSources (directories)

  • Provide an XML listing of the requested resources

  • Available components:

    • DirectoryGenerator

      • ImageDirectoryGenerator

      • MP3DirectoryGenerator

    • TraversableGenerator

    • TraversableSourceDescriptionGenerator

    • XPathTraversableGenerator


Useful stuff more generators

Useful stuff: more generators

  • JXTemplateGenerator: inspired by JSTL, more on this later

  • RequestGenerator: XMLized Request object

  • SessionAttributeGenerator: streams an object stored in session as XML

  • StreamGenerator: reads and streams XML from a request InputStream (e.g. POST requests)

  • HttpProxyGenerator: accesses an XML stream over HTTP

  • HTMLGenerator: grabs HTML from a source, converts to XHTML using jTidy and streams it away


Useful stuff traxtransformer

Useful stuff: TraxTransformer

  • Can use either (and concurrently):

    • TRAX

    • Xalan

    • Saxon

  • Relevant configuration parameters:

    <use-request-parameters>true|false</use-request-parameters>

    <use-session-parameters>true|false</use-session-parameters>

    <use-cookie-parameters>true|false</use-cookie-parameters>

    <xslt-processor-role>trax|xalan|xsltc</xslt-processor-role>

    <check-includes>true</check-includes>

  • Beware caching impact!


Useful stuff i18ntransformer

Useful stuff: I18NTransformer

  • Incredibly useful for dictionaries and localization

  • Golden rule: use it

  • Relevant configuration:

    <map:transformer name="i18n"logger="sitemap.transformer.i18n"src="org.apache.cocoon.transformation.I18nTransformer"><catalogues default="messages"><catalogue id="messages"name="messages"location="translations"/><catalogue id="menu"name="menu"location="translations"/><catalogue id="tiered"name="messages"><location>translations/tiered</location><location>translations</location></catalogue></catalogues><cache-at-startup>true</cache-at-startup>

    </map:transformer>


Dissecting i18ntransformer

Dissecting I18NTransformer

  • Resolving catalogue files:

    • name, id: unique identifiers and base names for files

    • location: a source to be prepended to the base names

    • Locale will be appended, in full or short form (en_US or en as a fallback).

    • Finally, “.xml” will complete the file name

  • So:

    <catalogue id="messages"name="messages”location="translations"/>

  • Assuming “en_US” as locale, the transformer will look for:

    translations/messages_en_US.xml

    translations/messages_en.xml

    translations/messages.xml


I18n catalog files

I18N catalog files

<catalogue xml:lang="en">

<message key="Apache Cocoon i18n Samples">Apache Cocoon i18n Samples</message><message key="Samples">Samples</message><message key="Introduction">Introduction</message><message key="Static (XML)">Static (XML)</message><message key="Dynamic (XSP)">Dynamic (XSP)</message><message key="Sitemap source">Sitemap source</message><message key="Locales">Locales</message><message key="Documentation">Documentation</message><message key="i18n transformer docs"><![CDATA[<I18ntransformer> docs]]></message><message key="i18n transformer Javadoc"><![CDATA[<I18ntransformer> Javadoc]]></message><message key="LocaleAction Javadoc"><![CDATA[<LocaleAction> Javadoc]]></message><message key="Credits">Credits</message><message key="Konstantin Piroumian">Konstantin Piroumian</message><message key="Many others...">Many others...</message>

</catalogue>


Using the i18ntransformer

Using the I18NTransformer

  • From then you can happily translate:

  • Elements

    <title><i18n:text>titletext</i18n:text>

    </title>

  • Attributes

    <para title="first"name="article" i18n:attr="title name">

  • Dates

    <i18n:date-time pattern="MEDIUM"/>

  • Numbers

    <i18n:number type="percent"src-locale="en"value="1.2"/>


Useful stuff cincludetransformer

Useful stuff: CIncludeTransformer

  • Dynamically inserts content in XML streams

  • Reacts to elements in the http://apache.org/cocoon/include/1.0 namespace

    <page   xmlns:cinclude="http://apache.org/cocoon/include/1.0"><title>Hello</title><content><para>This is my first Cocoon page!</para><cinclude:include src="include.xml"element="included"/></content></page>

  • Can be cached as well:

    <map:transform type="cinclude"><map:parameter name="expires"value="600"/>

    </map:transform>

    <cinclude:cached-include src="include.xml"/>


Useful stuff sourcewritingtransformer

Useful stuff: SourceWritingTransformer

  • Useful to write XML data to (Writeable) Sources during pipeline execution

    • e.g., save a file

  • Reacts to elements in the http://apache.org/cocoon/source/1.0 namespace

  • Typically used with XSLT building the source:* stuff

  • Read the Javadocs for details

    <page><source:write create="true”

    xmlns:source="http://apache.org/cocoon/source/1.0"><source:source>file://tmp/test.write</source:source><source:fragment><title>a title</title><content>       ...</content></source:fragment></source:write></page>


Useful stuff xmlserializer

Useful stuff: XMLSerializer

  • Outputs, well, XML.

  • Configurable encodings and doctypes:

    <map:serializer logger="sitemap.serializer.xhtml"

    mime-type="application/xhtml+xml"name="xhtml11”

    src="org.apache.cocoon.serialization.XMLSerializer"><doctype-public>-//W3C//DTD XHTML 1.1//EN</doctype-public><doctype-system>

    http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd

    </doctype-system>

    <encoding>UTF-8</encoding>

    </map:serializer>


Useful stuff fopserializer

Useful stuff: FOPSerializer

  • Uses Apache FOP to produce:

    • PDF

    • PS

    • PCL

    • RTF

      <map:serializer logger="sitemap.serializer.fo2pdf"

      mime-type="application/pdf"name="fo2pdf"src="org.apache.cocoon.serialization.FOPSerializer"><user-config>WEB-INF/fop-config.xml</user-config><set-content-length>true</set-content-length>

      </map:serializer>

      <map:serializer logger="sitemap.serializer.fo2ps"

      mime-type="application/postscript"name="fo2ps"src="org.apache.cocoon.serialization.FOPSerializer"/>

      <map:serializer logger="sitemap.serializer.fo2pcl"

      mime-type="vnd.hp-PCL"name="fo2pcl"src="org.apache.cocoon.serialization.FOPSerializer"/>


Useful stufff svgserializer

Useful stufff: SVGSerializer

  • Takes SVG as input, produces JPEG/PNG as output

  • Uses Apache Batik

    <map:serializer logger="sitemap.serializer.svg2jpeg"

    mime-type="image/jpeg"name="svg2jpeg"src="org.apache.cocoon.serialization.SVGSerializer"><parameter name="quality"type="float"value="0.9"/>

    </map:serializer>

    <map:serializer logger="sitemap.serializer.svg2png"

    mime-type="image/png"name="svg2png”

    src="org.apache.cocoon.serialization.SVGSerializer"/>


Useful stuff imagereader

Useful stuff: ImageReader

  • Will serve images (surprise!)

  • The kick: performing width, height, ratio adjustments (great for thumbnails)

    <map:match pattern="image-size-*"><map:read type="image"src="logo.jpg"><map:parameter name="width"value="{1}"/><map:parameter name="height"value="{1}"/></map:read>

    </map:match>


Sub sitemaps

Sub sitemaps

  • Sitemaps could become overpopulated and messy (the Perl effect)

  • Solution: modularize using sub-sitemaps

  • From the main sitemap match the parent path and mount a sitemap underneath:

    <map:match pattern="xsp/**"><map:mount uri-prefix="xsp"src="xsp.xmap" /></map:match>

  • Wildcard substitution, of course, works:

    <map:match pattern="~*/**">

    <map:mount src="/home/{1}/public_html/"uri-prefix="~{1}"/></map:match>


Input output modules

Input/Output Modules

  • Modules create generic components and plug actual input/output at runtime

  • Example: grab a request parameter and use it in the sitemap

    <map:match pattern=”welcome">

    <map:generate src=”local-files/{request-param:file}.xml"/>

    <map:transform src="welcome.xslt"/><map:serialize type="xhtml"/></map:match>

  • Again: no dynamic routing possible

    • Modules are evaluated during the pipeline setup phase


Useful modules globalinputmodule

Useful modules: GlobalInputModule

  • Allows to configure global variables in the sitemap, with runtime substitution

  • Helps writing maintainable code

    <map:component-configurations><global-variables><staging>webdav://localhost/webdav/step1/</staging></global-variables></map:component-configurations><map:pipeline><map:match pattern="repo/"><map:generate type="traverse"src="{global:staging}repo/"><map:parameter name="depth"value="1"/></map:generate><map:serialize type="xml"/></map:match>

    </map:pipeline>


Useful modules xmlfileinputmodule

Useful modules: XMLFileInputModule

  • Allows XPath queries on external resources

  • Helps maintainability: configuration will be outside the sitemap

  • Configured in cocoon.xconf

    <component-instance  class="org.apache.cocoon.components.modules.input.XMLFileModule"logger="core.modules.xml"name=”settings"><file src="cocoon://${project.mount}/configuration/test.xhtml"reloadable="false"cacheable="true"/></component-instance>

    <map:generate type="traverse"src="{settings:/html/head/title}">


When things go wrong error handling

When things go wrong: error handling

  • Error conditions (exception) can be catched in the pipeline

  • Each pipeline can have a handle-errors section

  • Error handling is inherited

  • NotifyingGenerator provides errors in XML format

  • ExceptionSelector allows branching according to the exception


Error handling explained

Error handling explained

<map:selector logger="sitemap.selector.exception"name="exception"

src="org.apache.cocoon.selection.ExceptionSelector">

<exception class="o.a.c.ResourceNotFoundException"name="not-found"/>

<exception class="o.a.c.c.flow.InvalidContinuationException"

name="invalid-continuation"/>

</map:selector>

<map:handle-errors>

<map:select type="exception"><map:when test="not-found"><map:generate type="notifying"/><map:transform src="stylesheets/system/error2html.xslt”/><map:serialize status-code="404"/></map:when><map:when test="invalid-continuation"><map:generate type="notifying"/><map:transform src="stylesheets/system/error2html.xslt"><map:serialize status-code="404"/></map:when><map:otherwise><map:generate type="notifying"/><map:transform src="stylesheets/system/error2html.xslt"><map:serialize status-code="500"/></map:otherwise></map:select>

</map:handle-errors>


Flowscript

Flowscript

The magic of web continuations


Overview

Overview

  • Introduction

  • JavaScript features

  • View layer

  • Putting it all together

  • Session variables

  • Managing continuations


Introduction

Introduction

  • Need for flow control

    • What is "flow control" ?

      • Control of transition between pages

      • Driven by application logic

    • Aren't actions enough ?

      • Yes, but they require state management

      • Quickly becomes complex, hard to understand and to maintain


Introduction1

Introduction

  • Flow script : what is it ?

    • Simple and effective way to glue together business logic, presentation and page flow

    • Uses scripts written in JavaScript (server-side)

      • a simple scripting language

      • can implement the most complex use cases

    • 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


Introduction2

Introduction

  • Flow script example

varcart;

varuser;

functioncheckout()

{

while(user==null){

cocoon.sendPageAndWait("login.html");

user=UserRegistry.getUser(cocoon.request.get("name"));

}

cocoon.sendPageAndWait("shippingAddress.html",{who:user});

varaddress=cocoon.request.get("address");

cocoon.sendPageAndWait("creditCard.html");

varcreditCard=cocoon.request.get("creditCard");

cocoon.sendPageAndWait("confirmOrder.html");

EnterpriseSystem.placeOrder(user,cart,address,creditCard);

cocoon.sendPage("orderPlaced.html");

}


Introduction3

Introduction

  • JavaScript vs. Java detour

    • If you know Java, you already know JavaScript !Well, mostly.

    • JavaScript is dynamically typed (variables don’t have types, values do)

    • Prototype-based inheritance as opposed to class-based inheritance

    • Objects are extensible at runtime : add or remove properties and methods


Calling the view

Calling the view

  • cocoon.sendPage()

    • cocoon.sendPage invokes the output page (view) with two arguments

      • The view URL, relative to current sitemap

      • A context Map made available to the view

         Can contain Java or JavaScript objects

    • 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});


Calling the view1

Calling 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


Continuations

Continuations

  • 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


Continuations1

Continuations

saved continuations

  • Sample flow script revisited

varcart;

varuser;

functioncheckout()

{

while(user==null){

cocoon.sendPageAndWait("login.html");

user=UserRegistry.getUser(cocoon.request.get("name"));

}

cocoon.sendPageAndWait("shippingAddress.html",{who:user});

varaddress=cocoon.request.get("address");

cocoon.sendPageAndWait("creditCard.html");

varcreditCard=cocoon.request.get("creditCard");

cocoon.sendPageAndWait("confirmOrder.html");

EnterpriseSystem.placeOrder(user,cart,address,creditCard);

cocoon.sendPage("orderPlaced.html");

}


View layer jxtemplate

View layer : JXTemplate

  • What is JXTemplate ?

    • An XML template language inspired by JSTL

    • Doesn't allow code, but only access to context variables

       More simple, more secure

    • Flow values are provided as variables :

    • 2 expression languages : Jexl and JXPath

<jx:forEach var="item" items="${cart.items}">

<p>Name: <jx:out value="${item.name}"/></p>

</jx:forEach>

<a href="kont/${continuation.id}">Continue</a>


View layer jxtemplate1

View layer : JXTemplate

  • Jexl

    • JSTL & Velocity's expression language

      • JavaBean property navigation language

         Property navigation using "."

      • Expressions enclosed in ${…}

         More suited to Java objects

You are calling from ${request.remoteHost}

http://jakarta.apache.org/commons/jexl/


View layer jxtemplate2

View layer : JXTemplate

  • JXPath

    • XPath on abitrary object graphs

      • XML documents, but also JavaBeans

      • Expressions enclosed in #{…}

         Equally suited to XML documents and Java objects

You are calling from #{$request/remoteHost}

 http://jakarta.apache.org/commons/jxpath/


Putting it all together

Putting it all together

  • The sitemap

<map:flow language="JavaScript">

<map:script src="store.js"/>

</map:flow>

<map:pipelines>

<map:pipeline>

<map:match pattern="checkout/">

<map:call function="checkout"/>

</map:match>

<map:match pattern="*.html"/>

<map:generate src="{1}.jx"/>

<map:transform src="page2html.xsl"/>

<map:serialize/>

</map:match>

<map:match pattern="kont/*">

<map:call continuation="{1}"/>

</map:match>

…/…

Call a flow function

Called by the flow

Ressurect a continuation


Putting it all together1

Putting it all together

  • Recap

    • Controller is composed of flow scripts written in JavaScript

      • use sendPageAndWait() to send a response and temporarily suspend execution

    • Views are regular pipeline with access to flow data

      • JPath XSP tag library

      • JXTemplate generator

    • Model : your Java business logic

    • Sitemap glues everything together


The cocoon global object

The "cocoon" global object

  • Access to the environment

    • "request", "response", "session " and "context" properties

    • "parameter" : sitemap parameters

  • Access to the framework

    • Logging :"log" property

       cocoon.log.debug("Hi there");

    • Getting components

       cocoon.getComponent("org.apache.excalibur.xml.Parser")

       cocoon.releaseComponent(parser)


The cocoon global object1

The "cocoon" global object

  • Script modularization

    • JavaScript has no "import" feature

       cocoon.load("resource://other/script.js")

  • Page flow control

    • cocoon.sendPage(), cocoon.sendPageAndWait()

       Internal calls to the sitemap

    • cocoon.redirectTo("foo.html")

       External redirect sent to the browser


Session variables

Session 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 !


Session variables1

Session variables

  • Example

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("orderPlaced.html");

}

function logout() {

user = null;

sendPage("bye.html");

}

Shows the login screenonly if needed

Won't pass through if not logged !

Just clear user info to log out


Managing continuations

Managing continuations

  • Continuation trees

    • Browser "back" or "new window"

varcart;

varuser;

functioncheckout()

{

while(user==null){

cocoon.sendPageAndWait("login.html");

user=UserRegistry.getUser(cocoon.request.get("name"));

}

cocoon.sendPageAndWait("shippingAddress.html",{who:user});

varaddress=cocoon.request.get("address");

cocoon.sendPageAndWait("creditCard.html");

varcreditCard=cocoon.request.get("creditCard");

cocoon.sendPageAndWait("confirmOrder.html");

EnterpriseSystem.placeOrder(user,cart,address,creditCard);

cocoon.sendPage("orderPlaced.html");

}


Managing continuations1

Managing 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


Managing continuations2

Managing continuations

  • Expiring continuations

    • Manual expiration :

      • sendPageAndWait() returns its continuation k

      • 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");

...

BusinessService.commit();

// Cannot go back again

k.invalidate();


Conclusion

Conclusion

  • 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

       Handling of "back" and "new window"


Development tools

Development tools

  • Flow script debugger

    • Activated in cocoon.xconf


Dealing with forms

Dealing with forms

The powerful Cocoon forms framework


Introduction4

Introduction

  • 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 Cocoon Forms…


Cocoon forms principles

Cocoon Forms principles

  • Main requirements

    • Strong typing and formatting

       A date input will give a java.util.Date

       Support for localized input formats

    • No requirement for a form bean

       The form has its own data model

    • Easy and safe binding to the data model

       Only when the all inputs are valid

       No direct link from request to application data

    • Strong separation of form definition and styling

    • Extensibility

       Everything is a component


Cocoon forms principles1

Cocoon Forms principles

  • The big picture


Cocoon forms principles2

Cocoon Forms 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

publicinterfaceWidget{

publicWidgetgetParent();

publicvoidsetParent(Widgetwidget);

publicWidgetgetWidget(Stringid);

publicStringgetId();

publicStringgetFullyQualifiedId();

publicvoidreadFromRequest(FormContextformContext);

publicObjectgetValue();

publicvoidsetValue(Objectobject);

publicbooleanvalidate(FormContextformContext);

publicvoidgenerateSaxFragment(ContentHandlercontentHandler,Localelocale);

publicvoidgenerateLabel(ContentHandlercontentHandler);

}

Naming

Widget hierarchy

Parsing and validation

XML output


Cocoon forms principles3

Cocoon Forms principles

  • Form definition overview

<fd:form xmlns:fd="http://apache.org/cocoon/forms/1.0#definition">

<fd:widgets>

<fd:field id="name" required="true">

<fd:label>Name:</fd:label>

<fd:datatype base="string">

<fd:validation>

<fd:length min="2"/>

</fd:validation>

</fd:datatype>

</fd:field>

<fd:field id="email" required="true">

<fd:label>Email address:</fd:label>

<fd:datatype base="string">

<fd:validation>

<fd:email/>

</fd:validation>

</fd:datatype>

</fd:field>

…/…

<fd:widgets>

</fd:form>


Cocoon forms principles4

Cocoon Forms principles

  • Form template overview

    • Embeds widget references in target markup

<html xmlns:ft="http://apache.org/cocoon/forms/1.0#template">

<head>

<title>Registration form</title>

</head>

<body>

<h1>Registration</h1>

<ft:form-template action="registration" method="POST">

<ft:widget-label id="name"/>

<ft:widget id="name"/>

<br/>

<ft:widget-label id="email"/>

<ft:widget id="email"/>

<br/>

…/…

<input type="submit"/>

</ft:form-template>

</body>

</html>


Cocoon forms principles5

Cocoon Forms principles

  • Resulting output


The form definition file

The form definition file

  • Widgets

    • Standard widgets

      • <fd:form> : the main form widget

      • <fd:field> : "atomic" input field

      • <fd:booleanfield> : boolean input

      • <fd:mutivaluefield> : multiple selection in a list

      • <fd:repeater> : collection of widgets

      • <fd:output> : unmodifiable widget

      • <fd:action> : action button

      • <fd:tree> : a tree-shaped widget

    • They're all defined in cocoon.xconf

       Add your own if needed


The form definition file1

The form definition file

  • The <fd:field> widget

    • Definition overview

    • The label can contain abitrary markup

      • Including i18n references

<fd:field id="..." required="true|false">

<fd:label>...</fd:label>

<fd:datatype base="...">

[...]

</fd:datatype>

<fd:selection-list>

[...]

</fd:selection-list>

</fd:field>

<fd:label>Your <b>name</b></fd:label>

<fd:label>

<i18n:text key="name-field-label"/>

</fd:label>


The form definition file2

The 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

<fd:datatype base="...">

<fd:convertor>

[...]

</fd:convertor>

<fd:validation>

[...]

</fd:validation>

</fd:datatype>

Parsing and formatting

Validation


The form definition file3

The 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

<fd:datatype base="date">

<fd:convertor type="formatting">

<fd:patterns>

<fd:pattern>yyyy-MM-dd</fd:pattern>

<fd:pattern locale="en">MM/dd/yyyy</fd:pattern>

<fd:pattern locale="fr">dd/MM/yyyy</fd:pattern>

<fd:pattern locale="nl-BE">dd/MM/yyyy</fd:pattern>

<fd:pattern locale="de">dd.MM.yyyy</fd:pattern>

</fd:patterns>

</fd:convertor>

</fd:datatype>


The form definition file4

The 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

       Example : email input field

<fd:field id="email">

<fd:datatype base="string">

<fd:validation>

<fd:length max='100'/>

<fd:email>

<fd:failmessage>Not a valid email address!</fd:failmessage>

</fd:email>

</fd:validation>

</fd:datatype>

</fd:field>


The form definition file5

The form definition file

  • Selection lists

    • Provide enumerations to the user

      • List of items having a value

      • Optional item label

    • Selection lists can be external and dynamic

<fd:field name="OS">

<fd:datatype base="string"/>

<fd:selection-list>

<fd:item value="Linux"/>

<fd:item value="Windows"/>

<fd:item value="Mac OS"/>

<fd:item value="Solaris"/>

<fd:item value="other">

<fd:label><i18n:text key="other"/></fd:label>

</fd:item>

</fd:selection-list>

</fd:field>

<fd:selection-list src="cocoon:/build-list.xml">


The form definition file6

The form definition file

  • The <fd:booleanfield> widget

    • Boolean values

       Usually rendered as a checkbox

<fd:booleanfield id="somebool">

<fd:label>Put me <em>on</em> or <em>off</em>.</fd:label>

</fd:booleanfield>


The form definition file7

The form definition file

  • The <fd:multivaluefield> widget

    • Allows the selection of several values

      • The value is an Object[]

         Requires a <fd:selection-list>

<fd:multivaluefield id="drinks">

<fd:label>Indicate your 2 most preferred drinks:</fd:label>

<fd:datatype base="string">

<fd:validation>

<fd:value-count exact="2"/>

</fd:validation>

</fd:datatype>

<fd:selection-list>

<fd:item value="Maes"/>

<fd:item value="Jupiler"/>

<fd:item value="Leffe"/>

<fd:item value="Hoegaarden"/>

<fd:item value="Coca Cola"/>

</fd:selection-list>

</fd:multivaluefield>


The form definition file8

The form definition file

  • The <fd:repeater> widget

    • Repeats a number of child widgets

       Used to manage collections, tables, etc.

<fd:repeater id="contacts">

<fd:field id="firstname">

<fd:label>Firstname</fd:label>

<fd:datatype base="string"/>

</fd:field>

<fd:field id="lastname">

<fd:label>Lastname</fd:label>

<fd:datatype base="string"/>

</fd:field>

</fd:repeater>


The form definition file9

The form definition file

  • The <fd:output> widget

    • Read-only widget

      • Provides formatting features

      • But doesn't read its value from the request

<fd:output id="shipping-date">

<fd:label>

<i18n:text key="shipping-date.label"/>

</fd:label>

<fd:datatype base="date">

<fd:convertor type="formatting" style="short"/>

</fd:datatype>

</fd:output>


The form definition file10

The form definition file

  • The <fd:action> widget

    • An action button other than standard "submit"

      • Allows various actions to be taken on the form

         "action-command" defines the event name

<fd:repeater id="contacts">

<fd:field id="firstname">

<fd:label>Firstname</fd:label>

<fd:datatype base="string"/>

</fd:field>

<fd:field id="lastname">

<fd:label>Lastname</fd:label>

<fd:datatype base="string"/>

</fd:field>

<fd:booleanfield id="select"/>

</fd:repeater>

<fd:action id="add" action-command="add-contact">

<fd:label>Add contact</fd:label>

</fd:action>

<fd:action id="remove" action-command="remove-selected-contacts">

<fd:label>Remove selected contacts</fd:label>

</fd:action>


The form template

The form template

  • The big picture (again)


The form template1

The form template

  • Role of the Cocoon FormsTransformer

    • "Expand" all ft: elements

<htmlxmlns:ft="http://apache.org/cocoon/forms/1.0#instance">

<head>

<title>Registration form</title>

</head>

<body>

<h1>Registration</h1>

<fi:form-template action="registration" method="POST">

Name:

<fi:field id="name">

<fi:label>Name:</fi:label>

<fi:value>Cocoon</fi:value>

</fi:field>

<br/>

Email address:

<fi:widget id="email">

<fi:label>Email address:</fi:label>

<fi:value>foo</fi:value>

<fi:validation-message>

Invalid email address

</fi:validation-message>

</fi:widget>

<br/>

…/…

<input type="submit"/>

</fi:form-template>

</body>

</html>

<htmlxmlns:ft="http://apache.org/cocoon/forms/1.0#template">

<head>

<title>Registration form</title>

</head>

<body>

<h1>Registration</h1>

<ft:form-template action="registration" method="POST">

<ft:widget-label id="name"/>

<ft:widget id="name"/>

<br/>

<ft:widget-label id="email"/>

<ft:widget id="email"/>

<br/>

…/…

<input type="submit"/>

</ft:form-template>

</body>

</html>

Validation failed


The form template2

The form template

  • Role of the FormsTransformer

    • Expand all "ft" elements in their "fi" counterpart

         ft = Cocoon Forms template

         fi = Cocoon Forms instance

    • Output of the transformer goes to styling

      • Provided : HTML styling

      • Other stylings are possible (e.g. WML)

         Cocoon Forms does not hardcode the presentation !


The form template3

The form template

  • The <ft:form-template> element

    • Setup the transformer context

       Retrieve the Form object from the environment

  • The <ft:widget-label> element

    • Copies the content of <fd:label>

       Used to separate label output from the full widget


The form template4

The form template

  • The <ft:widget> element

    • Produces the corresponding widget instance

      • Markup depends on the actual widget

      • For fields : <fi:label>, <fi:value>, <fi:selection-list>

    • <ft:widget> can contain styling information

      • Drives the styling stylesheet

         Contents of <fi:styling> depends on the styling !

<ft:widget id="fourchars">

<!-- particular styling for the enumeration -->

<fi:styling list-type="listbox" listbox-size="4"/>

</ft:widget>


The form template5

The form template

  • The <ft:repeater-widget> element

    • Iterates on the contents of a <fd:repeater>

      • Use to build e.g. tables

      • Produces indexed names for each iteration

  • <ft:repeater-widget-label>

    • Gets the label of a child of the repeater

      • Useful for table headers


The form template6

The form template

<table>

<tr>

<th>Name</th>

<th>Email address</th>

</tr>

<tr>

<td>

<fi:widget id="contacts.0.firstname">

<fi:label>Name</fi:label>

<fi:value>Harry</fi:value>

</fi:widget>

</td>

<td>

<fi:widget id="contacts.0.email">

<fi:label>Email address</fi:label>

<fi:value>[email protected]</fi:value>

</fi:widget>

</td>

</tr>

<tr>

<td>

<fi:widget id="contacts.1.firstname">

<fi:label>Name</fi:label>

<fi:value>Anakin</fi:value>

</fi:widget>

</td>

<td>

<fi:widget id="contacts.1.email">

<fi:label>Email address</fi:label>

<fi:value>[email protected]</fi:value>

</fi:widget>

</td>

</tr>

</table>

  • The <ft:repeater-widget> element

<table>

<tr>

<th>

<ft:repeater-widget-label

id="contacts" widget-id="firstname"/>

</th>

<th>

<ft:repeater-widget-label

id="contacts" widget-id="email"/>

</th>

</tr>

<ft:repeater-widget id="contacts">

<tr>

<td>

<ft:widget id="firstname"/>

</td>

<td>

<ft:widget id="email"/>

</td>

</tr>

</ft:repeater-widget>

</table>


Built in html styling

Built in HTML styling

  • The provided stylesheets

    •  »forms-field-styling.xsl"

      • Only styles basic inputs (fields & actions)

         many styling variants

    •    »forms-advanced-field-styling.xsl »

      • Advanced group layout

         fieldsets, tab panels, overlapping panels


Built in html styling1

Built in HTML styling

  • Field styling

    • Basic styling : html input

    • <fi:styling type="…">

      • "password"  <input type="password">

      • "hidden"  <input type="hidden">

      • "textarea"  <textarea>

      • "date"  date popup


Built in html styling2

Built in HTML styling

  • Fields with a <selection-list>

    • Basic styling : drop-down menu

    • <fi:styling type="…">

      • "listbox"  <select><option>…

      • "radio"  <input type="radio">

        • Additional "orientation" attribute (horizontal/vertical)

  • <multivaluefield>

    • Basic styling : check-boxes


Built in html styling3

Built in HTML styling

  • <fi:group>

    • Instance-only widget providing high-level styling

       No corresponding <fd:> nor <ft:>

      • Contains items that will be laid out

<fi:group>

<fi:label>Profile header</fi:label>

<fi:styling type="fieldset" layout="columns"/>

<fi:items>

<ft:widget id="revision"/>

<ft:widget id="identification"/>

<ft:widget id="name"/>

<ft:widget id="author"/>

<ft:widget id="classID"/>

<ft:widget id="releaseDate">

<fi:styling type="date"/>

</ft:widget>

<ft:widget id="additional-info"/>

</fi:items>

</fi:group>


Built in html styling4

Built in HTML styling

  • <fi:group> styling

    • Contents rendering

      • "layout" attribute : "columns"

         Automatic 2-column layout of widgets and labels

<fi:group>

<fi:label>Profile header</fi:label>

<fi:styling type="fieldset" layout="columns"/>

<fi:items>

<ft:widget id="revision"/>

[...]

</fi:items>

</fi:group>

type="fieldset"

layout="columns"


Built in html styling5

Built in HTML styling

  • <fi:group> styling

    • Container rendering

       "type" attribute : "fieldset", "tabs", "choice"

       Tabs defined with CSS

type="choice"

type="tabs"

Note : items in "tabs" and "choice" are most often subgroups


Binding linking forms to application data

Binding : linking 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

<fb:context

xmlns:fb="http://apache.org/cocoon/forms/1.0#binding"

xmlns:fd="http://apache.org/cocoon/forms/1.0#definition"

path="/data/user">

<fb:value id="email" path="email" readonly="true"/>

<fb:value id="number" path="[email protected]">

<fd:convertor datatype="long"/>

</fb:value>

<fb:value id="choose" path="[email protected]">

<fd:convertor datatype="boolean"/>

</fb:value>

</fb:context>

Set the context of included paths

Read-only widget

Associates a widget to a path

Binding convertor (XML is text)


Usage in flow script

Usage in flow script

  • The form.js library

    • Provides a Form class

      • Constructor takes a form definition file

    • Method Form.showForm() to display the form

      • Does not return until validation is ok !!

         Internal loop on sendPageAndWait()

Application data for the view

function edit_header() {

var form = new Form("forms/profile-header-def.xml");

form.showForm("view-profile-header.html", {foo: bar});

var revision-date = form.getModel().releaseDate;

...

sendDialog("Thanks a lot");

}

Getting form data


Usage in flow script1

Usage in flow script

  • Advanced features

    • Business-level validation

       Because not all constraints can be in the definition file

    • Knowing the <fd:action> that was hit

function edit_header() {

var limit = Application.getLimit();

var form = new Form("forms/profile-header-def.xml");

form.validator = function(form) {

var dateWidget = form.getWidget("releaseDate");

if (dateWidget.getValue() > limit) {

dateWidget.setValidationError("Out of limits");

returnfalse;

}

returntrue;

}

form.showForm("view-profile-header.html", {foo: bar});

if (form.submitID == 'cancel') {

sendDialog("Action cancelled");

} else {

var revision-date = form.getModel().releaseDate;

...

sendDialog("Thanks a lot");

}

}

Form is redisplayed if result is false

Test of the submit button


Usage in flow script2

Usage in flow script

  • Advanced features

    • Binding form and application data

function edit_header() {

var data = Application.getData();

var form = new Form("forms/profile-header-def.xml");

form.createBinding("forms/profile-header-binding.xml");

form.load(data);

form.showForm("view-profile-header.html", {foo: bar});

form.save(data);

sendDialog("Thanks a lot");

}


Putting it all together the sitemap

Putting it all together : the sitemap

  • HTTP method selection

    • GET method : start the flow

    • POST method : continue

    • Advantages

      • The form's action is "" (submit to the same URL)

      • Continuation management is hidden

<map:match pattern="edit_*.html">

<map:select type="method">

<!-- GET : start the flow for this screen -->

<map:when test="GET">

<map:call function="editor_{1}"/>

</map:when>

<!-- POST (form submission) : continue the flow -->

<map:when test="POST">

<map:call continuation="{request-param:continuation-id}"/>

</map:when>

</map:select>

</map:match>


Putting it all together the sitemap1

Putting it all together : the sitemap

  • View pipeline

    • Use of JXTemplate generator

      • Allows the use of application data passed to showForm()

    • Or just a plain file generator, using the template

<map:match pattern="view-*.html">

<map:generate type="jxtemplate" src="forms/{1}-tmpl.xml"/>

<map:transform type="forms"/>

<map:transform type="i18n"/>

<map:transform type="xslt" src="resources/editor-layout.xsl"/>

<map:serialize type="html"/>

</map:match>

<map:match pattern="view-*.html">

<map:generate type="file" src="forms/{1}-tmpl.xml"/>

<map:transform type="forms"/>

<map:transform type="i18n"/>

<map:transform type="xslt" src="resources/editor-layout.xsl"/>

<map:serialize type="html"/>

</map:match>


Conclusion1

Conclusion

  • A powerful form framework

    • Rich datatypes and validation rules

    • Easy extension to specific needs

  • Flow script makes it really easy

  • Future work

     Client-side validation

     Better event handling system

     Overall stabilization

Detailed documentation on http://wiki.cocoondev.org/Wiki.jsp?page=CForms


Summary

Summary

  • Good for complex / multi forms

  • Widget Oriented Approach

    • Custom validation rules

    • Dependencies

    • Strongly type data

  • Separation of declarations and templates

    • Modular

    • Reuse

  • Business Integration via Flow

  • I18n Support


Tales from the operation room

Tales from the operation room

8 simple rules for building a manageable Cocoon applications


Cocoon and manageability

Cocoon and manageability

  • Cocoon is a huge beast to master

  • Things tend to get out of hands quickly

  • The real Cocoon advantage is about increased manageability

    • So plan for it


Plan plan plan

Plan, plan, plan

  • Don’t start coding, start sketching

  • Customize the Cocoon environment:

    • Be ruthless in excluding blocks

    • Have a solid build system

    • Use mount-table wisely

    • Do version control local.build.properties and local.blocks.properties


Manage configuration files

Manage configuration files

  • You will need to modify configuration files:

    • Use Cocoon’s own XConfTool to patch Cocoon configurations

    • Separate configuration (patch) files by functionality

    • Have further configuration files to overcome the current Cocoon blocks limitations (why do you need JMS to access WebDAV?)

    • Don’t trust components in Cocoon’s main sitemap, declare them again


Relocation is not an option

Relocation is not an option

  • Users might install your application in a number of ways:

    • Directly from the webapp root

    • From a context path

    • As a sub-sitemap

  • Resource resolving needs to take this into account:

    • Use a mount-point variable

      <map:generate src="{global:mount-point}/some/where.xml">

    • Perform calculations (upcoming Cocoon versions)

      <map:generate src="{request:sitemapURIPrefix}/some/where.xml">


Samples are just samples

Samples are just samples

  • Don’t rely on them for any functionality

  • Import the required resources, don’t link to them

  • This is especially true for Cocoon Forms

    • Newer Cocoon versions have Forms resources packaged in a jar file

    • However, XSLTs are still included in samples


Separate application and user concerns

Separate application and user concerns

  • In most applications, users are supposed to manage configuration files

  • Keep user-accessible resources separated:

    • Client-side CSS, JS, images

    • Consider xsl:import (with performance in mind) as override mechanism


Package and ship

Package and ship

  • Ideally, package everything in a jar file

  • Yes, even sitemaps:

    <map:mount src=”resource://com/pnetx/app/sitemap.xmap"/>

  • Don’t forget:

    • Error management (map:handle-errors)

    • Error logging (logkit.xconf)


Wrapping up

Wrapping up

  • Long journey, and bumpy ride

  • Yet barely scratched the surface

  • More Cocoon presentations during ApacheCon:

    • DE1348: Tools for Content Management and Publishing in Apache: An Overview

    • DE1258: Single Source Publishing with Apache Forrest

    • DE1221: Cocoon - One Hour Portal

    • DE1244: Developing Enterprise Web Applications with Cocoon and Spring

    • DE1284: Creating Print on Demand solutions with Cocoon, FOP, and Lucene

    • DE1272: Powering High-volume web sites with Lenya/Cocoon and mod_cache


Thank you

Thank you!

Questions?


  • Login