Test-driving XForms with Orbeon
In this second installment, we conclude our evaluation of XForms implementations and explain why we ultimately preferred the Orbeon engine. I walk you through a XForms sample to explain essential concepts. My team has spent quite a lot of time understanding the Orbeon architecture and I discuss our findings, including separate-deployment configuration and state handling.
When we did our first research on XForms, we tried out many different implementations (see last post). It became very soon clear to me that it would be the best to start with a server-side engine, because this approach allows a seamless integration in existing applications. Because all processing is done on the server side, the engine always delivers regular HTML to the browser. Therefore, server-side engines work without a plug-in on the client side, i.e. they look and feel like a standard Struts or JSF application. (Orbeon runs on Firefox, IE (6, 7, 8), Safari, Google Chrome, and Opera.) Also, as the engine runs in the same environment as our existing JEE applications, technical integration is much easier.
There were only two relevant choices: Orbeon and Chiba. In the end, Orbeon turned out as the winner. But at first, Chiba looked very promising, due to its simple architecture, small codebase and it’s also easy to operate! Orbeon, on the other side, appeared quite complex – a monolithic, 40 MB web archive (WAR); also it seemed a challenge to integrate it into existing Java EE applications (more about how we solved this below).
Why we chose Orbeon
In the end, we chose Orbeon, because our primary goal was to gain experience with the XForms technology. And unlike Chiba, Orbeon supports almost all of the XForms 1.1 features. The Orbeon community is very active and the core developers are also regularly answering questions in the Orbeon mailing list.
In my opinion, the
Here are the four finalists, just in case you are evaluating XForms engines, too:
- Orbeon: The XForms we finally chose for your XForms projects.
- Chiba: The only engine comparable to Orbeon. Supports far less XForms features. Also further development seemed to have stopped in 2008.
Update: The betterFORM XForms engine is a successor of Chiba and seems really interesting. See also the comments below.
- Mozilla XForms Plug-in / IE Forms Player: Quite usable but as browser plug-ins require installation on the client
Overview of the Orbeon Architecture
Our Sample Form
Let’s start our test-drive and produce a working XForms document. I’ve picked an sample form that we implemented within a day. It’s simple but already uses many of the nice features of XForms.
The form is part of a bank account application process and is used to enter basic personal data about the applicant. The enumeration values (gender, title, etc.) are read from separate XML resources. Some fields are only visible, if a certain checkbox is checked (e.g. address changed within last three years).
When developing XForms documents, the first step is usually to define the XML data structure containing the information to be display and edited upon. The reason for this is that XForms reads all data from XML. Editing data with XForms means retrieving an XML document from a URL, changing it and sending the result to an URL.
Here is an example of a pre-filled XML document for our form:
<?xml version="1.0" encoding="UTF-8"?> <Kreditkartenantrag xmlns="http://www.mgm-tp.com/xforms-showcase/"> <Kunde> <Geschlecht>M</Geschlecht> <Titel>Dr.</Titel> <NamensVorsatz>zu</NamensVorsatz> <NamensZusatz>Hause</NamensZusatz> <Nachname>Mustermann</Nachname> <Vorname>Max</Vorname> <Geburtsname>Beispiel</Geburtsname> <Adresse> <Strasse>Standardstrasse</Strasse> <Hausnummer>15</Hausnummer> <PLZ>80815</PLZ> <Ort>Teststadt</Ort> </Adresse> <Geburtsdatum>2001-01-01</Geburtsdatum> <Geburtsort>Teststadt</Geburtsort> <Familienstand>ledig</Familienstand> </Kunde> <Adressaenderung3Jahre>true</Adressaenderung3Jahre> <BisherigeAdresse> <Strasse>Alte Standardstrasse</Strasse> <Hausnummer>11</Hausnummer> <PLZ>80811</PLZ> <Ort>Testdorf</Ort> </BisherigeAdresse> <Taetigkeit> <Beschaeftigungsart>Rentner(in)</Beschaeftigungsart> <Berufsbezeichnung>Musterjob</Berufsbezeichnung> <BeschaeftigungSeit>2001-01-01</BeschaeftigungSeit> <MonatsNettoEinkommen>5000</MonatsNettoEinkommen> </Taetigkeit> <Kontakt>...</Kontakt> <SchufaUebermittlung>...</SchufaUebermittlung> <Ausweis>...</Ausweis> <KreditkartenKonfiguration>...</KreditkartenKonfiguration> <UnterschriftLiegtVor>true</UnterschriftLiegtVor> </Kreditkartenantrag>
If you compare the XML document with the visual representation of the XForms document, you might notice, that the structure of the XML document differs from the XForms document:
- The nesting and naming of the elements in the XML document is different, e.g. in the XML document, all address attributes are grouped in one “Adresse” element. In the XForms document, the attributes are further subdivided (Straße / Hausnummer, PLZ / Ort).
- The document contains typed / non-text elements, e.g. the date of birth is stored in ISO date format “yyyy-dd-mm”, whereas the XForm displays the date formatted as “d.m.yyyy”. This is very important to allow internationalization of the form and standardized processing of the XML document.
- Some elements of the XML document do not appear in the form at all. The reason could be, that these elements are edited in other forms or the XML structure is also used in other contexts than XForms.
- The document contains a reference to an XML schema. This schema is used to validate submitted form data.
A Walkthrough of our sample XForms
Now let’s have a look at some interesting parts of the form code.
The schema attribute of the model element allows us to point the XForms processor to an XML Schema definition:
Next come the references to XML documents containing actual data:
<!-- Default instance --> <!-- Form data to be displayed and edited upon --> <xf:instance id="antrag" src="/documents/kreditkartenantrag.xml" /> <!-- List of employment types --> <xf:instance id="employmentTypes" src="/enumerations/employmentTypes.xml" />
The first XML document we reference here automatically becomes the default instance, i.e. the document we refer to when we define our input controls later. All other instances in this example refer to enumerations used for radio buttons and select boxes.
Next comes the submission element. It tells XForms, which data should be sent back to the server when the form is submitted:
<!-- example submission action with validation disabled --> <xf:submission id="submission" ref="instance('antrag')" validate="false" replace="all" resource="/xforms/REST/post.jsp" method="post" />
The last part of the XForms model structure is the bind element:
<!-- former address is only asked for if address has changed within the last three years --> <xf:bind nodeset="/d:Kreditkartenantrag/d:BisherigeAdresse" relevant="string(../d:Adressaenderung3Jahre)='true'" />
This bind elemend shows one of the coolest features in XForms. It binds the
relevant attribute of the default instqnce element for “former address” to the value of the element for “address changed within last three years”.
In XForms, input controls bound to elements with “
relevant == false” are hidden. So this bind rule has the effect, that the input controls associated with the “former address” element are only visible when “address changed within last three years” is true. In summary, it’s a declarative way of showing / hiding input controls depending on a boolean expression.
The XForms group element is used to define an XPath context for contained input controls. This allows to use relative XPath expressions inside the group. The group itself is rendered as an HTML span. The group’s class attribute is copied 1:1 to the resulting span and styled with CSS to create a two column layout.
<xf:group ref="/d:Kreditkartenantrag" class="first column">
The rest of the document contains the XForms input controls, embedded into a few HTML elements for layout purposes. Here are some random excerpts:
<span class="table-row"> <xf:input ref="d:Nachname"> <xf:label>Nachname</xf:label> </xf:input> </span> ... <span class="table-row"> <xf:label class="table-layout-header">Beruf</xf:label> <xf:select1 ref="d:Taetigkeit/d:Beschaeftigungsart" appearance="minimal"> <xf:label>Art der Beschäftigung</xf:label> <xf:itemset nodeset="instance('employmentTypes')/item"> <xf:label ref="@name" /> <xf:value ref="@value" /> </xf:itemset> </xf:select1> <span/>
Finally, the button for submission of the form is described as follows:
<xf:submit submission="submission"> <xf:label>Formular absenden</xf:label> </xf:submit>
This submit element refers to the submission definition with ID “submission” I have shown above.
Integrating Orbeon with a Web Application
Because with XForms you only build web forms (and not complete web applications), Orbeon is normally integrated into an existing application. One configuration which we evaluated at mgm is a standard Servlet-based web application combined with a separately deployed instance of the Orbeon engine. This form of operation is official described in “Using the Orbeon Forms XForms Engine with Java Applications“.
In the separate deployment scenario, a Tomcat server contains two web applications:
- Business application: containing all pages of your application as well as the XForms.
- Orbeon application: Orbeon deployed as a separate web application.
Our business application handles all “normal” page requests. The pages can be regular HTML or XForms/XHTML pages. In case of JSP, we use a custom JSP tag to include the XForms content into the JSP, producing the XForms pages. Our custom JSP tag (source code here for download.) is very similar to
Now, how are the two web applications connected? Our application is configured with a special Servlet filter,
OrbeonXFormsFilter. This filter processes all requests to XForms pages (which have an extension like “.xhtml”). The Servlet filter then communicates with the Orbeon application through a
This configuration results in a relatively loose coupling of the business application and the Orbeon XForms processor. The regular Orbeon distribution can be used (with a few additional configurations, see the file “properties-local.xml” below). For server-side integration, I had to implemented a small JSP tag which fixed a problem with the Servlet response buffer handling in Orbeon’s
Our XForms document is seamlessly integrated into the regular web pages of the business application. The rendered HTML can be styled with CSS.
- complex-form.xhtml: Sample form (XForms source)
- Orbeon web application (I used the stable build of the Community Edition)
- properties-local.xml: Configuration settings for separate deployment (copy to WEB-INF/resources/config/ folder of the Orbeon web application)
Other Features of the Orbeon Engine
Integration with Backend Systems – One aspect I did not mention is the integration of the form with middleware / backend systems. I simply assumed that all data is read from and written as XML over HTTP (which is quite nice because it allows to write XForms before the server side logic is implemented). Possible approaches for XML include custom XML parsing (e.g. JDOM) or XML to Java binding (e.g. JAXB). The resources can be implemented as plain Servlets, JSP pages or (more conveniently) through the new JEE 6 REST API (JAX-RS).
Another topic which quickly arises are custom XForms controls. Many applications have special requirements for some controls, e.g. a specific date picker or input control for monetary amounts is required. Orbeon provides XBL for this, see for example Guide to Using and Writing XBL Components.
State Handling – A weak spot of Orbeon (and server side form processing technologies in general) are response times and server load. Because the form state is kept on the server side, whenever the form state changes, a round trip is required. Orbeon provides some configuration parameters to suppress round trips for unused events (e.g. DOM focus events). To reduce the memory consumption on the server, the form state can be kept on the client (see
Orbeon XForms – State Handling).