This article demonstrates how to create a very simple web-based questionnaire for collecting a customer's personal information. The questionnaire consists of two pages containing a total of three questions. The visibility of the second page is determined by a customer's response to questions on the first page. This article describes how to use WebSphere Operational Decision Management to implement dynamic forms for creating the questionnaire.
You should have a working knowledge of WebSphere Operational Decision Management V7.5 and understand the general concepts of business rules management. Knowledge of Java, JEE and programming languages in general is assumed.
Forms are the key components of all web-based applications. A form consists of multiple pages, each containing one or more field types such as option box, radio box or text box. Using WebSphere Operational Decision Management you define forms and implement decision logic with business rules. For example, decision logic can be used to change page visibility based on a user's responses. Forms are built using standard JEE technology. Web applications interact with WebSphere Operational Decision Management to retrieve forms information for presentation and to send updated forms with user-entered responses to Operational Decision Management for decision-making. Forms can be changed by updating rules, thus the name dynamic forms.
Although forms are important, they can be difficult to develop and hard to maintain. Dynamic forms can be developed with less coding; moreover, dynamic forms are visible to business users allowing them to define and maintain the content and flow of complex forms with minimal IT support. Thus the following problems are addressed:
- User interfaces are a bottleneck in adapting to changing business needs – even minor updates are costly and time-consuming.
- Business users have no direct control or visibility into the UI functionality, which is hidden in legacy code.
- Customers are dissatisfied because of inflexible forms and redundant data entry.
- The user experience is not consistent across channels - web, agent and call-center apps each implement similar logic in different ways.
Develop the Execution Object Model (XOM)
In this step, you create the Execution Object Model (XOM) -- Java classes for representing a form. The basic models include: Form, Page, and Field. The relationships between these models are:
- There are multiple pages in a form.
- A page is the container of fields.
- There are multiple fields on a given page.
The classes,their properties, and their methods are described below. A helper class is included.
- Form: currentPage, pages.
- Page: code, label, visible, fields.
- Field: code, label, type, options, responses.
- FieldType: Text, Radio, Checkbox and Select and it is an enum class.
- DynamicFormsHelper: a helper class that contains the following
methods:
- addPage(String code, String label, Form form): adds a page into the form with specified code and label.
- addField(String code, String label, FieldType type, String options, String pageCode, Form form): adds a field with specified code, label and type to the page of form.
- gotoNextPage(Form form): makes the form move to next page.
- lastVisiblePageIndex(Form form): returns the index of the last visible page.
- currentPageIndex(Form form): returns the index of current page that the form stays on.
- getField(String code, String pageCode, Form form): returns the field with specific code on the page with specific code of the form.
- getPage(String pageCode, Form form): returns the page with specific code.
- getCurrentPageLabel(Form form): returns the current page label.
- getCurrentPage(Form form): returns the current page.
Figure 1 shows the class diagram.
Figure 1. Class diagram
We can use a form object, a page object and a field object to represent a web-based questionnaire, a page and a question respectively. Now we can open the Rule Designer in WebSphere Operational Decision Management to create a Java project with the name DynamicForms-XOM. We then create models according to the class diagram and the code of the helper class.
Listing 1. DynamicFormsHelper.java
package com.ibm.wodm.df.models;
public class DynamicFormsHelper {
public static void addPage(String code, String label, Form form) {
Page page = new Page();
page.setCode(code);
page.setLabel(label);
form.getPages().add(page);
}
public static void addField(String code, String label, FieldType type,
String options, String pageCode, Form form) {
Page existingPage = null;
for (Page page : form.getPages()) {
if (page.getCode().equals(pageCode)) {
existingPage = page;
break;
}
}
Field field = new Field();
field.setCode(code);
field.setLabel(label);
field.setType(type);
if (options != null) {
for (String option : options.split(",")) {
field.getOptions().add(option);
}
}
existingPage.getFields().add(field);
}
public static void gotoNextPage(Form form) {
int currentPageIndex = currentPageIndex(form);
if (form.getPages().size() != (currentPageIndex + 1)) {
for (int i = currentPageIndex + 1; i < form.getPages().size(); i++) {
Page page = form.getPages().get(i);
if (page.isVisible()) {
form.setCurrentPage(page.getCode());
break;
}
}
}
}
public static int lastVisiblePageIndex(Form form) {
int lastVisiblePageIndex = 0;
for (int i = 0; i < form.getPages().size(); i++) {
Page page = form.getPages().get(i);
if (page.isVisible()) {
lastVisiblePageIndex = i;
}
}
return lastVisiblePageIndex;
}
public static int currentPageIndex(Form form) {
if (form.getCurrentPage() == null) {
return -1;
}
int currentPageIndex = 0;
for (int i = 0; i < form.getPages().size(); i++) {
Page page = form.getPages().get(i);
if (page.getCode().equals(form.getCurrentPage())) {
currentPageIndex = i;
break;
}
}
return currentPageIndex;
}
public static Field getField(String code, String pageCode, Form form) {
for (Page page : form.getPages()) {
if (page.getCode().equals(pageCode)) {
for (Field field : page.getFields()) {
if (field.getCode().equals(code)) {
return field;
}
}
}
}
return null;
}
public static Page getPage(String pageCode, Form form) {
for (Page page : form.getPages()) {
if (page.getCode().equals(pageCode)) {
return page;
}
}
return null;
}
public static String getCurrentPageLabel(Form form) {
return form.getPages().get(currentPageIndex(form)).getLabel();
}
public static Page getCurrentPage(Form form) {
return form.getPages().get(currentPageIndex(form));
}
}
|
Other classes are Plain Old Java Objects and are therefore not listed here.
In the same workspace as above, we create a rule project with the name DynamicForms-Rules and then we create a BOM entry, rules and ruleflow for defining forms with rules. The rule project can be published to the Decision Center of WebSphere Operational Decision Management so that business users can manage the rules.
Develop Business Object Model (BOM)
In Rule Designer, we create a Business Object Model (BOM) entry based on the XOM created in the previous section. We only import mandatory attributes of the XOM classes and verbalize some of them so that they can be used for developing rules. All created BOM classes and relevant vocabularies are as follows:
- Form: its term is form and there is no verbalized attribute.
- Page: its term is page and the attribute “visible” is verbalized as make it {a boolean} that {a page} is visible to show or hide a page.
- Field: its term is field and the attribute “responses” is verbalized as {the responses} of {a field} to get users’ responses to a field or a question.
- FieldType: its term is field type and all attributes are added as domain values: Checkbox, Radio, Select and Text.
- DynamicFormsHelper: it is not verbalized and its four member methods
are imported and verbalized:
- addField: the vocabulary is add a field with code: {a string}, label {a string}, type {a field type} and options {3} to the page with code {a string} of form {a form}. It is used to add a field specified with code, type and label to an existing page of a form.
- addPage: the vocabulary is add a page with code: {a string} and label: {a string} to form {a form}. It is used to add a page specified with code and label to a form.
- getField: the vocabulary is the field with code {a string} on page {a string} of form {a form}. It is used to get a field with some code that exists on a specific page of a form.
- getPage: the vocabulary is the page with code {a string} of form {a form}. It is used to get a page with a specific code.
Figure 2. Vocabulary for DynamicForms-Rules
We use the Form class as a ruleset parameter with direction IN_OUT. Figure 3 shows the definition.
Figure 3: Ruleset parameters
Create rule structure and ruleflow
For implementing the scenario, we need rules for defining a web-based questionnaire and rules for changing the visibility of the second page based on a user's responses to questions on the first page. Two additional requirements are to validate the user's responses and to convert between user responses and domain objects of the application. Rules are categorized into four packages: Initialize, Pre Process, Page Navigation and Post Process. Figure 4 shows the rule structure.
Figure 4: Rule structure
The overall rule flow has four rule tasks:
- Initialize: executes rules for initializing a form. The rules are fired only once when a questionnaire is presented to a user.
- Pre-process: executes rules for validating users’ responses.
- Page Navigation: executes rules for dynamically changing page-visibility based on conditions and navigates to the next page in its Final Action section.
- Post-process: executes rules for post-processing such as mapping all responses to domain objects of the application.
These rule tasks are depicted in the ruleflow shown in Figure 5.
Figure 5: Rule flow
The business rules used in this example fall into the following categories:
- Definition rules that create a form consisting of pages and fields that define the web-based questionnaire.
- Validation rules that validate users’ responses.
- Page visibility rules for dynamically showing or hiding pages.
- Mapping rules that perform post-processing to map users’ responses to domain objects of the application.
In the first rule package “1 - Initialize”, two sub-packages “1 - Pages Initialization” and “2 - Fields Initialization” are created. These subpackages define decision tables “Add Pages” and “Add Fields” respectively. The decision table “Add Pages” is used to define and add pages to the form.
- The condition column is: true is {a boolean}
- The action column is: add a page with code: <a string> and label: <a string> to form form.
Figure 6 shows how to define pages for the questionnaire.
Figure 6: Add Pages decision table (sample)
The Add Fields decision table is used to define and add fields to the pages of the form.
- The condition column is the same as the Add Pages decision table
- The action column is: add a field with code: <a string> , label <a string> , type <a field type> and options <a string> to the page with code <a string> of form form.
Figure 7 shows how to define questions and add them to the pages of the questionnaire.
Figure 7: Add Fields decision table (sample)
We need to ensure that pages are created prior to creating the fields for the page. That is, the decision table for adding pages must be evaluated prior to the decision table for adding fields. To do this, the Rule Execution Ordering attribute of the rule task Initialization is set to Literal as shown in Figure 8.
Figure 8: Initialization rule task
Next we can add validation logic. For example, we can add an action rule to validate whether a user answered mandatory questions on some page of the questionnaire.
In the rule package Page Navigation, we can add rules for changing page visibility. Figure 9 shows the rules for changing the visibility of the second page titled “FamilyInfo” according to the answer to the question “Married”, which is on the first page titled “PersonalInfo”.
Figure 9: Rule sample: Changing visibility of pages
For processing a user's answers, we can map all user responses to domain objects of the application. Relevant rules can be added in the rule package Post-process.
Develop a web-based questionnaire with JEE technology
To display defined forms to users as a web-based questionnaire and to interact with the rule engine, we create a Dynamic Web Project named DynamicForms-Web. The artifacts created are:
- The servlet class DynamicFormsServlet, which handles requests and responds to users.
- The rules execution class RulesExecutor, which invokes the rule engine.
- JSP pages and Cascading Style Sheets file, which render forms to display the questionnaire to users.
Listing 2. DynamicFormsServlet.java
package com.ibm.wodm.df.web.servlet;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ibm.wodm.df.models.DynamicFormsHelper;
import com.ibm.wodm.df.models.Field;
import com.ibm.wodm.df.models.Form;
import com.ibm.wodm.df.models.Page;
import com.ibm.wodm.df.web.rulesexecution.RulesExecutor;
public class DynamicFormsServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String actionMethod = req.getParameter("actionMethod");
Form form = (Form) req.getSession().getAttribute("form");
if (form != null) {
setResponses(req, form);
}
if (actionMethod.equals("next")) {
String previousPage = null;
if (form != null) {
previousPage = form.getCurrentPage();
}
form = RulesExecutor.executeRules(form);
String currentPageCode = form.getCurrentPage();
if (formIsComplete(form, previousPage, currentPageCode)) {
req.getRequestDispatcher("pages/summary.jsp").forward(req, resp);
return;
}
} else if (actionMethod.equals("back")) {
form = backToPreviousPage(form);
}
req.getSession().setAttribute("form", form);
req.getRequestDispatcher("pages/form.jsp").forward(req, resp);
}
private boolean formIsComplete(Form form, String previousPage,
String currentPageCode) {
return form != null && previousPage != null &&
previousPage.equals(currentPageCode);
}
@SuppressWarnings("unchecked")
private void setResponses(HttpServletRequest req, Form form) {
String currentPage = form.getCurrentPage();
Enumeration<String> params = req.getParameterNames();
while (params.hasMoreElements()) {
String paramName = params.nextElement();
Field field = DynamicFormsHelper.getField(paramName, currentPage, form);
if (field != null) {
if (field.getResponses() != null) {
field.getResponses().clear();
}
String[] values = req.getParameterValues(paramName);
for (String str : values) {
field.getResponses().add(str);
}
}
}
}
private static Form backToPreviousPage(Form form) {
int currentPageIndex = DynamicFormsHelper.currentPageIndex(form);
for (int i = currentPageIndex - 1; i >= 0; i--) {
Page page = form.getPages().get(i);
if (page.isVisible()) {
form.setCurrentPage(page.getCode());
break;
}
}
return form;
}
}
|
The servlet class handles a user's request to navigate the forms (move to the next or previous page) and collects users’ responses. When a user moves to a "next page" this class calls the rules execution class to invoke the rules engine and then displays pages to the user. If a user reaches the last page of the questionnaire, a summary page is displayed. When a user navigates to a "previous page" the requested page is retrieved from a page list of forms.
The rules execution class uses J2SE to execute rules.
Listing 3. RulesExecutor.java
package com.ibm.wodm.df.web.rulesexecution;
import ilog.rules.res.model.IlrPath;
import ilog.rules.res.session.IlrJ2SESessionFactory;
import ilog.rules.res.session.IlrSessionFactory;
import ilog.rules.res.session.IlrSessionRequest;
import ilog.rules.res.session.IlrSessionResponse;
import ilog.rules.res.session.IlrStatelessSession;
import java.io.PrintWriter;
import com.ibm.wodm.df.models.Form;
public class RulesExecutor {
public static Form executeRules(Form form) {
try {
IlrSessionFactory ilrSessionFactory = createJ2SESessionFactory();
IlrSessionRequest request = ilrSessionFactory.createRequest();
request.setInputParameter("form", form);
request.setRulesetPath(new IlrPath
("DynamicFormsRuleApp", "DynamicFormsRules"));
IlrStatelessSession statelessSession =
ilrSessionFactory.createStatelessSession();
IlrSessionResponse response = statelessSession.execute(request);
form = (Form) response.getOutputParameters().get("form");
} catch (Exception e) {
e.printStackTrace();
}
return form;
}
private static IlrSessionFactory createJ2SESessionFactory() {
PrintWriter writer = new PrintWriter(System.out);
IlrJ2SESessionFactory sessionFactory = new IlrJ2SESessionFactory();
sessionFactory.setOutput(writer);
return sessionFactory;
}
}
|
The JSP page renders fields based on their types, which are set with rules. Each field is rendered with standard HTML elements. Listing 4 shows how to render the field with type Radio.
Listing 4. Code snippet of forms.jsp for rendering field with type radio
<% if (field.getType() == FieldType.Radio) { %>
<table> <tr>
<%
for (int i = 0; i < field.getOptions().size(); i++) {
String option = "";
if (field.getOptions().get(i) != null) {
option = field.getOptions().get(i);
}
boolean checked = false;
if (field.getResponses() != null
checked = field.getResponses().contains(option);
}
if (checked) {
%>
<td><span class="label"><%=option%></span></td>
<td><input type="radio" name="<%=field.getCode()%>" class="controlText"
size="200px" value="<%=option%>" checked /></td>
<% } else { %>
<td><span class="label"><%=option%></span></td>
<td><input type="radio" name="<%=field.getCode()%>" class="controlText"
size="200px" value="<%=option%>" /></td>
<% } } %>
</tr> </table>
<% } %>
|
Figure 10 shows the sample questionnaire implemented using dynamic forms.
Figure 10: Web-based questionnaire (sample page)
Dynamic forms allow you to define and maintain forms using business rules. Through the example described in this article, you have seen how an application can be implemented with business rules and JEE technologies. Dynamic forms provide your application with the flexibility needed to quickly respond to business changes. You can leverage other technologies such as Ajax for dynamically generating Ajax invocation scripts to change forms, and the Dojo framework for generating forms with Dojo widgets.
The author would like to thank Ming Li and Michael Liu for reviewing the technical content of this article.
| Description | Name | Size | Download method |
|---|---|---|---|
| Dynamic forms download | DF_workspace.zip | 32KB | HTTP |
Information about download methods
-
developerWorks BPM
zone: Get the latest technical resources on IBM BPM solutions,
including downloads, demos, articles, tutorials, events, webcasts, and
more.
-
IBM BPM
Journal: Get the latest articles and columns on BPM solutions in
this quarterly journal, also available in both Kindle and PDF versions.



