Desenvolva Formulários Dinâmicos Usando o WebSphere Operational Decision Management V7.5

Neste artigo, você aprenderá a desenvolver o Execution Object Model (XOM), o Business Object Model (BOM) e regras para implementação de formulários dinâmicos no WebSphere Operational Decision Management V7.5. Usando um questionário simples baseado na web como exemplo, o artigo demonstra como processar os formulários com a tecnologia JEE.

Jian Feng Cai , Associate Architect, IBM

Jian Feng Cai trabalha na área de desenvolvimento de aplicativos de sistema empresarial há mais de 9 anos. Durante esse período ele aplicou diversas tecnologias como JEE, regras de negócio e tecnologia de processo para desenvolver aplicativos empresariais em vários domínios.



23/Out/2012

Introdução

Este artigo demonstra como criar um questionário muito simples baseado na web para coletar as informações pessoais de um cliente. O questionário é composto por duas páginas contendo um total de três perguntas. A visibilidade da segunda página é determinada pelas respostas de um cliente às perguntas na primeira página. Este artigo descreve como usar o WebSphere Operational Decision Management para implementar formulários dinâmicos para criação do questionário.

Você deve ter um conhecimento funcional do WebSphere Operational Decision Management V7.5 e entender os conceitos gerais do gerenciamento de regras de negócio. O conhecimento de Java, JEE e linguagens de programação em geral é necessário.

O que são formulários dinâmicos?

Formulários são os principais componentes de todos os aplicativos baseados na web. Um formulário é composto por diversas páginas, cada uma contendo um ou mais tipos de campo como caixa de opção, radio box ou caixa de texto. Usando o WebSphere Operational Decision Management você define formulários e implementa uma lógica de decisão com regras de negócio. Por exemplo, a lógica de decisão pode ser usada para alterar a visibilidade da página com base nas respostas de um usuário. Os formulários são construídos usando a tecnologia padrão JEE. Os aplicativos da web interagem com o WebSphere Operational Decision Management para recuperar informações de formulários para apresentação e para enviar formulários atualizados com respostas inseridas pelo usuário ao Operational Decision Management para tomada de decisão. Os formulários podem ser alterados por meio da atualização das regras, por isso o nome formulários dinâmicos.

Por que usar formulários dinâmicos?

Embora os formulários sejam importantes, eles podem ser difíceis de desenvolver e de manter. Os formulários dinâmicos podem ser desenvolvidos com menos codificação; além disso, os formulários dinâmicos ficam visíveis aos usuários de negócio permitindo que eles definam e mantenham o conteúdo e o fluxo de formulários complexos com o mínimo de suporte da TI. Dessa forma, os problemas a seguir são resolvidos:

  • Interfaces de usuário são um desafio ao adaptar-se às necessidades de negócio em constante mudança – mesmo atualizações menores são caras e demoradas.
  • Os usuários de negócio não têm controle direto ou visibilidade da funcionalidade de UI, que fica oculta no código herdado.
  • Os clientes não estão satisfeitos devido a formulários inflexíveis e entrada de dados redundantes.
  • A experiência do usuário não é consistente entre canais - aplicativos da web, de agente e de canais de atendimento implementam uma lógica parecida de formas diferentes.

Desenvolva o Execution Object Model (XOM)

Nesta etapa, você cria o Execution Object Model (XOM) -- classes Java para representação de um formulário. Os modelos básicos incluem: Formulário, Página e Campo. Os relacionamentos entre esses modelos são:

  • Há diversas páginas em um formulário.
  • Uma página é o recipiente de campos.
  • Há vários campos em uma determinada página.

As classes, suas propriedades e seus métodos estão descritos abaixo. Uma classe auxiliar é incluída.

  1. Formulário: currentPage, páginas.
  2. Página: código, rótulo, visível, campos.
  3. Campo: codigo, rótulo, tipo, opções, respostas.
  4. FieldType: Texto, Rádio, Caixa de seleção e Seleção e é uma classe de enumeração.
  5. DynamicFormsHelper: uma classe auxiliar que contém os seguintes métodos:
    1. addPage(String code, String label, Form form): adiciona uma página ao formulário com código e rótulo especificado.
    2. addField(String code, String label, FieldType type, String options, String pageCode, Form form): adiciona um campo com código especificado, rótulo e tipo à página do formulário.
    3. gotoNextPage(Form form): faz o formulário mudar para a próxima página.
    4. lastVisiblePageIndex(Form form): retorna o índice da última página visível.
    5. currentPageIndex(Form form): retorna o índice da página atual na qual o formulário permanece.
    6. getField(String code, String pageCode, Form form): retorna o campo com o código especificado na página com o código específico ao formulário.
    7. getPage(String pageCode, Form form): retorna a página com o código específico.
    8. getCurrentPageLabel(Form form): retorna o rótulo da página atual.
    9. getCurrentPage(Form form): retorna a página atual.

A Figura 1 mostra o diagrama de classe.

Figura 1. Diagrama de classe
Diagrama de classe

Clique para ver a imagem maior

Figura 1. Diagrama de classe

Diagrama de classe

Podemos usar um objeto de formulário, um objeto de página e um objeto de campo para representar um questionário baseado na web, uma página e uma pergunta respectivamente. Agora, podemos abrir o Rule Designer no WebSphere Operational Decision Management para criar um projeto Java com o nome DynamicForms-XOM. Em seguida, criamos modelos de acordo com o diagrama de classe e o código da classe auxiliar.

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

}

Outras classes são Objetos Java antigos e simples e, portanto, não estão listadas aqui.


Criar um projeto de regra

Na mesma área de trabalho que a mencionada acima, criamos um projeto de regra com o nome DynamicForms-Rules e criamos uma entrada BOM, regras e fluxo de regra para definição de formulários com regras. O projeto de regra pode ser publicado no Decision Center do WebSphere Operational Decision Management de modo que os usuários de negócio possam gerenciar as regras.

Desenvolva Business Object Model (BOM)

No Rule Designer, criamos uma entrada de Business Object Model (BOM) com base no XOM criado na seção anterior. Importamos apenas atributos obrigatórios das classes XOM e verbalizamos alguns deles de modo que possam ser usados para o desenvolvimento de regras. Todas as classes BOM criadas e vocabulários relevantes são da seguinte maneira:

  1. Formulário: seu termo é form e não há atributo verbalizado.
  2. Página: seu termo é page e o atributo “visible” é verbalizado como make it {a boolean} that {a page} is visible para mostrar ou ocultar uma página.
  3. Campo: seu termo é field e o atributo “responses” é verbalizado como {the responses} of {a field} para colocar as respostas dos usuários em um campo ou pergunta.
  4. FieldType: seu termo é field type e todos os atributos são adicionados como valores de domínio: Checkbox, Radio, Select e Text.
  5. DynamicFormsHelper: não é verbalizado e seus quatro métodos membros são importados e verbalizados:
    1. addField: o vocabulário é 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}. Isso é usado para adicionar um campo especificado com código, tipo e rótulo a uma página existente de um formulário.
    2. addPage: o vocabulário é add a page with code: {a string} and label: {a string} to form {a form}. Isso é usado para adicionar uma página especificada com código e rótulo a um formulário.
    3. getField: o vocabulário é the field with code {a string} on page {a string} of form {a form}. Isso é usado para obter um campo com algum código que exista em uma página específica de um formulário.
    4. getPage: o vocabulário é the page with code {a string} of form {a form}. Isso é usado para obter uma página com um código específico.
Figura 2. Vocabulário para DynamicForms-Rules
Vocabulário para DynamicForms-Rules

Defina os parâmetros do conjunto de regras

Usamos a classe Form como um parâmetro de conjunto de regras com direção IN_OUT. A Figura 3 mostra a definição.

Figura 3: Parâmetros de conjunto de regras
Figura 3: Parâmetros de conjunto de regras

Crie uma estrutura de regra e fluxo de regra

Para implementação do cenário, precisamos de regras para definição de um questionário com base na web e regras para alteração da visibilidade da segunda página com base nas respostas de um usuário a perguntas na primeira página. Dois requisitos adicionais servem para validar as respostas do usuário e para converter entre respostas do usuário e objetos de domínio do aplicativo. As regras são categorizadas em quatro pacotes: Initialize, Pre Process, Page Navigation e Post Process. A Figura 4 mostra a estrutura de regra.

Figura 4: Estrutura de regra
Figura 4: Estrutura de regra

O fluxo de regra geral tem quatro tarefas de regra:

  1. Inicializar: executa regras para inicialização de um formulário. As regras são disparadas somente uma vez quando um questionário é apresentado a um usuário.
  2. Pré-processo: executa regras para validação das respostas dos usuários.
  3. Navegação na página: executa regras para alterar dinamicamente a visibilidade da página com base em condições e navega até a próxima página em sua seção Ação Final.
  4. Pós-processo: executa regras para processamento posterior, como mapeamento de todas as respostas a objetos de domínio do aplicativo.

Essas tarefas de regra são retratadas no fluxo de regra exibido na Figura 5.

Figura 5: Fluxo de regra
Figura 5: Fluxo de regra

Desenvolva regras

As regras de negócio usadas nesse exemplo se enquadram nas categorias a seguir:

  • Definição de regras que criam um formulário composto por páginas e campos que definem o questionário com base na web.
  • Regras de validação que validam as respostas dos usuários.
  • Regras de visibilidade da página para exibir ou ocultar dinamicamente páginas.
  • Regras de mapeamento que executam o processamento posterior nas respostas dos usuários para objetos de domínio do aplicativo.

No primeiro pacote de regra “1 - Initialize”, dois subpacotes “1 - Pages Initialization” e “2 - Fields Initialization” são criadosEsses subpacotes definem as tabelas de decisão “Add Pages” e “Add Fields” respectivamente. A tabela de decisão “Add Pages” é usada para definir e adicionar páginas ao formulário.

  • A coluna condição é: true is {a boolean}
  • A coluna de ação é: add a page with code: <a string> and label: <a string> to form form.

A Figura 6 mostra como definir páginas para o questionário.

Figura 6: tabela de decisão Add Pages (amostra)
Figura 6: tabela de decisão Add Pages (amostra)

A tabela de decisão Add Fields é usada para definir e adicionar campos às páginas do formulário.

  • A coluna condição é a mesma que a tabela de decisão Add Pages
  • A coluna de ação é: 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.

A Figura 7 mostra como definir questões e as adiciona às páginas do questionário.

Figura 7: tabela de decisão Add Fields (amostra)
Figura 7: tabela de decisão Add Fields (amostra)

Precisamos garantir que as páginas são criadas antes da criação dos campos para a página. Ou seja, a tabela de decisão para adição de páginas precisa ser avaliada antes de a tabela de decisão para adicionar campos. Para fazer isso, o atributo Rule Execution Ordering da tarefa de regra Initialization é definido como Literal como mostra a Figura 8.

Figura 8: tarefa de regra Initialization
Figura 8: tarefa de regra Initialization

Em seguida, podemos adicionar uma lógica de validação. Por exemplo, podemos adicionar uma regra de ação para validar se um usuário respondeu às perguntas obrigatórias em alguma página do questionário.

No pacote de regra Page Navigation, podemos adicionar regras para alteração da visibilidade da página. A Figura 9 mostra as regras para alteração da visibilidade da segunda página intitulada “FamilyInfo” de acordo com a resposta à pergunta “Married”, que está na primeira página intitulada “PersonalInfo”.

Figura 9: amostra de regra: alterando a visibilidade das páginas
Figura 9: amostra de regra: alterando a visibilidade das páginas

Para processar as respostas de um usuário, podemos mapear todas as respostas do usuário para os objetos de domínio do aplicativo. É possível adicionar regras relevantes no pacote de regra Post-process.


Desenvolva um questionário baseado na web com a tecnologia JEE

Para exibir formulários definidos aos usuários como um questionário baseado na web e para interagir com o mecanismo de regra, criamos um Projeto dinâmico da web chamado DynamicForms-Web. Os artefatos criados são:

  1. A classe de servlet DynamicFormsServlet, que manipula solicitações e responde aos usuários.
  2. A classe de execução de regras RulesExecutor, que invoca o mecanismo de regra.
  3. Páginas JSP e arquivo de folha de estilo em cascata, que processam formulários para exibir o questionário aos usuários.
Listagem 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;
    }

}

A classe de servlet manipula a solicitação de um usuário para navegar nos formulários (ir para a próxima página ou para a página anterior) e coleta as respostas dos usuários. Quando um usuário vai para uma "próxima página" essa classe chama a classe de execução de regras para invocar o mecanismo de regras e exibe páginas ao usuário. Se um usuário atingir a última página do questionário, uma página de resumo será exibida. Quando um usuário navega até uma "página anterior" a página solicitada é recuperada de uma lista de páginas de formulários.

A classe de execução de regras usa J2SE para executar regras.

Listagem 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;
    }
}

A página JSP renderiza campos com base em seus tipos, que são definidos com regras. Cada campo é renderizado com elementos padrão de HTML. A Listagem 4 mostra como renderizar o campo com o tipo Radio.

Listagem 4. Fragmento de código de forms.jsp para renderização do campo com o tipo 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>
<% } %>

A Figura 10 mostra o exemplo de questionário implementado usando formulários dinâmicos.

Figura 10: questionário baseado na web (página de amostra)
Figura 10: questionário baseado na web (página de amostra)

Conclusão

Os formulários dinâmicos permitem que você defina e mantenha formulários usando regras de negócio. Por meio do exemplo descrito neste artigo, você ciu como um aplicativo pode ser implementado com regras de negócio e tecnologias JEE. Os formulários dinâmicos fornecem ao seu aplicativo a flexibilidade necessária para responder rapidamente às mudanças nos negócios. É possível aproveitar outras tecnologias como Ajax para geração dinâmica de scripts de invocação Ajax para alterar formulários e a estrutura Dojo para geração de formulários com os widgets Dojo.

Agradecimentos

O autor gostaria de agradecer Ming Li e Michael Liu por revisar o conteúdo técnico deste artigo.


Download

DescriçãoNomeTamanho
Code sample fileDF_workspace.zip32KB

Recursos

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que acessar o developerWorks, um perfil será criado para você. Informações do seu perfil (tais como: nome, país / região, e empresa) estarão disponíveis ao público, que poderá acompanhar qualquer conteúdo que você publicar. Seu perfil no developerWorks pode ser atualizado a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=WebSphere
ArticleID=842407
ArticleTitle=Desenvolva Formulários Dinâmicos Usando o WebSphere Operational Decision Management V7.5
publish-date=10232012