Introduction to the Page Flow Controller
The Orbeon Forms Page Flow Controller (PFC) is the heart of your Orbeon Forms web application. It dispatches incoming user requests to individual pages built out of models and views, following the model / view / controller (MVC) architecture. The PFC is configured with a file called a page flow. A page flow not only describes the pages offered by your application, it also declaratively describes an entire application's navigation logic, allowing the development of pages and XML services completely independently from each other. The PFC encourages designing applications with a total separation between:
NOTE: By default, the PFC is configured in
web.xml as the main processor
for the Orbeon Forms servlet and portlet. However, you are not required to use the PFC
with Orbeon Forms: you can define your own main processor for servlets and portlets, as
documented in Packaging and
Deployment. For most web applications, the PFC should be used.
BasicsPage flow configuration
A page flow is usually defined in a file called
You can configure the location of the page flow configuration file in the web
application's PagesMost web applications consist of a set of pages, identified to clients (web browsers) by a certain URL, for example:
In most cases the URL can be split as follows:
For a particular web application, what usually matters in order to identify a
particular page is the path within the URL under the context
path, here
Other pages may be declared as follows:
A Simple pages
Creating a static page with Orbeon Forms is quite easy: just add a
Here, using the
The path is relative to the location of the page flow configuration file where
the
It is recommended to to use XHTML and to put all the elements in the XHTML
namespace, Instead of using a static XHTML page, you can also use an XSLT template to generate a dynamic page. This allows using XSLT constructs mixed with XHTML constructs, for example:
When XSLT templates are used, it is recommended to use the
Page model and page view
In the MVC architecture, the page logic is implemented by a page model, and the page layout by a page view. The MVC architecture promotes the separation of model, view and controller:
For instance, a news page can use a page model to retrieve the list of headlines and then pass this information as an XML document to a page view. The view produces an XHTML page by creating a table with the content of the headlines, adding a logo at the top of the page, a copyright notice at the bottom, etc.
Each PFC
The model passes data to the view as an XML document, as follows:
A model XPL pipeline and an XSLT view can
be declared as follows for the
Here, the location of the model and view definitions mirrors the path of the page, and file names repeat the directory path, so that files can be searched easier. It is up to the developer to choose a naming convention, but it is recommended to follow a consistent naming structure. Other possibilities include:
or:
A typical XSLT view can extract model data passed to it automatically by the PFC on its default input, for example, if the model generates a document containing the following:
Then an XSLT view can display the content of the
XML submissionRationaleA page built out of a model and a view can retrieve information from a data source and format it. However, this is not enough to make a page which can use parameters submitted by a client to configure what data is being presented, or how it is presented.
The Orbeon Forms PFC uses the concept of XML submission to provide page
configurability. To the model and view of a given page, an XML submission is
simply an XML document whose content is available as an XPL pipeline or an XSLT input called
There are different ways to produce an XML submission:
Internal XForms submissionThe most common case of XML submission in Orbeon Forms is submission from the built-in XForms engine. Assume you have a page defined as follows:
If you wish to submit an XForms instance to this page from within
This ensures that when this XForms submission is activated, an XML document containing the submitted XForms instance will be made available to the page model and view.
NOTE: The
action attribute on the xforms:submission
element should not be confused with the <action> element
of the page flow. The former specifies a URL to which the XForms submission
must be performed, as per the XForms 1.0 recommendation; the latter
specifies a PFC action executed when a
specified boolean XPath expression operating on an XML submission evaluates
to true. The XForms submission's action attribute instead
matches a PFC <page> element's path-info
attribute.
You can also directly submit to another page by specifying a different action, for example:
In general it is recommended to leave the control of the flow between pages to PFC actions, as documented below. External XML submission
An external XML submission must refer to the URL of the page accepting the
submission. It is up to the developer to provide this URL to the external
application, for example
Default submission
In case there is no external or internal XML submission, it is possible to
specify a static default XML submission document. This is particularly useful to
extract information from a page URL, as documented below. You specify a default
submission with the
Accessing XML submission dataThe mechanisms described above explain how a page receives an XML submission, but not how to actually access the submitted XML document. You do this in one of the following ways:
If no submission has taken place, the XML submission document is an Orbeon Forms "null" document, as follows:
Extracting data from the URLXML submission using HTTP POST convenient in many cases, however there are other ways page developers would like to configure the way a page behaves:
A PFC page can easily extract data from the URL using the
The following page extracts the two URL parameters:
The
In such a case, if no
With a query string of
With a query string of
NOTE: The default submission document does not have to use element or attribute
names identical to the URL parameter names. Doing so however may make the
code clearer.
If there are multiple URL parameters with the same name, they will be stored in the element or attribute separated by spaces.
It is also possible to extract data from the URL path. To do so, use a
The
The
Finally,
NOTE: If a page actually uses an XML submission, which means either having
<action> elements, or reading the instance in the page model
or page view, it must not expect to be able to read the HTTP request body
separately using the Request
generator.
Navigating between pagesPage flow
The site logic or page flow describes the conditions that trigger the navigation from one page to the other. It also describes how arguments are passed from one page to the other. In a simple web application simulating an ATM, as illustrated by the ATM example the navigation logic could look like the one described in the diagram on the right. In this diagram, the square boxes represent pages and diamond-shaped boxes represent actions performed by the end-user. With the PFC, page flow is expressed declaratively and externally to the pages. Consequently, pages can be designed independently from each other. The benefits of a clear separation between site logic and page logic and layout include:
Actions and resultsAn example
Consider a
This page is composed of different parts illustrated in the figure below:
This behavior is described in the Page Flow with:
The
|
| Redirect |
|
|---|---|
| Forward |
|
The benefit of the "redirect" method is that after being redirected to page
b, the end-user will see a URL starting with /b in the
browser's address bar. He will also be able to bookmark that page and to come
back to it later. However, a drawback is that the request for page b is
sent by the browser with a GET method. Since browsers impose
limits on the maximum amount of information that can be sent in a
GET (URL length), this method might not work if the amount of
information that needs to be passed to page b from page a is too
large. This typically happens when working with fairly large XML submissions.
In those cases, you must use the "forward" method, which does not limit the
amount of information passed from page to page. The "forward" method also
reduces the number of roundtrips with the server.
redirect-exit-portal, behaves
like the redirect method but sends a redirection which exits
the portal, if any. This is mainly useful for the Orbeon Forms examples portal.
You can configure the method:
-
At the application level, in
properties.xmlwith:<property as="xs:string" processor-name="oxf:page-flow" name="instance-passing" value="forward|redirect"/> -
At the page flow level with the
instance-passingattribute on the page flow root element:<config instance-passing="forward|redirect">...</config> -
In the page flow at the "result" level, with the
instance-passingattribute on the<result>element:<page id="a" path-info="/a" model="..." view="..."><action when="..."><result page="b" instance-passing="forward|redirect"/></action></page>
A configuration at the application level (properties.xml) can be
overridden by a configuration at the page flow level
(instance-passing on the root element), which can in its turn be
overridden by a configuration at the result level (instance-passing
on the <result> element).
Paths and matchers
Patterns
The value of the path-info attribute can be either a simple pattern
or a custom pattern.
| Value | Description |
|---|---|
| Simple Pattern |
Simple patterns optionally start or end with a star character ( *). For
instance: /about/company.html matches exactly this URL, about/*
matches any URL that starts with about/, *.gif matches any URL
that ends with .gif.
|
| Custom Pattern |
In this case, an additional matcher attribute must be specified on the
<page> element. The matcher argument points to a matcher
processor qualified name. Two matcher processors are provided with Orbeon Forms: the Perl5 matcher
(oxf:perl5-matcher) and the Glob matcher (oxf:glob-matcher). The
Perl5 matcher accepts Perl
regular expressions and the Glob matcher accepts Unix shell
glob expressions.
|
Matching files and pages with the perl5 matcher
Groups of files can be matched using a single <files> element with the Perl5
matcher:
<files path-info="/doc/[^.]*\.html" matcher="oxf:perl5-matcher"/>
A matcher can also be specified on a <page> element:
<page path-info="/forms/([_A-Za-z\-0-9]+)/page/([0-9]{1,3})" matcher="oxf:perl5-matcher"/>
When using a matcher that allows for groups, the part of the path matched by those groups can be
extracted as documented above with the <setvalue> element. Note that the only
matcher bundled with Orbeon Forms that accepts groups is the Perl5 matcher, referenced with
oxf:perl5-matcher.
Parametrizing the model and view attributes
The result of matches can be referred to directly in the model and view
attributes using the notation ${group-number}:
<page path-info="/forms/([_A-Za-z\-0-9]+)/page/([0-9]{1,3})" matcher="oxf:perl5-matcher" model="oxf:/forms/${1}/model.xpl" view="oxf:/forms/${1}/view-${2}.xhtml"/>
In this case, if the path contains: /forms/my-form/page/12:
-
The model file read will be
oxf:/forms/my-form/model.xpl -
The view file
oxf:/forms/my-form/view-12.xhtml
Parametrizing model and view attributes this way often allows greatly
reducing the size of page flows that contain many similar pages.
Navigating to pages that use matchers
When a result element directs flow to a page that uses matchers and
<setvalue> elements, the PFC attemps to rebuild the destination path accordingly.
Consider the following example:
<page id="source" path-info="/"><action><result page="destination" transform="oxf:xslt"><form xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="2.0"><username>orbeon</username><blog-id>12345</blog-id></form></result></action></page>
<page id="destination" path-info="/user/([^/]+)/blog/([^/]+)" matcher="oxf:perl5-matcher" view="blogs/${1}/blog-${2}.xhtml"><setvalue ref="/form/username" matcher-group="1"/><setvalue ref="/form/blog-id" matcher-group="2"/></page>
In this example, accessing the source page directly causes navigation to the
destination page. Using the following information:
- The internal XML submission
- The destination page's matcher groups
-
The
<setvalue>elements
The PFC reconstructs the path to /user/orbeon/blog/12345. This path is used to request
the destination page. In this case, the view attribute evaluates to
blogs/orbeon/blog-12345.xhtml.
<setvalue> elements will cause the requested path to have its literal value, in
the example above /user/([^/]+)/blog/([^/]+). It is not advised to perform
navigation this way.
Other configuration elements
Overview
A page flow file is comprised of three sections:
-
The
<files>elements list files that must be served directly to the client, such as images or CSS files. -
The
<page>elements declare pages and for each one specify identifier, path, model, view, and XML submission. -
The
<epilogue>and<not-found-handler>elements define additional behavior that apply to all the pages.
The files element
Some files are not dynamically generated and are served to the client as-is. This is typically the case for images such as GIF, JPEG, CSS files, etc..
You tell the PFC what files to serve directly with one or more
<files> elements in the page flow. The example below shows
the configuration used by the Orbeon Forms examples:
<config><files path-info="*.gif"/><files path-info="*.css"/><files path-info="*.pdf"/><files path-info="*.js"/><files path-info="*.png"/><files path-info="*.jpg"/><files path-info="*.wsdl"/><files path-info="*.html" mime-type="text/html"/><files path-info="*.java" mime-type="text/plain"/><files path-info="*.txt" mime-type="text/plain"/><files path-info="*.xq" mime-type="text/plain"/>...</config>
With <files path-info="*.gif"/>, if a request reaches the
PFC with the path images/logo.gif, the file
oxf:/images/logo.gif is sent in response to that request.
The <files> element supports the path-info and matcher attributes
like the <page> element. It also supports a
mime-type attribute telling the PFC what media type must be sent
to the client with the files. The PFC uses defaults for well-known extension,
as defined by the Resource Server
processor. In doubt, you can specify the mime-type attribute.
The epilogue element
You often want a common look and feel across pages. Instead of duplicating the
code implementing this look and feel in every page view, you can define it in a
central location called the page flow epilogue. The
<epilogue> element specifies the XPL pipeline which implements the page flow
epilogue.
This is an example of <epilogue> element, pointing to the
default epilogue XPL pipeline:
<epilogue url="oxf:/config/epilogue.xpl"/>
The page flow epilogue is discussed in more details in the Page Flow Epilogue documentation.
The not-found-handler element
The <not-found-handler> element is used to specify the
identifier of a page to call when no <page> element in the
page flow is matched by the current request. There can be only one
<not-found-handler> per page flow.
This is an example of <not-found-handler> element and the
associated <page> element:
<page id="not-found" path-info="/not-found" view="/config/not-found.xhtml"/>
<not-found-handler page="not-found"/>
By default, oxf:/config/not-found.xhtml displays a simple XHTML page
telling the user that the page requested cannot be found.
<not-found-handler> element is not used for resources
served through the <files> element. In that case, the
PFC returns instead a "not found" code to the user agent (code 404 in the
case of HTTP).
Error handling
Several things can go wrong during the execution of a page flow by the PFC, in particular:
- The page flow may be ill-formed.
- A runtime error may be encountered when processing the page flow, such as not finding a particular page model referenced by a page.
- An action, page model, page view or epilogue may generate an error at runtime.
Those error conditions are not directly handled by the PFC. Instead, they are
handled with the error XPL pipeline specified
in the web application's web.xml file. By default, the error processor
is the Pipeline processor, which runs the oxf:/config/error.xpl XPL
pipeline. You can configure error.xpl for your own needs. By default,
it formats and displays the Java exception which caused ther error.
See Packaging and Deployment for more information about configuring error processors.
Typical combinations of page model and page view
The sections below show how page model and page view are often combined.
View only
Simple pages with no back-end code can be implemented with a single XPL pipeline, XSLT template or static page.
A view XPL pipeline must have a data output. The XML generated by
the view then goes to the epilogue.
Model only
If a page is not sent back to the user agent, there is no need for a view. This
is typically the case when a redirect needs to be issued, a binary file is
produced, or when a page simply implements an XML service.
View only with xml submission
This is a variant of the view only scenario, where an XML submission is
used. In this case, the view receives the XML submission as the
instance input.
Model only with xml submission
This is a variant of the model only scenario, where an XML submission is
used.
View and model
This is the classic case. An XPL pipeline implements the page model and an XSLT
template implements the page view where data produced by the model is consumed
by the view.
View and model with xml submission, case 1
This is the equivalent of the previous model where an XML submission is used. In
this case an instance input is made available to the model and the
view.
View and model with xml submission, case 2
This is a variant of the previous case where the model declares an
instance output. This allows the model to modify the submitted XML
instance. This is typically useful when the view displays some values from the
XML submission document but these values are not exactly the same as those
entered by the user. For example, a page with a text field where the user types
an airport code. If the user enters a known city such as San Francisco, the
application may automatically add the corresponding airport code (SFO in this
case).
Examples
Redirection with the PFC
The following example illustrates how to perform a simple redirection with the PFC.
Assume you want some path, /a, to be redirect to another path,
/b. You can do this as follows:
<page path-info="/a"><action><result page="page-b" instance-passing="redirect"/></action></page>
<page id="page-b" path-info="/b">...</page>
Note that you do not have to use redirect, but that doing so will cause
the user agent to display the path to page /b in its URL bar. The
instance-passing attribute is also unnecessary if
redirect is already the default instance passing mode.
Implementing XML services with the PFC
The PFC allows you to very easily receive an XML document submitted, for example with an HTTP POST, and to generate an XML response. This can be useful to implement XML services such as XML-RPC, SOAP, or any XML-over-HTTP service. The following PFC configuration defines a simple XML service:
<page path-info="/xmlrpc" model="xml-rpc.xpl"/>
Notice that there is no view attribute: all the processing for this
page is done in the page model.
The following content for xml-rpc.xpl implements an XML service
returning as a response the POST-ed XML document:
<p:config xmlns:p="http://www.orbeon.com/oxf/pipeline" xmlns:oxf="http://www.orbeon.com/oxf/processors"><!-- The XML submission is available on the "instance" input --><p:param name="instance" type="input" schema-href="request.rng"/><!-- Processing of the XML submission (here we just return the request) --><p:processor name="oxf:identity"><p:input name="data" href="#instance"/><p:output name="data" id="response"/></p:processor><!-- TODO: update this, it's obsolete, must use xml-converter --><!-- Generate a response --><p:processor name="oxf:xml-serializer"><p:input name="data" href="#response" schema-href="response.rng"/><p:input name="config"><config/></p:input></p:processor></p:config>
Notice the optional schema-href attributes which allow validating
the request and the response against schemas.