Preface:
Thank you Joram to motivate me to write this post and explains what is mentioned in this post in more details.
We are using Activi in our company. Activiti provides an explorer application which is based on Vaadin. Vaadin is a Javascript based web framwork and extends Google GWT.
My first problem with this approach is that a new protocol for form definition is created from scratch. There are already mature form definition protocols with lots of open source and commercial implementations available. So why to reinvent the wheel ? Xform maybe the best standard available today. It is a little bit old and forgotten, but still works fine.
My second problem is the framework used. Vaadin is wonderful, but it is not easy to integrate it with other main stream servlet based frameworks.
First I tried to make current Vaadin based implementation to use Xform instead of home made protocol used in it. I spent several days on the subject and was persuaded that it is not easy if not impossible. One of the problems is discussed here in Vaadin forum.
To select a rendering engine, first I took ronal.van.kuik’s advice in this thread and selected BetterForms open source Xforms implementation. I was not able to configure it properly to work well in a short time. So I tested Orbeon, another open source implementation.This time it went well. I was able to create a proof of concept easily. Here I explain how it works.
Orbeon Integration
First of all Orbeon needs to be installed on the tomcat. Orbeon could be configured to process the Xforms for another application. First it should be deployed as a seperate web application, say /orbeon. It is a stand alone application with a nice user interface for management and even designing new forms. But what we need here is the form rendering functionality. For this, a jar file should be copied in the application and configured as a filter. This filter checks the HTTP traffic and renders any xforms content in it.
Details for configuration of Orbeon could be found here. Installation is very straight forward. I used “seperate configuration” option, though “Integrated application” also does not seem to be much different.
Xforms file assignment
The next step is to define a standard for assigning the user task to a specific xforms file. Our application uses static tapestry forms. It is desired that application be backward compatible and can support traditional static forms. For this, I selected to add an “xform:” string to the start of the form name, if it is going to be rendered by Xforms engine. Else it will be processed as usual. Here is how the definition looks like:
<userTask
id="utProvideMerchantMainInfo" name="Provide merchant main info"
activiti:formKey="xforms:merchant/ProvideMerchantMainInfo">
</userTask>
Rendering Xforms
Now is the time to do the main part of the job and render the form. The form reading should be dynamic. As Orbeon filter is configured, it is enough to copy the content of xforms file to http output. To do this, i have created a Servlet. This servlet simply, gets the file name containing xform from a request parameter and copies the content of the file to http stream.
Here is the code for servlet:
String formName = request.getParameter(PARAM_XFORM_NAME);
String resourceName = "/xforms/" + formName + ".xhtml";
String line;
Writer writer = response.getWriter();
while ((line = reader.readLine()) != null) {
writer.write(line);
}
and here is its mapping in web.xml
<servlet>
<servlet-name>xformActiviti</servlet-name>
<servlet-class>net.atos.xa.mac.admin.xform.XformsRendererServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xformActiviti</servlet-name>
<url-pattern>/xforms/renderer</url-pattern>
</servlet-mapping>
now in the application, it is enough to set the file name parameter and forward the page to renderer servlet:
if (formPrefix == FormPrefix.XFORMS) {
formKey = FormPrefix.removePrefix(formKey);
Link link = new LinkImpl("/xa-mac-admin" + "/xforms/renderer", false,
false, response, null);
link.addParameter(XformsRendererServlet.PARAM_XFORM_NAME, formKey);
link.addParameter("taskId", taskId);
return link;
That was the main part, now the form is rendered by orbeon filter. Orbeon filter, also cares for events and ajax like interactions.
Submitting the xform
After the user sees the rendered xform, he fills into the fields and submits the form. In Xform standard, xforms:submission is responsible for this. Xform engine creates an xml file with from input data and sends the generated xml to the url mentioned in xforms:submission tag.
here is a sample value for this tag in our xform:
<xforms:submission action="http://localhost:8080/xa-mac-admin/xforms/submit" method="post"
id="submit" includenamespaceprefixes="" />
The xml is sent to the above url. Again we need a servlet to receive xml file, parse it and complete the task. The source for the code is a little bit long and trivial.
Initial values of xform fields
The above procedure was the first step and usually the form in this step is clear. But it is probable that in the next steps, some of the previously input data should be shown. Again for this purpose, an xml document should be created and sent to Xform engine.