a renovação do jsf

45
A renovação do JSF – Parte 1 Esta é a primeira parte de uma série de dois artigos que, juntos, trarão ao leitor uma avaliação das principais características incorporadas na versão mais recente da especificação JavaServer Faces, integrada à Java EE 7. Esta é a primeira parte de uma série de dois artigos que, juntos, trarão ao leitor uma avaliação das principais características incorporadas na versão mais recente da especificação JavaServer Faces, integrada à Java EE 7. Embora a grande maioria das mudanças tenha um caráter mais corretivo ou adaptativo, outras constituem um arsenal ainda maior e mais rico de recursos para o desenvolvimento de soluções web em Java. Os pontos abordados ao longo da série não visam, definitivamente, encerrar o assunto, que é muito amplo e tem uma gama incrível de aplicações. Deste modo, nosso foco será direcionado quase que totalmente para quatro das mais significativas características, as chamadas Big Ticket Features. Em que situação o tema é útil Este tema é bastante relevante para todo desenvolvedor que use a tecnologia Java como alvo em seus sistemas. É igualmente útil para todo entusiasta de tecnologias web e que, por este motivo, gosta de se manter atualizado em relação ao modo como os frameworks mais populares do mercado evoluem ao longo do tempo. Precisamente no dia 12 de junho de 2013, a Oracle lançou oficialmente a versão 7 da Java Enterprise Edition, a plataforma Java para desenvolvimento de soluções web. Esta edição é mais evolucionária do que revolucionária, e conta com atualizações importantes em praticamente todas as especificações que a compõem (Servlets, JPA, Expression Language, CDI, EJB, JMS, JTA, JSP e outras) e também com o lançamento de outras inéditas, como a API para o protocolo Web Sockets (JSR-356) e a API para processamento de conteúdo JSON (JSR-353). Além disso, a Oracle liberou sua implementação de referência para essas revisões através de uma nova versão de seu servidor de aplicações, o GlassFish 4, bem como uma atualização da IDE NetBeans para a versão 7.3.1, totalmente compatível com a Java EE 7 e disponível para download gratuito no site do projeto (veja o endereço para a página desta IDE na seção Links). Neste artigo, cobriremos as novidades em torno da especificação JSF, dando maior atenção para as características consideradas mais profundas, intituladas pelo próprio grupo de trabalho como Big Ticket Features. Ao longo do texto, revisitaremos alguns conceitos fundamentais para facilitar a compreensão do cenário em que a implementação atual se insere, complementando com exemplos práticos e análises passo a passo de todo o código-fonte utilizado. Desta forma, esperamos trazer ao leitor um nível de conforto suficiente para encorajá-lo a utilizar as novidades deste framework em suas próximas aplicações web ou, ainda, aplicá-las nas já existentes. Todo o trabalho realizado para o lançamento do JSF 2.2 originou-se no texto proposto na JSR-344. Boa parte do que se planejou foi cumprido, e o resultado final é uma especificação ainda mais madura, completa, poderosa e, por que não dizer, flexível. Entretanto, os atrasos foram inevitáveis, dada toda a turbulência gerada em torno da tecnologia Java ao longo dos últimos meses por conta de algumas vulnerabilidades tratadas com grande preocupação e, cabe comentar, certo exagero pela mídia. Tudo isso fez com que parte do trabalho fosse iniciada tardiamente, culminando na redução do escopo de algumas características e, em alguns casos, postergação de recursos para edições futuras. A liderança das atividades em torno do JSF 2.2 ficou, mais uma vez, por conta do competente Ed Burns, um engenheiro sênior da Oracle à frente do desenvolvimento desta especificação desde sua primeira versão. Na seção Links, no final do artigo, convidamos o leitor a visitar a página da JSR-344, na qual é possível

Upload: andersonkerlly

Post on 24-Oct-2015

194 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: A renovação do JSF

A renovação do JSF – Parte 1

Esta é a primeira parte de uma série de dois artigos que, juntos,

trarão ao leitor uma avaliação das principais características

incorporadas na versão mais recente da especificação JavaServer

Faces, integrada à Java EE 7.

Esta é a primeira parte de uma série de dois artigos que, juntos, trarão ao leitor uma avaliação das principais

características incorporadas na versão mais recente da especificação JavaServer Faces, integrada à Java EE

7. Embora a grande maioria das mudanças tenha um caráter mais corretivo ou adaptativo, outras constituem

um arsenal ainda maior e mais rico de recursos para o desenvolvimento de soluções web em Java. Os pontos

abordados ao longo da série não visam, definitivamente, encerrar o assunto, que é muito amplo e tem uma

gama incrível de aplicações. Deste modo, nosso foco será direcionado quase que totalmente para quatro das

mais significativas características, as chamadas Big Ticket Features.

Em que situação o tema é útil

Este tema é bastante relevante para todo desenvolvedor que use a tecnologia Java como alvo em seus

sistemas. É igualmente útil para todo entusiasta de tecnologias web e que, por este motivo, gosta de se

manter atualizado em relação ao modo como os frameworks mais populares do mercado evoluem ao longo

do tempo.

Precisamente no dia 12 de junho de 2013, a Oracle lançou oficialmente a versão 7 da Java Enterprise

Edition, a plataforma Java para desenvolvimento de soluções web. Esta edição é mais evolucionária do que

revolucionária, e conta com atualizações importantes em praticamente todas as especificações que a

compõem (Servlets, JPA, Expression Language, CDI, EJB, JMS, JTA, JSP e outras) e também com o

lançamento de outras inéditas, como a API para o protocolo Web Sockets (JSR-356) e a API para

processamento de conteúdo JSON (JSR-353). Além disso, a Oracle liberou sua implementação de referência

para essas revisões através de uma nova versão de seu servidor de aplicações, o GlassFish 4, bem como uma

atualização da IDE NetBeans para a versão 7.3.1, totalmente compatível com a Java EE 7 e disponível para

download gratuito no site do projeto (veja o endereço para a página desta IDE na seção Links).

Neste artigo, cobriremos as novidades em torno da especificação JSF, dando maior atenção para as

características consideradas mais profundas, intituladas pelo próprio grupo de trabalho como Big Ticket

Features. Ao longo do texto, revisitaremos alguns conceitos fundamentais para facilitar a compreensão do

cenário em que a implementação atual se insere, complementando com exemplos práticos e análises passo a

passo de todo o código-fonte utilizado. Desta forma, esperamos trazer ao leitor um nível de conforto

suficiente para encorajá-lo a utilizar as novidades deste framework em suas próximas aplicações web ou,

ainda, aplicá-las nas já existentes.

Todo o trabalho realizado para o lançamento do JSF 2.2 originou-se no texto proposto na JSR-344. Boa

parte do que se planejou foi cumprido, e o resultado final é uma especificação ainda mais madura, completa,

poderosa e, por que não dizer, flexível. Entretanto, os atrasos foram inevitáveis, dada toda a turbulência

gerada em torno da tecnologia Java ao longo dos últimos meses por conta de algumas vulnerabilidades

tratadas com grande preocupação – e, cabe comentar, certo exagero – pela mídia. Tudo isso fez com que

parte do trabalho fosse iniciada tardiamente, culminando na redução do escopo de algumas características e,

em alguns casos, postergação de recursos para edições futuras.

A liderança das atividades em torno do JSF 2.2 ficou, mais uma vez, por conta do competente Ed Burns, um

engenheiro sênior da Oracle à frente do desenvolvimento desta especificação desde sua primeira versão. Na

seção Links, no final do artigo, convidamos o leitor a visitar a página da JSR-344, na qual é possível

Page 2: A renovação do JSF

conhecermos todos os demais membros da equipe e tudo aquilo que foi proposto e realizado por eles. Esta é

uma cultura importante, pois nos ajuda a conhecer melhor o papel fundamental exercido pelo JCP (Java

Community Process) na evolução da tecnologia Java em sua totalidade. À medida que analisamos o

potencial e o nível de influência das cabeças por trás de cada JSR (acrônimo para Java Specification

Request), bem como as empresas que, direta ou indiretamente, estão envolvidas nas discussões, passamos a

entender com muito mais clareza os motivos que fazem com que Java seja líder no mercado mundial por

tantos e tantos anos.

Embora as chamadas “Big Ticket Features” sejam poucas (mais precisamente, quatro), envolvem muitos

conceitos e imprimem, por este motivo, grande densidade ao tema. Logo, para que consigamos tratar todos

os pontos principais com o cuidado necessário e didática adequada, dedicaremos todo o restante do artigo

para a análise pontual de cada um deles, reservando o final do texto para algumas conclusões importantes

acerca de todo o material apresentado.

Algumas palavras iniciais sobre o JSF 2.2

JavaServer Faces, como sabemos, é uma proposta de framework para a construção da camada de

apresentação em sistemas web desenvolvidos em Java. Trata-se de uma dentre as muitas especificações que,

juntas, constituem a plataforma Java EE. Inúmeras tecnologias relacionam-se entre si neste universo, e o

JavaServer Faces 2.2 tem algumas dependências diretas que precisam ser conhecidas por todo

desenvolvedor, para trazer ao leitor uma visão da posição deste framework no ecossistema global. São elas:

· JavaServer Pages 2.2, incluindo Expression Language 2.2 (JSR-245);

· Expression Language 3.0 (JSR-341);

· Servlet 3.0 (JSR-315);

· Java Standard Edition, versão 6 (JSR-270);

· Java Enterprise Edition, versão 6 (JSR-316);

· Java Beans 1.0.1;

· JavaServer Pages Standard Tag Library (JSTL) 1.2.

Todas essas JSRs estão devidamente documentadas no site do JCP, livres para download e consulta.

Novamente, recomendamos ao leitor que dedique algum tempo para conhecer melhor este processo, que dita

o passo do progresso da tecnologia Java em seus diversos sabores.

Outro ponto que devemos destacar, antes de começar a investigar as novas características do framework, é a

limpeza realizada nos seus espaços de nomes (namespaces). O nome Sun foi definitivamente removido das

URIs, que foram redefinidas conforme o conteúdo da Tabela 1. Embora os namespaces antigos ainda sejam

válidos, a recomendação, desde já, é para que passemos a evitar seu uso, substituindo-os pelos novos.

Page 3: A renovação do JSF

Tabela 1. Mudança das URIs dos espaços de nome.

Agora que já falamos rapidamente sobre essas mudanças mais gerais da especificação, é hora de

começarmos a explorar suas principais características.

A primeira Big Ticket Feature: marcadores amigáveis à HTML

Antes de entrarmos no mérito de marcadores “HTML-friendly”, dedicaremos algumas palavras iniciais para

contextualizar o processo de tratamento de requisições de usuário desde o momento em que chegam ao

servidor até aquele em que uma resposta é enviada para o cliente. Observe o diagrama da Figura 1, que

retrata a máquina de estados à qual toda requisição JSF é submetida. Tudo começa em sua recepção, feita

por uma instância da classe javax.faces.webapp.FacesServlet. Este é o controlador frontal do framework,

por onde toda entrada (javax.servlet.ServletRequest) chega e toda resposta (genericamente representada

pela classe javax.servlet.ServletResponse) é despachada. A cada nova requisição, este controlador ficará

responsável por criar um novo objeto de contexto (javax.faces.context.FacesContext) ao qual todas as

estruturas relacionadas a ela (e seus respectivos estados) serão vinculadas. Logo em seguida, chega o

momento do ciclo de vida ser executado; representado genericamente pela classe

javax.faces.lifecycle.Lifecycle, ele encapsula o tratamento de cada um dos seis blocos ilustrados no

diagrama da Figura 1 da seguinte maneira:

· Lifecycle.execute(javax.faces.context.FacesContext): cuida dos cinco primeiros blocos do ciclo de vida,

da restauração da view à invocação da aplicação;

· Lifecycle.render(javax.faces.context.FacesContext): cuida da fase de renderização de respostas que

deverão ser enviadas ao cliente (normalmente, um navegador web);

Page 4: A renovação do JSF

Figura 1. Ciclo de vida de requisições JSF.

Observe que apenas a renderização é separada dos demais blocos do ciclo de vida, fato justificado pela

maior complexidade associada a esta fase. Nos dois métodos listados, vemos que há um parâmetro de

entrada que guarda uma instância de contexto, criada para o tratamento da requisição. Este objeto será, passo

a passo, recheado com todas as informações pertinentes à interação atual, de modo a representar de forma

fiel a situação da aplicação, a cada momento.

A primeira fase do ciclo de vida é a Restauração de uma view, que, em JSF, é representada genericamente

pela classe javax.faces.view.ViewDeclarationLanguage. Nesta fase, o controlador procurará por uma view

cujo identificador (view ID) corresponda exatamente àquele passado na requisição. Caso não a encontre, ela

precisará ser totalmente montada. Por outro lado, se for encontrada, será apenas restaurada. Em ambos os

casos, o objetivo desta fase é fazer com que a view associada à requisição esteja devidamente montada e

identificada no lado servidor.

A forma que o JSF usa para manter esta representação de uma view em memória é a de uma árvore de

objetos, que se inicia a partir de uma raiz (uma instância de javax.faces.component.UIViewRoot), na qual

todos os demais elementos (especializações de javax.faces.component.UIComponent) estão vinculados.

As quatro fases seguintes do ciclo de vida, descritas abaixo, serão executadas apenas nos casos em que a

requisição tenha dados a serem processados. Caso contrário, serão ignoradas e apenas a etapa de

Renderização de resposta será efetivamente processada. Um bom exemplo de cenário em que a resposta é

imediatamente renderizada depois da execução da restauração da view é aquele em que o usuário acessa o

sistema pela primeira vez e a tela inicial deve ser exibida. Neste caso, não há nenhum dado sensível vindo

do cliente e nenhuma ação disparada pelo mesmo; o que existe é apenas uma solicitação de inicialização do

sistema e nada mais.

A segunda etapa no ciclo de vida JSF é a Aplicação dos valores da request. Nela, cada componente da

árvore citada anteriormente terá uma chance de avaliar os parâmetros enviados pelo cliente na requisição,

identificar quais se relacionam com ele e, por fim, atualizar-se de modo a refletir exatamente o estado atual

da aplicação, guardando todos esses valores localmente.

Então, a máquina de estados é movida para a fase do Processamento de validações. Novamente, é dada

uma chance, para cada componente da view, de executar todas as conversões e validações a eles associadas.

Este é o momento em que a checagem de intervalos de dados e/ou conversões de tipos são realizadas, de

Page 5: A renovação do JSF

modo a assegurar que os dados preenchidos no cliente sejam válidos e representem exatamente o que devem

representar.

Se todos os valores preenchidos no cliente forem válidos e todas as conversões programadas forem bem

sucedidas, será permitido que a fase de Atualização dos valores de modelo seja executada. Até o momento

anterior, o foco estava todo na camada de apresentação, em que cada componente da view guardava

localmente os dados a ele associados. Neste instante, entretanto, já é seguro refletir na camada de modelo

todas as informações contidas na camada de apresentação. Para isso, faz-se uso de beans gerenciados (ou

backing beans), associados às views por meio da Linguagem de Expressão (EL, definida na JSR-341),

especificação que também compõe a Java EE e da qual o JSF faz uso massivo.

Até aqui, todos os dados preenchidos e selecionados na view já estão devidamente referenciados na camada

de modelo. A próxima fase, de Invocação da aplicação, consiste em dar aos componentes da view a chance

de executarem ações disparadas pelo cliente. Apenas para facilitar a visualização, imagine uma ação como

sendo um clique em um botão de submissão de formulário. Novamente, há aqui a possibilidade de um bean

gerenciado estar envolvido no processo, desde que métodos implementados por ele sejam vinculados a

propriedades de ação dos componentes desta view, também por meio da já citada EL. É nesta fase que,

através de regras de navegação mapeadas no sistema (mais especificamente, no arquivo de configurações

JSF, o popular faces-config.xml), define-se a próxima view a ser apresentada para o cliente, através da

configuração e utilização de outcomes.

A última fase do ciclo de vida JSF é a Renderização da resposta. Aqui, o sistema já conhece a view que

deve ser apresentada ao cliente, bem como todos os dados que devem ser vinculados a ela. Logo, é

necessário que cada objeto da árvore de componentes JSF seja devidamente convertido para uma linguagem

que seja legível para o cliente. Embora JSF possa ser estendido para trabalhar com outras linguagens de

marcação e outros protocolos, toda a sua implementação padrão está baseada em HTTP(s) e HTML. Quando

o processo de “tradução” é finalizado, o objeto de resposta é preparado e, por fim, enviado para o cliente

através do mesmo controlador frontal, FacesServlet, já mencionado no início do ciclo de vida.

Ao final da etapa de Renderização da resposta, o conteúdo criado é finalmente enviado ao cliente, através

do objeto de resposta (ServletResponse) gerado e manipulado diretamente pelo controlador frontal do

framework (FacesServlet).

Este é, portanto, o processo completo de tratamento de requisições de usuário. Mas, afinal, onde (e de que

maneira) se encaixa a Big Ticket feature intitulada HTML Friendly Markups?

O fato é que, desde a JSF 2.0, a linguagem padrão para declaração de views (View Declaration Language,

ou VDL) é a Facelets, substituta direta da velha conhecida tecnologia de todo programador web em Java, o

JSP (JavaServer Pages). Cada marcador escrito nesta VDL está associado a um componente do framework

(que será, por sua vez, uma especialização de javax.faces.component.UIComponent), e os processos de

encoding (tradução de HTML para componentes Java) e decoding (tradução de componentes Java para

código HTML) que ocorrem nas fases de Restauração de views e Renderização de respostas são

realizados por agentes conhecidos, respectivamente, como view handlers (no caso do encoding em nível de

views), tag handlers (no caso de encoding em nível de marcadores) e renderizadores. Todos eles são

acionados a partir da instância de javax.faces.view.ViewDeclarationLanguage que representa a view em

questão, como já dito. Páginas construídas com o uso de Facelets acabam obrigatoriamente vinculadas ao

processo de renderização do JSF. Sendo assim, para que se tenha uma ideia de como ela será exibida ao

usuário final, é necessário que implantemos esse sistema em um servidor de aplicações (como GlassFish,

WebSphere ou JBoss) ou um servidor web (como Jetty ou Tomcat) e o coloquemos em execução.

Esta nova característica trazida pelo JSF 2.2, no entanto, apresenta dois aspectos que nos permitem mudar

significativamente a forma de trabalhar a interface com o usuário: os atributos e os elementos “pass-

through”. Como os próprios nomes sugerem, esses elementos são ignorados pelo processo convencional do

JSF para a interpretação dos elementos de uma view, uma vez que eles não têm participação na fase de

Page 6: A renovação do JSF

renderização e serão úteis apenas no processamento de conteúdo, no ambiente servidor. Veremos, a seguir,

como cada um funciona.

Atributos pass-through

Todo marcador JSF possui um conjunto de atributos composto por uma combinação de propriedades

definidas no componente (javax.faces.component.UIComponent) e no renderizador (especialização de

javax.faces.render.Renderer) para ele projetados. Conforme já vimos no ciclo de vida acima, cada

elemento da view tem a chance de ler e processar parâmetros escritos na requisição que chega ao servidor.

Para facilitar a visualização disso, basta que imaginemos um elemento muito comum em páginas web: uma

caixa de texto. Enquanto uma palavra digitada é uma propriedade do componente (com valor de negócio,

muitas vezes, sendo usada para atualização do modelo em fases mais avançadas do ciclo de vida), seu

tamanho em pixels é algo mais relacionado à forma como ela deverá ser desenhada para o usuário. Em

ambos os casos, tanto o renderizador quanto o componente já “sabem”, de antemão, exatamente quais os

dados que devem procurar em cada requisição que chega, pois se trata de algo que pertence ao projeto

dessas classes.

No entanto, atributos pass-through têm um propósito diferente: permitir ao programador que defina atributos

adicionais, arbitrários ou não, que serão ignorados tanto pelo componente quanto pelo renderizador a ele

associado. Para exemplificar, vejamos o código da Listagem 1. Nela, vemos as três formas possíveis de se

trabalhar com atributos desta natureza, que são:

1. Por meio do emprego do marcador f:passThroughAttribute, definindo-se a chave (name) e o valor

(value) do atributo. Esta abordagem foi usada no componente de identificador passthrough;

2. Por meio do marcador f:passThroughAttributes, definindo-se um mapa de valores (que será uma

implementação de java.util.Map<String, Object>) que será associado a um conjunto de atributos. Esta

abordagem foi usada no componente de identificador passthrough2;

3. Por meio do uso de atributos inseridos no próprio marcador que representa o elemento HTML, seguindo

um espaço de nomes específico para atributos pass-through (http://xmlns.jcp.org/jsf/passthrough) declarado

e prefixado (neste caso, com pt, de pass-through) na view em questão (<html>). Esta abordagem foi usada

no componente de identificador passthrough3. Perceba que, neste caso usamos tanto um atributo com

semântica previamente conhecida (placeholder, que define um texto de apoio/sugestão ao usuário,

popularmente conhecido como hint text) quanto outro absolutamente arbitrário (chaveQualquer), ao qual

não há semântica alguma previamente associada.

Listagem 1. Página home.xhtml, que trabalha com atributos pass-through aplicados a facelets.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html"

xmlns:f="http://xmlns.jcp.org/jsf/core"

xmlns:pt="http://xmlns.jcp.org/jsf/passthrough">

<h:head>

<title>Java Server Faces 2.2 - Java Magazine</title>

</h:head>

<h:body>

Page 7: A renovação do JSF

<div align="center" >

<h:form prependId="false">

<h:outputText value="Testando pass-through individual:" />

<h:inputText value="#{htmlFriendlyMB.passThroughAttribute}"

id="passthrough" binding=

"#{htmlFriendlyMB.campoTexto}" >

<f:passThroughAttribute name="passthroughAttr1"

value="Testando passthrough" />

</h:inputText> <br/><br/>

<h:outputText value="Testando pass-through via mapa:" />

<h:inputText value="#{htmlFriendlyMB.passThroughAttribute}"

id="passthrough2" binding=

"#{htmlFriendlyMB.campoTexto2}" >

<f:passThroughAttributes

value="#{htmlFriendlyMB.passThroughAttributeMap}" />

</h:inputText> <br/><br/>

<h:outputText value="Testando pass-through via namespace:" />

<h:inputText value="#{htmlFriendlyMB.passThroughAttribute}"

pt:placeholder="Entre com o valor"

id="passthrough3" pt:chaveQualquer="Valor arbitrário"

binding="#{htmlFriendlyMB.campoTexto3}"/> <br/><br/>

<h:commandButton id="cmdPassThrough" value="Analisar"

action="#{htmlFriendlyMB.processarAtributosPassThrough()}" />

</h:form>

</div>

</h:body>

</html>

A recuperação dos valores pass-through associados a elementos HTML, no lado servidor, é possível a partir

de uma nova API incorporada à classe javax.faces.component.UIComponent, assim definida:

1. getPassThroughAttributes(boolean criarMapa): java.util.Map<String, Object> – este método tem

como parâmetro uma variável booleana que, ao ser valorada com true, estabelece que um novo mapa de

objetos deva ser criado caso ainda não exista um mapa de atributos pass-through vinculado ao componente.

Quando este parâmetro for false, no entanto, estabelece-se que null será retornado caso este componente não

tenha um mapa de atributos pass-through associado a ele no instante em que o método for invocado;

2. getPassThroughAttributes(): java.util.Map<String, Object> – este método é uma simplificação do

anterior. Na prática, a sua execução consiste em uma chamada a getPassThroughAttributes(boolean)

passando true como valor de entrada. Usando-se este método, portanto, um ponteiro nulo jamais será

devolvido a quem o invocou;

Observe a Listagem 2, na qual temos um bean gerenciado fazendo uso dos métodos recém-listados. Cada

componente usado na construção da árvore que representa a view da Listagem 1 possui um mapa próprio de

atributos pass-through, e cada um dos valores pode ser facilmente recuperado através da chave que o

identifica nesta coleção. Para facilitar a demonstração prática disto, fizemos uso do atributo binding nos

Page 8: A renovação do JSF

elementos da Listagem 1 para associá-los a instâncias de componentes definidas programaticamente no

bean gerenciado da Listagem 2, a partir dos atributos nomeados como campoTexto, campoTexto2 e

campoTexto3.

Além dos campos de texto citados acima, a view da Listagem 1 também contém um botão, identificado

como cmdPassThrough. Quando ele é clicado, dispara uma chamada ao método de assinatura

processarAtributosPassThrough(), implementado pela classe HtmlFriendlyMB. Este método, uma vez

chamado, dispara uma chamada a três outros métodos privados, em sequência, assim definidos:

1. analisarAtributoPassThrough():void – percorre o mapa de atributos do componente identificado pelo

ID passthrough e imprime o valor de cada atributo na console;

2. percorrerMapaDeAtributos():void – percorre o mapa de atributos do componente identificado pelo ID

passthrough2 e imprime seus valores na console;

3. analisarPassthroughViaNamespace():void – percorre o mapa de atributos do componente identificado

pelo ID passthrough3 e imprime o valor de cada atributo na console.

Listagem 2. HtmlFriendlyMB.java: bean gerenciado que trata do processamento de atributos pass-through.

package br.com.devmedia.jsf22.controller;

import java.util.HashMap;

import java.util.Map;

import javax.inject.Named;

import javax.enterprise.context.RequestScoped;

import javax.faces.component.UIComponent;

/**

* Bean gerenciado usado para mostrar os recursos

da característica de

* marcadores amigáveis ao HTML 5 do JSF 2.2.

*

* @author pedrobrigatto

*/

@Named(value = "htmlFriendlyMB")

@RequestScoped

public class HtmlFriendlyMB {

private String passThroughAttribute;

private Map<String, Object> passThroughAttributeMap;

private UIComponent campoTexto;

private UIComponent campoTexto2;

private UIComponent campoTexto3;

private int contador = 0;

public HtmlFriendlyMB() {

this.passThroughAttributeMap = new HashMap<>();

this.passThroughAttributeMap.put("Atributo1", "Testando");

this.passThroughAttributeMap.put("Atributo2", "Atributos");

Page 9: A renovação do JSF

this.passThroughAttributeMap.put("Atributo3", "Pass-through");

}

//... getters e setters para todos os atributos do bean gerenciado

public void processar() {

resultado = String.format("Este texto já foi

modificado %d vezes", ++contador);

System.out.println(resultado);

}

/**

* Método usado para processar atributos pass-through,

recurso disponibilizado

* na versão 2.2. da especificação JSF.

*/

public void processarAtributosPassThrough() {

analisarAtributoPassThrough();

percorrerMapaDeAtributos();

analisarPassthroughViaNamespace();

}

private void analisarAtributoPassThrough() {

if (campoTexto != null) {

System.out.println(String.format(

"@@@@@ O atributo foi recuperado e tem valor %s",

campoTexto.getPassThroughAttributes()

.get("passthroughAttr1").

toString()));

}

}

private void percorrerMapaDeAtributos() {

if (campoTexto2 != null) {

System.out.println(String.format(

"##### O ID do campo utilizando mapa de

atributos pass-through é %s",

campoTexto.getId()));

Map<String, Object> mapa = campoTexto2

.getPassThroughAttributes();

for (Map.Entry item : mapa.entrySet()) {

System.out.println(String.format(

">>>>> Atributo pass-through

detectado com chave

%s e valor %s", item.getKey().

Page 10: A renovação do JSF

toString(), item.getValue().toString()));

}

}

}

private void analisarPassthroughViaNamespace() {

if (campoTexto3 != null) {

Map<String, Object> mapa = campoTexto3.

getPassThroughAttributes();

for (Map.Entry item : mapa.entrySet()) {

System.out.println(String.format(

">>>>> Atributo pass-through detectado

com chave %s e valor %s",

item.getKey().toString(), item.getValue().toString()));

}

}

}

public Map<String, Object> getPassThroughAttributeMap() {

return passThroughAttributeMap;

}

public void setPassThroughAttributeMap

(Map<String, Object>

passThroughAttributeMap) {

this.passThroughAttributeMap =

passThroughAttributeMap;

}

}

Por fim, na Listagem 3, apresentamos o texto impresso como resultado da execução do código acima

descrito. Ali, podemos ver que, de fato, todos os atributos associados aos Facelets usados na construção da

view da Listagem 1 foram recuperados e analisados com sucesso.

Atributos pass-through, como vimos, podem ser arbitrários, isto é, identificados livremente de acordo com

os planos da equipe de desenvolvimento de projetos em Java para a web. Dessa forma, podemos rechear

componentes de uma view com um conjunto variável de informações adicionais e que podem influenciar, no

ambiente servidor, tanto no modelo de dados quanto no próprio visual da página atual ou de uma página

seguinte do fluxo em questão. Caberá, portanto, ao programador decidir se o conjunto de atributos da

própria API de componentes JSF é suficiente para guardar todas as informações de uma view ou se o uso de

um conjunto adicional de dados, identificados arbitrariamente, pode ser interessante. Em qualquer um dos

casos, o fato importante a ser registrado aqui é que, agora, isto é não apenas possível, mas extremamente

simples de se fazer em JSF.

Vejamos agora como funciona o conceito de elementos pass-through.

Listagem 3. Log do servidor contendo os valores dos atributos pass-through recuperados em tempo de

execução.

Page 11: A renovação do JSF

INFO: JM-JSF22-1 foi implantado com sucesso em 6,738 milissegundos.

INFO: @@@@@ O atributo foi recuperado e tem valor Testando passthrough

INFO: ##### O ID do campo utilizando mapa de atributos pass-through ?

passthrough

INFO: >>>>> Atributo pass-through detectado com

chave Atributo2 e valor Atributos

INFO: >>>>> Atributo pass-through detectado com

chave Atributo1 e valor Testando

INFO: >>>>> Atributo pass-through detectado com

chave Atributo3 e valor Pass-through

INFO: >>>>> Atributo pass-through detectado com

chave chaveQualquer e valor Valor arbitrário

INFO: >>>>> Atributo pass-through detectado com

chave placeholder e valor Entre com o valor

Elementos pass-through

Esta abordagem traz ainda mais liberdade ao autor de páginas em sistemas web desenvolvidos sobre a

plataforma Java EE. Enquanto, com atributos pass-through, falamos exclusivamente de campos associados a

componentes de uma view (escritos a partir da VDL Facelets), agora trataremos de elementos de uma view

declarados a partir de HTML puro e que, por serem assim declarados, passam sobre o mecanismo

convencional de renderização do JSF.

A grande marca desta estratégia está no fato de que, muito embora o conteúdo de uma view possa ser

construído a partir de elementos escritos em HTML, não há prejuízo algum para o sistema em si no tocante a

todos os recursos que o JSF provê no ambiente servidor. A “mágica”, neste caso, fica por conta de uma peça

central de “decoração” de conteúdo, responsável pelo mapeamento de elementos HTML para elementos

JSF. A API responsável por este processo está contida na classe javax.faces.view.facelets.TagDecorator,

sensivelmente aprimorada nesta nova versão da especificação. Este “decorador” é colocado para trabalhar

em uma fase do ciclo de vida conhecida como Restauração da view, abordada há pouco. Nesta fase, a

instância de javax.faces.view.ViewDeclarationLanguage que representa a view atual passa por sua criação

ou restauração. O método no qual este processo de restauração ocorre pertence à API de

ViewDeclarationLanguage e tem a seguinte assinatura:

buildView(FacesContext, UIViewRoot)

Este método é invocado a partir do já descrito controlador frontal da especificação JSF, FacesServlet, nos

momentos iniciais do tratamento da requisição de usuário.

O fluxo completo é denso, mas pode ser resumido pelo diagrama da Figura 2. Por ela, vemos que o

decorador atua como um agente do framework que, analisando cada marcador definido na view em questão,

buscará em uma tabela o seu elemento JSF correspondente. Caso não o encontre, atribuirá a ele um

mapeamento genérico, como veremos mais adiante no texto. Desta forma, ainda que o programador/designer

crie uma view fazendo uso apenas de HTML, serviços do framework farão com que ela tenha sua

representação no lado servidor, tal como acontece com views desenhadas a partir de Facelets.

Page 12: A renovação do JSF

Figura 2. Representação do processo de decoração de marcadores.

Mas, afinal de contas, de onde vêm os dados para que o mapeamento citado ocorra? Quais são os critérios e

as informações que o decorador utilizará para que este processo se conclua com sucesso? A resposta está na

Tabela 2. Este é o conjunto de dados no qual o decorador se baseia para, marcador a marcador definido na

view, encontrar o seu elemento JSF correspondente. Perceba que, para uma grande gama de marcadores

HTML, há um conjunto de combinações possíveis que culminam na definição do marcador alvo na

biblioteca JSF. Para os casos em que não há uma regra de mapeamento específica, a documentação

estabelece que ele seja associado ao elemento genérico “elemento”. Uma vez que o conteúdo a ser

renderizado é HTML puro, não existe a necessidade de se mapear todos os elementos HTML a componentes

específicos da biblioteca do JSF; entretanto, algumas associações são essenciais, como, por exemplo, o

bloco lógico a ser executado no clique de um botão de uma página. A grande vantagem do uso de elementos

pass-through é a possibilidade de, a partir deles, desenharmos páginas web somente com a linguagem

HTML, ignorando o processo de renderização do JSF sem perder, com isso, todos os demais recursos do

framework no tratamento de views do lado servidor. Para entendermos melhor como tudo isso funciona,

vejamos o conteúdo da Listagem 4.

Listagem 4. Index.xhtml – página que faz uso de elementos pass-through.

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:jsf="http://xmlns.jcp.org/jsf"

xmlns:f="http://java.sun.com/jsf/core">

<head jsf:id="head">

<title>Putting it all together </title>

</head>

<body jsf:id="body">

<form jsf:id="form" jsf:prependId="false">

<label jsf:for="name">Name </label>

<input jsf:id="name" type="text"

jsf:value="#{htmlFriendlyMB2.name}" />

<label jsf:for="tel">Tel </label>

Page 13: A renovação do JSF

<input jsf:id="tel" type="text"

jsf:value="#{htmlFriendlyMB2.tel}" />

<label jsf:for="email">Email </label>

<input jsf:id="email" type="text"

jsf:value="#{htmlFriendlyMB2.email}" />

<input type="submit" value="Executar" jsf:id="acao"

jsf:action="#{htmlFriendlyMB2.processar}" >

<f:ajax execute="@form" render="name tel email"

event="action" />

</input>

</form>

</body>

</html>

Page 14: A renovação do JSF

Tabela 2. Base para decoração de elementos HTML.

Nela, todos os elementos da view foram escritos em HTML 5. Não há, como na Listagem 1, o uso de

Facelets para a composição da estrutura da página. Ou seja: há, aqui, uma clara independência em relação

aos elementos JSF para a definição da interface com o usuário, deixando o programador ou designer web

absolutamente livre para trabalhar todos os seus conceitos de experiência de usuário de forma bem mais

ampla. Além disso, toda página desenvolvida apenas com elementos HTML pode ser facilmente aberta e

visualizada em qualquer navegador web sem a necessidade de submetê-la ao runtime JSF. No entanto,

devido ao já mencionado processo de decoração encapsulado pela classe TagDecorator, nenhum dos

recursos JSF é perdido pelo desenvolvedor no ambiente servidor. O mapeamento apresentado pela Tabela 2,

Page 15: A renovação do JSF

bem como todas as regras estabelecidas para a associação entre elementos HTML, view handlers, tag

handlers e renderizadores, garante que a árvore de componentes seja criada, mantida e represente, deste

modo, os estados de cada elemento da view em questão. Logo, o que temos no ambiente servidor ainda são

objetos JSF, o que nos permite trabalhar novamente com o conceito de valores pass-through através da

mesma API já citada.

Perceba que a view da Listagem 4 começa declarando o espaço de nomes “http://xmlns.jcp.org/jsf”,

identificado pelo prefixo jsf, no qual estão definidos atributos a serem usados ao longo de sua estrutura.

Todas as caixas de entrada de texto utilizadas trabalham com um dos atributos definidos neste espaço de

nomes, (jsf:id), para assim serem identificadas unicamente no documento. Além disso, trabalham também

com o atributo (jsf:value) para vincular os dados nelas preenchidas a atributos definidos em um bean

gerenciado, que veremos em instantes. O último elemento definido dentro do formulário é um botão de

submissão, e aqui mais um atributo deste espaço de nomes é utilizado (jsf:action) para vincular eventos de

ação disparados por ele a um método do mesmo bean gerenciado que descreveremos logo mais.

Até aqui, vimos como a view HTML foi montada. Conforme dito acima, todos os campos dela foram

vinculados a atributos e métodos de um bean gerenciado. Este bean gerenciado, apresentado na Listagem 5,

está implementado em uma classe de nome HtmlFriendlyMB2, configurada para estar acessível via EL

através do identificador htmlFriendlyMB2 e cujo escopo será de sessão. Os campos da página têm seus

valores vinculados, cada qual, a um atributo do tipo java.lang.String deste bean, e o botão de submissão de

formulário está configurado para disparar (na fase de Invocação da Aplicação do ciclo de vida, como já

vimos) um método cuja assinatura é a seguinte:

processar (): void

e que, no exemplo, apenas imprime o número de vezes em que o formulário foi submetido; valor este que

fica guardado em um contador que é incrementado a cada clique do botão. A Listagem 6 apresenta o log do

servidor quando este sistema é colocado novamente para executar. Como podemos notar, uma página cujos

elementos de interface estão todos escritos em HTML 5, fazendo uso de atributos personalizados e descritos

em um novo espaço de nomes da especificação JSF, consegue se comunicar com um bean gerenciado Java,

em um ambiente JSF, da mesma forma que já estamos acostumados a ver quando usamos Facelets ou JSF

como VDL para a construção das views de nossos sistemas.

Listagem 5. HtmlFriendlyMB2.java: bean gerenciado que exemplifica o uso de elementos pass-through

package br.com.devmedia.jsf22.controller;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;

import javax.inject.Named;

/**

* Bean gerenciado de escopo de sessão para exemplificar o

uso de elementos pass-through

* da especificação JSF 2.2.

*

* @author pedrobrigatto

*/

@Named(value = "htmlFriendlyMB2")

@SessionScoped

public class HtmlFriendlyMB2 implements Serializable {

Page 16: A renovação do JSF

private String name;

private String tel;

private String email;

private String resultado;

private int contador = 0;

public HtmlFriendlyMB2() {}

//... getters e setters para todos os atributos da classe

public void processar() {

resultado = String.format("Este texto já foi modificado

%d vezes", ++contador);

System.out.println(resultado);

}

}

Listagem 6. Log da aplicação exemplificando o uso de elementos pass-through

INFO: Inicializando Mojarra 2.2.0 ( 20130502-2118

https://svn.java.net/svn/mojarra~svn/tags/2.2.0@11930)

para o contexto '/JM-JSF22-1'

INFO: Monitoring jndi:/server/JM-JSF22-1/WEB-INF/

faces-config.xml for modifications

INFO: Loading application [JM-JSF22-1] at [/JM-JSF22-1]

INFO: JM-JSF22-1 foi implantado com sucesso em 3,004 milissegundos.

INFO: Este texto j? foi modificado 1 vezes

INFO: Este texto j? foi modificado 2 vezes

INFO: Este texto j? foi modificado 3 vezes

Isto é tudo o que precisamos saber, de início, a respeito do recurso de marcadores amigáveis à HTML 5.

Com tudo o que foi apresentado até aqui, o leitor já será capaz de fazer algumas experiências bem

interessantes e testar, por si mesmo, todos os benefícios trazidos a partir desta Big Ticket Feature. Vejamos,

a partir de agora, outra característica central do JSF 2.2: Faces Flow.

Faces Flow

Outra novidade trazida pelo JSF 2.2 é o suporte ao desenvolvimento de sistemas web orientados a fluxos

(workflows). Esta característica, intitulada Faces Flow, foi elaborada em cima dos melhores recursos

existentes em outros frameworks também orientados a fluxos e já consolidados no mercado. São eles:

· Apache MyFaces CODI;

· Oracle ADF Task Flow;

· Spring Web Flow.

A partir de agora, será possível encapsular um conjunto de views/páginas em um pacote independente de

todos os demais, totalmente reutilizável e que, sozinho, será capaz de representar uma funcionalidade do

Page 17: A renovação do JSF

sistema. Desta maneira, as aplicações deixam de ter um único e grande fluxo, e essas pequenas unidades

passam a ser combinadas para compor uma solução final.

Até a plataforma Java EE 6, o escopo que mais chegava próximo ao de um fluxo era o de conversação

(javax.enterprise.context.ConversationScoped), introduzido com a especificação CDI (Contexts and

Dependency Injection) em sua versão 1.0. No entanto, este escopo é um pouco mais amplo que o de um

workflow, pois uma “conversa” entre cliente e servidor pode ser composta por um conjunto variável de

fluxos. Para simplificar a visualização, uma conversação pode ser interpretada como uma aba de um

navegador web executando uma aplicação qualquer. Quando, por uma necessidade qualquer, o mesmo

usuário abre, em duas abas distintas, a mesma aplicação (ainda que em funções diferentes), terá à sua

disposição duas conversações independentes entre si, mas que compartilham da mesma sessão de usuário.

Fluxos, no entanto, éalgo diferente. São definidos por um ponto único de entrada, outro – também único – de

saída e um conjunto variável de passos intermediários. Também podem envolver parâmetros de entrada e de

saída, usados para receber valores de alguns fluxos e enviar valores para outros. Pontos de entrada, pontos

de saída e todos os outros elementos de um fluxo são conhecidos, na literatura, como nós, e é esta a

nomenclatura que usaremos no texto que se segue.

Para facilitar o entendimento, imagine um cadastro em sites de emprego, em que três etapas devem ser

cumpridas para que uma candidatura seja efetuada. Este processo está ilustrado na Figura 3.

Em um primeiro momento, preenchem-se os dados gerais do candidato (como nome, e-mail e telefones de

contato). Feito isso, a próxima etapa é apresentada, em que informações sobre escolaridade devem ser

fornecidas. A terceira e última etapa consiste na digitação de dados referentes ao histórico profissional da

pessoa. Somente quando todos esses dados são passados para o sistema é que o cadastramento desta pessoa

poderá, finalmente, ser realizado. Este é um caso clássico de fluxo, e o leque de cenários similares a ele

ilustra muito bem o quanto é importante, para uma especificação como a JavaServer Faces, ter em seu

arsenal um recurso “nativo” para a implementação de casos desta natureza.

Figura 3. Um modelo de tela para ilustrar o conceito de workflow.

Outro cenário tão ou mais comum quanto o exposto acima é o de venda de produtos pela Internet, em que

passos como Identificação do usuário, Preenchimento de dados de pagamento (cartão de crédito, data de

validade, parcelamento, bandeira, dentre outros) e Finalização da compra são, todos eles, necessários para

que, enfim, seja realizado o processamento da transação. Este é outro cenário que ajuda a esclarecer ao leitor

o conceito de um workflow de forma bem prática.

Page 18: A renovação do JSF

Este último caso mencionado nos ajuda muito a entender, inclusive, a questão do reuso de fluxos. Imagine

que, em sua empresa, seja necessário desenvolver um módulo de pagamento online para um site de comércio

eletrônico de um de seus clientes. Não é difícil imaginar que ele poderá ser útil, também, em projetos

similares, com escopos semelhantes. Por isso, seria extremamente interessante desenvolvê-lo como um

módulo, independente de um sistema específico, para poder “ligá-lo” em qualquer solução em que fosse

interessante. Reuso, portanto, é indubitavelmente o maior valor agregado por esta característica para o JSF.

Como citado anteriormente, Faces Flow muda o foco de páginas para nós. De acordo com a especificação,

são cinco os tipos possíveis de nós:

1. View: um pedaço de uma página ou uma página completa;

2. Chamada a método: invocação de métodos via Expression Language;

3. Switch: decisão de navegação baseada em condições booleanas;

4. Chamada a fluxo: consiste em uma chamada de um fluxo a outro;

5. Retorno de fluxo: consiste em uma configuração de saída de um fluxo.

Faces Flow demandou, ainda, a criação de duas novas anotações (CDI), sendo elas:

· @javax.faces.flow.FlowScoped: que associa o tempo de vida de beans gerenciados assim anotados ao

tempo de duração de um dado fluxo;

· @javax.faces.flow.builder.FlowDefinition: usada para configurar métodos de uma classe que têm por

objetivo construir, programaticamente, um fluxo dentro de uma aplicação.

A especificação também define um novo objeto acessível via EL, identificado pelo nome flowScope. Para

acessá-lo dentro de uma view, por exemplo, basta que utilizemos a notação #{flowScope}, exatamente como

já fazemos com beans gerenciados e outros objetos JSF pré-configurados, como application. Quando este

objeto de escopo é acessado via EL em views, o que ocorre nos bastidores é uma chamada ao método

facesContext.getApplication().getFlowHandler().getCurrentFlowScope(). É dentro deste objeto de

escopo que, por exemplo, serão guardados parâmetros que devem ser passados de um fluxo para outro,

conforme veremos daqui a instantes.

Há uma série de outros detalhes aos quais devemos nos atentar. Para não tornar a análise maçante, no

entanto, faremos uso de um exemplo contido no tutorial da especificação Java EE, que tem como tema a

realização de checkouts em uma loja online, hipotética. Este exemplo pode ser baixado através de uma

ferramenta do GlassFish chamada Update Tool, e as instruções de como fazê-lo estão na seção Links no

final do artigo.

Começaremos pela ilustração da Figura 4, que apresenta a comunicação entre os fluxos propostos no

projeto mencionado.

Page 19: A renovação do JSF

Figura 4. Representação dos fluxos da aplicação de checkout.

Pelo diagrama, vemos dois fluxos implementados. O primeiro deles, chamado joinFlow, foi configurado

declarativamente (ou seja, através de um arquivo XML, chamado joinFlow-flow.xml) e contém apenas dois

nós, identificados por joinFlow.xhtml e joinFlow2.xhtml. O segundo, chamado checkoutFlow, foi

configurado através da API de Faces Flow e é constituído de quatro nós, identificados pelos nomes

checkoutFlow.xhtml, checkoutFlow2.xhtml, checkoutFlow3.xhtml e checkoutFlow4.xhtml. Ambos os fluxos

utilizam beans gerenciados para guardar valores de entrada e processar ações das views neles contidas.

Passaremos, agora, à análise do primeiro fluxo citado, joinFlow. Observe a Listagem 7, na qual é

apresentado o arquivo XML usado para configurá-lo. A definição do fluxo, representada pelo marcador

<flow-definition>, tem um atributo denominado id usado para estabelecer o seu identificador único em toda

a aplicação. Logo em seguida, um nó de retorno é configurado, de modo que seu valor seja recuperado,

dinamicamente, através de um atributo de um bean gerenciado, o qual veremos em detalhes mais adiante.

Parâmetros de entrada também são definidos (param1CheckoutFlow e param2CheckoutFlow), os quais

serão usados para a transmissão de valores iniciais de checkoutFlow para joinFlow. Por fim, um nó de

chamada de fluxo é configurado para estabelecer o modo pelo qual joinFlow invocará checkoutFlow, que é

exatamente a comunicação entre fluxos ilustrada na Figura 4. Perceba que, para esta chamada, dois

parâmetros de saída são definidos (param1FromJoinFlow e param2FromJoinFlow), sobre os quais

voltaremos a falar logo mais.

A convenção de Faces Flow determina que o nó de entrada de todo fluxo é aquele que recebe exatamente o

mesmo nome do fluxo propriamente dito. Este é o caso de joinFlow.xhtml, apresentado na Listagem 8. Este

é um código particularmente rico, através do qual conseguiremos visualizar boa parte dos elementos citados

até aqui.

Listagem 7. joinFlow-flow.xml. Configuração do fluxo joinFlow de forma declarativa (XML).

<?xml version='1.0' encoding='UTF-8'?>

<!--

Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

You may not modify, use, reproduce, or distribute this software except in

compliance with the terms of the License at:

http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

-->

<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"

Page 20: A renovação do JSF

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee

http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">

<flow-definition id="joinFlow">

<flow-return id="returnFromJoinFlow">

<from-outcome>#{joinFlowBean.returnValue}</from-outcome>

</flow-return>

<inbound-parameter>

<name>param1FromCheckoutFlow</name>

<value>#{flowScope.param1Value}</value>

</inbound-parameter>

<inbound-parameter>

<name>param2FromCheckoutFlow</name>

<value>#{flowScope.param2Value}</value>

</inbound-parameter>

<flow-call id="callcheckoutFlow">

<flow-reference>

<flow-id>checkoutFlow</flow-id>

</flow-reference>

<outbound-parameter>

<name>param1FromJoinFlow</name>

<value>param1 joinFlow value</value>

</outbound-parameter>

<outbound-parameter>

<name>param2FromJoinFlow</name>

<value>param2 joinFlow value</value>

</outbound-parameter>

</flow-call>

</flow-definition>

</faces-config>

Listagem 8. joinFlow.xhtml. Ponto de entrada do fluxo identificado como joinFlow.

<?xml version='1.0' encoding='UTF-8' ?>

<!--

Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

You may not modify, use, reproduce, or distribute this software except in

compliance with the terms of the License at:

http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Page 21: A renovação do JSF

<html lang="en"

xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html"

xmlns:f="http://xmlns.jcp.org/jsf/core">

<h:head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<h:outputStylesheet library="css" name="stylesheet.css"/>

<title>Join Flow Page One</title>

</h:head>

<h:body style="background-color: lightgoldenrodyellow">

<h:form prependId="false">

<h:graphicImage url="#{resource['images:duke.books.gif']}"

alt="Duke carrying books"/>

<h2>Join Flow Page One</h2>

<p>Thank you,

<span id="param1FromCheckoutFlow">

#{flowScope.param1Value}</span>

from

<span id="param2FromCheckoutFlow">

#{flowScope.param2Value}</span>.

(Reading the parameters passed in from the checkout flow,

if there are any.)</p>

<p>Check the boxes to receive our newsletters

or special offers.</p>

<h:panelGrid columns="2" role="presentation">

<h:outputLabel for="clubcheck"

value="Yes! I'd like to join the Duke Fan Club!"/>

<h:selectBooleanCheckbox id="clubcheck"

value="#{joinFlowBean.fanClub}"/>

<h:outputLabel for="newslettercheckbox"

value="Send me these FREE newsletters:"/>

<h:selectManyCheckbox id="newslettercheckbox"

layout="pageDirection"

value="#{joinFlowBean.newsletters}">

<f:selectItems value="#{joinFlowBean.newsletterItems}"/>

</h:selectManyCheckbox>

</h:panelGrid>

<p>Click Submit to continue, or Home to go to the

site home page.</p>

<p><h:commandButton value="Submit"

action="joinFlow2"/></p>

<p><h:commandButton value="Exit Flow"

action="returnFromJoinFlow"/></p>

</h:form>

</h:body>

</html>

Page 22: A renovação do JSF

O primeiro desses elementos e sobre o qual falaremos é o parâmetro de entrada, que pode ser usado para

passar valores de um fluxo a outro. Todo parâmetro, como já mencionamos, é guardado no escopo de fluxo,

e de lá recuperado quando for preciso. Na view de entrada de joinFlow, apresentado na Listagem 7, há dois

desses campos posicionados logo no início do código. Perceba que, identificados pelos nomes

param1FromCheckoutFlow e param2FromCheckoutFlow, eles usam exatamente o objeto de escopo

para recuperar seus valores, que estarão guardados, respectivamente, nos atributos param1Value e

param2Value de flowScope.

Outro ponto também destacado no código desta view é a configuração de um nó de retorno, mapeado em um

de seus botões de comando. Perceba que o identificador do valor de retorno é exatamente aquele usado na

Listagem 7, sendo suficiente para que a navegação seja realizada corretamente. Além deste botão, temos

outro que apenas aponta para o próximo passo de joinFlow.

O bean gerenciado responsável pelo tratamento de joinFlow pode ser analisado na Listagem 9. Não

tomaremos muito tempo com este código, pois a única novidade em relação ao que já conhecemos sobre JSF

é o uso do novo escopo do CDI, FlowScoped, que garante que o tempo de vida de objetos desta classe seja

exatamente o tempo de vida do fluxo ao qual eles sejam associados. Ao utilizarmos este tipo de escopo em

beans gerenciados, devemos apenas nos preocupar em garantir que o ID do fluxo associado ao escopo seja

exatamente aquele do fluxo ao qual desejamos vincular esta classe.

Fechando a análise deste primeiro fluxo, temos a Listagem 10, com o conteúdo de seu segundo e definitivo

passo. O ponto que merece destaque, aqui, é a referência ao segundo fluxo da aplicação, checkoutFlow. Isto

é feito configurando-se um dos botões da view para disparar a execução do nó de chamada de fluxo

configurado em joinFlow, o qual, por sua vez, já se encontra configurado para encontrar e iniciar o fluxo de

checkout, como já tivemos a oportunidade de ver na Listagem 7.

Listagem 9. JoinFlowBean.java. Bean gerenciado que tratará especificamente da execução do fluxo

joinFlow.

/**

* Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

*

* You may not modify, use, reproduce, or distribute this software except in

* compliance with the terms of the License at:

* http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

*/

package javaeetutorial.checkoutmodule;

import java.io.Serializable;

import javax.inject.Named;

import javax.faces.flow.FlowScoped;

import javax.faces.model.SelectItem;

/**

* Backing bean for JoinFlow.

*/

@Named

@FlowScoped("joinFlow")

public class JoinFlowBean implements Serializable {

private static final long serialVersionUID = 1L;

private boolean fanClub;

Page 23: A renovação do JSF

private String[] newsletters;

private static final SelectItem[] newsletterItems = {

new SelectItem("Duke's Quarterly"),

new SelectItem("Innovator's Almanac"),

new SelectItem("Duke's Diet and Exercise Journal"),

new SelectItem("Random Ramblings")

};

public JoinFlowBean() {

this.newsletters = new String[0];

}

public String getReturnValue() {

return "/exithome";

}

public boolean isFanClub() {

return fanClub;

}

public void setFanClub(boolean fanClub) {

this.fanClub = fanClub;

}

public String[] getNewsletters() {

return newsletters;

}

public void setNewsletters(String[] newsletters) {

this.newsletters = newsletters;

}

public SelectItem[] getNewsletterItems() {

return newsletterItems;

}

}

Listagem 10. joinFlow2.xhtml. Segunda e última página do fluxo de nome “joinFlow”.

<?xml version='1.0' encoding='UTF-8' ?>

<!--

Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

You may not modify, use, reproduce, or distribute this software except in

compliance with the terms of the License at:

http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

Page 24: A renovação do JSF

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html lang="en"

xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html">

<h:head>

<meta http-equiv="Content-Type" content="text/html;

charset=UTF-8" />

<h:outputStylesheet library="css" name="stylesheet.css"/>

<title>Join Flow Page Two</title>

</h:head>

<h:body style="background-color: lightgoldenrodyellow">

<h:form prependId="false">

<h:graphicImage url="#{resource['images:duke.books.gif']}"

alt="Duke carrying books"/>

<h2>Join Flow Page Two</h2>

<p>Thank you, #{flowScope.param1Value}!

Reading the parameter passed from

the Checkout flow.</p>

<p>To call the checkout flow,

click Check Out.</p>

<p>To go to the site's home page or to return

to the calling flow,

click Home.</p>

<p><h:commandButton value="Check Out"

action="callcheckoutFlow"/></p>

<p><h:commandButton value="Exit Flow"

action="returnFromJoinFlow"/></p>

</h:form>

</h:body>

</html>

Vamos, agora, dedicar algumas palavras ao processo de checkout (checkoutFlow). A mudança, neste caso,

está na configuração do fluxo, que, diferentemente do modelo declarativo de joinFlow, será definido

programaticamente a partir da API de Faces Flow. Na Listagem 11, apresentamos a página de entrada deste

fluxo que, da mesma forma que em joinFlow, é tida como nó de entrada do fluxo por levar o seu nome.

Além disso, assim como também foi feito no fluxo apresentado anteriormente, há parâmetros de entrada

sendo recebidos na view a partir do objeto de fluxo de escopo mantido pelo framework.

A Listagem 12 contém uma classe na qual o fluxo é, então, configurado. A API central de Faces Flow está

definida em javax.faces.flow.builder.FlowBuilder. A partir de uma instância desta classe, somos capazes

de fazer tudo aquilo que conseguimos através de um arquivo XML, como o visto na Listagem 7, em código

Java. Na verdade, quando optamos pela configuração declarativa, estamos delegando ao framework JSF a

construção do fluxo em questão, o que, por sua vez, acaba resultando em uma chamada a esta API, de forma

transparente.

Listagem 11. checkoutFlow.xhtml. Ponto de entrada do fluxo de checkout.

<?xml version='1.0' encoding='UTF-8' ?>

<!--

Page 25: A renovação do JSF

Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

You may not modify, use, reproduce, or distribute this software except in

compliance with the terms of the License at:

http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html lang="en"

xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html"

xmlns:f="http://xmlns.jcp.org/jsf/core">

<h:head>

<meta http-equiv="Content-Type" content="text/html;

charset=UTF-8" />

<h:outputStylesheet library="css" name="stylesheet.css"/>

<title>Checkout Flow Page One</title>

</h:head>

<h:body style="background-color: lightblue">

<h:form prependId="false">

<h:graphicImage url="#{resource['images:duke.books.gif']}"

alt="Duke carrying books"/>

<h2>Checkout Flow Page One</h2>

<p>Thank you for your order of #{checkoutBean.numItems}

books at a cost of

<h:outputText value="#{checkoutBean.cost}">

<f:convertNumber currencySymbol="$" type="currency"/>

</h:outputText>.</p>

<p>Please provide your shipping information. Required fields are

marked with an asterisk (*).</p>

<h3>Shipping Information</h3>

<h:panelGrid columns="3" role="presentation">

<h:outputLabel value="Name: * " for="name"/>

<h:inputText id="name" value="#{checkoutFlowBean.name}"

required="true"/>

<h:message for="name" style="color: #D20005"/>

<h:outputLabel value="Address Line 1: * " for="addr1"/>

<h:inputText id="addr1"

value="#{checkoutFlowBean.addressLine1}"

required="true"/>

<h:message for="addr1" style="color: #D20005"/>

<h:outputLabel value="Address Line 2:" for="addr2"/>

<h:inputText id="addr2"

value="#{checkoutFlowBean.addressLine2}"/>

<h:message for="addr2" style="color: #D20005"/>

Page 26: A renovação do JSF

<h:outputLabel value="City: * " for="city"/>

<h:inputText id="city" value="#{checkoutFlowBean.city}"

required="true"/>

<h:message for="city" style="color: #D20005"/>

<h:outputLabel value="State:" for="state"/>

<h:inputText id="state" value="#{checkoutFlowBean.state}"

maxlength="2"/>

<h:message for="state" style="color: #D20005"/>

<h:outputLabel value="Zip/Postcode: * " for="zip"/>

<h:inputText id="zip" value="#{checkoutFlowBean.postalCode}"

required="true"/>

<h:message for="zip" style="color: #D20005"/>

<h:outputLabel value="Country: * " for="country"/>

<h:inputText id="country" value="#{checkoutFlowBean.country}"

required="true"/>

<h:message for="country" style="color: #D20005"/>

</h:panelGrid>

<p>If you called this flow from the Join flow,

you can see these parameters:

"<h:outputText value="#{flowScope.param1Value}"/>" and

"<h:outputText value="#{flowScope.param2Value}"/>"

</p>

<p>Click Continue to move to the next page

of the flow.</p>

<p>Click Cancel to exit the flow and return to

the starting page.</p>

<p></p>

<p><h:commandButton value="Continue"

action="checkoutFlow2"/></p>

<p><h:commandButton value="Exit Flow"

action="returnFromCheckoutFlow"/></p>

</h:form>

</h:body>

</html>

Listagem 12. CheckoutFLow.java. Classe usada para se configurar o fluxo de checkout programaticamente.

/**

* Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

*

* You may not modify, use, reproduce, or distribute this software except in

* compliance with the terms of the License at:

* http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

Page 27: A renovação do JSF

*/

package javaeetutorial.checkoutmodule;

import java.io.Serializable;

import javax.enterprise.inject.Produces;

import javax.faces.flow.Flow;

import javax.faces.flow.builder.FlowBuilder;

import javax.faces.flow.builder.FlowBuilderParameter;

import javax.faces.flow.builder.FlowDefinition;

public class CheckoutFlow implements Serializable {

private static final long serialVersionUID = 1L;

@Produces

@FlowDefinition

public Flow defineFlow(@FlowBuilderParameter FlowBuilder flowBuilder) {

String flowId = "checkoutFlow";

flowBuilder.id("", flowId);

flowBuilder.viewNode(flowId, "/" + flowId + "/" + flowId + ".xhtml").

markAsStartNode();

flowBuilder.returnNode("returnFromCheckoutFlow").

fromOutcome("#{checkoutFlowBean.returnValue}");

flowBuilder.inboundParameter("param1FromJoinFlow",

"#{flowScope.param1Value}");

flowBuilder.inboundParameter("param2FromJoinFlow",

"#{flowScope.param2Value}");

flowBuilder.flowCallNode("calljoin").flowReference("", "joinFlow").

outboundParameter("param1FromCheckoutFlow",

"#{checkoutFlowBean.name}").

outboundParameter("param2FromCheckoutFlow",

"#{checkoutFlowBean.city}");

return flowBuilder.getFlow();

}

}

Toda vez que quisermos definir, em nossos sistemas, um método produtor de fluxos JSF, deveremos seguir

os passos listados a seguir:

· O método precisa ser configurado como produtor, através da anotação CDI

@javax.enterprise.inject.Produces;

· O método precisa ser configurado, também, com a anotação @javax.faces.flow.builder.FlowDefinition,

que garante que o que será produzido pelo método em questão é um fluxo (javax.faces.flow.Flow);

Page 28: A renovação do JSF

· O método deve retornar uma instância de javax.faces.flow.Flow;

· O método deve receber, por parâmetro, uma instância de javax.faces.flow.builder.FlowBuilder, que será

usado para configurar, de fato, o fluxo em questão;

Pelo código da Listagem 12, o leitor pode perceber que o que é feito ali é exatamente aquilo que já vimos

no arquivo XML apresentado na Listagem 7. Por este motivo, não investiremos tempo em analisar o

conteúdo deste método.

Na Listagem 13, apresentamos o nó de saída de checkoutFlow, que em muito se assemelha ao conteúdo da

Listagem 10. Vemos, ali, uma ação mapeada para saída de checkoutFlow e também uma ação de entrada

para joinFlow, que estabelece uma comunicação entre esses dois fluxos no sentido inverso ao que já vimos

quando analisamos joinFlow.

Listagem 13. checkoutFlow4.xhtml. Última página do fluxo de checkout.

<?xml version='1.0' encoding='UTF-8' ?>

<!--

Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

You may not modify, use, reproduce, or distribute this software except in

compliance with the terms of the License at:

http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html lang="en"

xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html">

<h:head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<h:outputStylesheet library="css" name="stylesheet.css"/>

<title>Checkout Flow Page Four</title>

</h:head>

<h:body style="background-color: lightblue">

<h:form prependId="false">

<h:graphicImage url="#{resource['images:duke.books.gif']}"

alt="Duke carrying books"/>

<h2>Checkout Flow Page Four</h2>

<p>Thank you for your order,

<h:outputText value="#{checkoutFlowBean.name}"/>!</p>

<p>Your order will be billed to

<h:outputText value="#{checkoutFlowBean.ccName}"/>.</p>

<p>To join our mailing list or club, click Join. This action will

call the Join flow.</p>

<p>To return to the index page or to the first page of the calling

flow, click Return.</p>

<p><h:commandButton value="Join" action="calljoin"/></p>

<p><h:commandButton value="Exit Flow"

action="returnFromCheckoutFlow"/></p>

Page 29: A renovação do JSF

</h:form>

</h:body>

</html>

As Listagens 14 e 15 foram apresentadas aqui apenas para fecharmos a composição dos ciclos. A Listagem

14 mostra a página de entrada da aplicação, onde cada um dos botões nela incluídos aponta para os fluxos

que vimos até o momento. A ação desses botões é estática e tem como valor o nome dos nós iniciais de cada

fluxo. Uma vez que essas páginas sejam acessadas, pela convenção que já foi apresentada ao leitor

anteriormente, é detectada a entrada em um fluxo, que passará a ser executado. A Listagem 15, por sua vez,

é uma página que representa o nó de saída do fluxo joinFlow, que contém um botão que redireciona o

usuário para a página inicial, já citada, contida na Listagem 14.

Listagem 14. Index.xhtml. Página inicial da aplicação.

<!--

Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

You may not modify, use, reproduce, or distribute this software except in

compliance with the terms of the License at:

http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html lang="en"

xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html"

xmlns:f="http://xmlns.jcp.org/jsf/core">

<h:head>

<meta http-equiv="Content-Type" content="text/html;

charset=UTF-8" />

<h:outputStylesheet library="css" name="stylesheet.css"/>

<title>Checkout Module: Entry Page (Order)</title>

</h:head>

<h:body>

<h:form prependId="false">

<h:graphicImage url="#{resource['images:duke.books.gif']}"

alt="Duke carrying books"/>

<h2>Order Page</h2>

<p>You have ordered #{checkoutBean.numItems}

books at a cost of

<h:outputText value="#{checkoutBean.cost}">

<f:convertNumber currencySymbol="$" type="currency"/>

</h:outputText>.</p>

<p>Click Check Out to check out your order

and enter the checkout

flow.</p>

<p><h:commandButton value="Check Out"

action="checkoutFlow"/></p>

Page 30: A renovação do JSF

<p>Click Join to join our mailing list or club and enter the join

flow.</p>

<p><h:commandButton value="Join" action="joinFlow"/></p>

<p>This page is the exit point for the checkout flow pages.</p>

</h:form>

</h:body>

</html>

Listagem 15. exitHome.xhtml. Página de saída do fluxo intitulado joinFlow.

<?xml version='1.0' encoding='UTF-8' ?>

<!--

Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.

You may not modify, use, reproduce, or distribute this software except in

compliance with the terms of the License at:

http://java.net/projects/javaeetutorial/pages/BerkeleyLicense

-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html">

<h:head>

<meta http-equiv="Content-Type" content="text/html;

charset=UTF-8" />

<h:outputStylesheet library="css"

name="stylesheet.css"/>

<title>Checkout Module: Exit Page (Home)</title>

</h:head>

<h:body>

<h:form>

<h:graphicImage url="#{resource['images:duke.books.gif']}"

alt="Duke carrying books"/>

<h2>Home/Exit Page</h2>

<p>Imagine that this is the home page of the company.

When you exit the join flow pages,

you land here.</p>

<p><h:commandButton value="Go to Checkout Page"

action="index"/></p>

</h:form>

</h:body>

</html>

Conclusão

Chegamos ao final do primeiro artigo da série sobre as novidades do JSF 2.2. Ao longo do texto, vimos duas

das mais significativas características incorporadas à especificação, que abrem agora a chance de se

trabalhar nativamente com fluxos e permitem, também, que se explore de forma livre e plena os recursos do

HTML 5 no desenvolvimento da interface gráfica de aplicações JSF. Essas são duas das quatro

Page 31: A renovação do JSF

características mais impactantes desta revisão do framework, restando ainda outras duas a serem abordadas

no último artigo da série.

Nele, trataremos em detalhes o conceito de views stateless e toda a discussão que esta questão gera. Esta é

uma solicitação antiga de muitos desenvolvedores, que viram, ainda que de forma reduzida, o seu pedido

finalmente atendido. Veremos, ainda, como funciona um mecanismo intitulado contratos de bibliotecas de

recursos, cuja ideia é a de suportar múltiplos templates dentro de uma aplicação Java para web.

Encerraremos o segundo artigo com algumas palavras sobre outra característica que, embora não tenha o

rótulo de “Big Ticket”, será de grande valor para a comunidade de desenvolvedores, facilitando

significativamente o trabalho com o recurso de upload de arquivos em aplicações web baseadas em JSF.

Desde já, gostaríamos de deixar novamente o convite para que o leitor consulte a documentação oficial da

JSR-344, cujo endereço pode ser encontrado na seção Links. Nela é possível termos uma noção mais plena

de todo o volume de trabalho realizado em cima do JSF, e o quanto tudo o que foi incorporado contribui no

sentido de entregar, à comunidade, um framework ainda mais robusto, poderoso, flexível e completo.

Por enquanto, desejamos ao leitor um bom divertimento com o conteúdo abordado até aqui, e deixamos

marcado um encontro, muito em breve, para fecharmos este nosso estudo em cima das novidades do

JavaServer Faces. Até lá!

A renovação do JSF – Parte 2

Neste artigo abordaremos três outras características centrais do

JSF 2.2, cobrindo todos os pontos classificados, na especificação,

como “Big Ticket Features”, fechando assim uma análise em torno

de todas as novidades mais relevantes.

A renovação do JSF – Parte 2

JavaServer Faces, o framework mais popular da especificação Java EE para o desenvolvimento da camada

de apresentação em sistemas web, foi atualizado. No primeiro artigo desta série, estudamos duas das mais

relevantes mudanças trazidas com a nova versão: uma perspectiva de desenvolvimento orientado a fluxos

(Faces Flow) e marcadores amigáveis à HTML 5, permitindo o uso desta linguagem em substituição à

Facelets na estruturação de views/páginas, quando desejado e/ou necessário. No texto que se segue,

abordaremos três outras características centrais do JSF 2.2, cobrindo todos os pontos classificados, na

especificação, como “Big Ticket Features”, fechando assim uma análise em torno de todas as novidades

mais relevantes encontradas nesta nova versão do framework.

Em que situação o tema é útil

Este tema será útil para todo desenvolvedor web que utilize Java como tecnologia-alvo. Será igualmente

proveitoso para todo entusiasta de tecnologias web que gosta de se manter atualizado sobre a evolução dos

frameworks mais populares do mercado ao longo do tempo.

No primeiro artigo desta série, analisamos uma característica bastante útil chamada Faces Flow. A partir

dela, passamos a contar com suporte nativo, em Java EE, para o desenvolvimento de aplicações orientadas a

Page 32: A renovação do JSF

fluxos, algo inédito até então e projetado a partir das melhores práticas e melhores recursos presentes em

frameworks de mercado que já trabalham neste modelo.

Estudamos, também, a flexibilização da especificação JSF no tocante à construção de interfaces com o

usuário a partir do recurso intitulado “HTML Friendly Markups” (ou, traduzido para o português,

marcadores amigáveis à HTML 5). Por ele, passa a ser possível contornarmos o modelo padrão de

desenvolvimento de views, substituindo a linguagem Facelets por HTML e, ainda assim, utilizarmos todos

os benefícios dos serviços oferecidos pelo framework no ambiente servidor (como a representação de views

a partir de árvores de componentes, preservação do estado dessas views, validações, conversões, dentre

outros).

Neste último artigo, veremos outras três importantes novidades do JSF 2.2. Ao longo do texto, o leitor

tomará contato com um novo componente projetado especificamente para a carga de arquivos (file upload),

uma estratégia para configurar e trabalhar com views stateless e, ainda, uma técnica para a construção e

utilização de múltiplos templates dentro de uma mesma aplicação.

Carregando arquivos no servidor com JSF

Carregar arquivos da camada cliente para a camada servidora nunca foi um recurso nativo no JavaServer

Faces. Para que nossas aplicações apresentassem este tipo de característica para o usuário final, tínhamos

que recorrer a dependências externas, dentre as quais a mais popular é a Apache Commons FileUpload (veja

a seção Links). Mesmo em implementações mais sofisticadas da especificação, como é o caso do

PrimeFaces, o componente que apresenta este recurso pronto para o desenvolvedor utiliza, implicitamente,

essas mesmas dependências.

Para começarmos a analisar este novo componente para carga de arquivos trazido pelo JSF 2.2, precisamos

compreender, com clareza, o ambiente no qual está inserido. Este recurso do framework tem sua base

estabelecida no suporte a multipart da Servlet API 3.0, o que significa que:

· O controlador frontal do JSF, javax.faces.webapp.FacesServlet é, agora, configurado com a anotação

@MultipartConfig da Servlet API 3.0 (JSR-315), tornando possível o tratamento de requisições cujo

conteúdo tenha sido codificado como multipart/form-data;

· Esta configuração descrita no item acima gera uma dependência do JSF em relação à Servlet API 3.0,

como já havíamos antecipado no início do artigo anterior.

Todo formulário cujo tipo de codificação de conteúdo seja multipart-form-data submeterá os dados nele

contido como uma grande stream de dados preparada de modo que cada campo seja representado como uma

parte. Toda parte, por sua vez, conterá não apenas o conteúdo definido, mas também, metadados como

tamanho, nome de arquivo (quando aplicável), dentre outros. Dentro dessa stream de dados, enviada na

requisição, são usadas strings delimitadoras de início e de fim. Assim, no ambiente servidor, será possível

separar os dados e metadados de cada campo para, então, processá-los adequadamente.

Uma parte, na Servlet API 3.0, é representada pela interface javax.servlet.http.Part. De acordo com sua

documentação oficial, esta interface representa “uma parte ou um item de um formulário recebida(o) a partir

de uma requisição cujo método seja POST e cujo tipo de encoding seja multipart/form-data”.

Sem nos demorarmos mais em teoria, vamos então para um estudo de caso. Começaremos pela Listagem 1,

que contém um formulário no qual usamos o novo componente criado para upload de arquivos, cujo

marcador atende por <h:inputFile> e pertence ao espaço de nomes de elementos HTML da JSF

(http://xmlns.jcp.org/jsf/html). Ainda sobre este formulário, é importante nos atentarmos para alguns fatos:

· Conforme requisito já levantado, a codificação de seu conteúdo foi configurada como multipart/form-data;

Page 33: A renovação do JSF

· O campo de carregamento de arquivo (<h:inputFile>) terá seu valor associado a um campo de um bean

gerenciado (cujo código veremos em instantes), através da já conhecida notação da Expression Language;

· Todo arquivo carregado e submetido deverá ser representado logicamente por uma instância de

javax.servlet.http.Part, dada a dependência já mencionada do JSF pela Servlet API.

Listagem 1. index.xhtml. Página inicial da aplicação que demonstra a carga de arquivos em JSF 2.2.

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html">

<h:head>

<title>Testando o upload de arquivos com JSF 2.2</title>

</h:head>

<h:body>

<h:form prependId="false" enctype="multipart/form-data" >

<h:panelGrid columns="2" >

<h:outputText value="Entre com o arquivo:" />

<h:inputFile value="#{uploadBean.arquivo}" />

<h:commandButton value="Enviar arquivo"

action="#{uploadBean.carregarArquivo()}" />

</h:panelGrid>

</h:form>

</h:body>

</html>

Observe a Listagem 2. Nela, encontramos o código-fonte do bean gerenciado citado no segundo item da

lista de marcadores do parágrafo anterior. Há um atributo nesta classe, chamado arquivo, que é exatamente

aquele usado pelo formulário para transmitir o arquivo escolhido por um usuário para carga. Este atributo,

como já sentenciado no terceiro item da lista acima, deve ter como tipo javax.servlet.http.Part, pelas

condições já explicadas.

Listagem 2.UploadBean.java. Bean gerenciado que realiza a carga de arquivos no servidor.

package br.com.devmedia.uploadapp.mbeans;

import java.io.File;

import java.io.IOException;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;

import javax.inject.Named;

import javax.servlet.http.Part;

/**

* Bean gerenciado utilizado para exemplificar o uso do suporte nativo da

* especificação JavaServer Faces 2.2 no tratamento a upload de arquivos.

*

Page 34: A renovação do JSF

* @author pedrobrigatto

*/

@Named(value = "uploadBean")

@SessionScoped

public class UploadBean implements Serializable {

/**

* Atributo usado para receber o arquivo selecionado pelo usuário

*/

private Part arquivo;

/**

* Método usado pela view para submeter o formulário preenchido pelo

* usuário.

*

* @return Um outcome usado pela aplicação para determinar a próxima view.

* @throws IOException Caso algum problema na escrita do arquivo ocorra.

*/

public String carregarArquivo() throws IOException {

String nomeArquivoSubmetido = arquivo.getSubmittedFileName();

System.out.println(String.format(

"Valor da propriedade submittedFileName antes do parse: %s",

nomeArquivoSubmetido));

formatarNome(nomeArquivoSubmetido);

System.out.println(String.format(

"Valor da propriedade submittedFileName depois do parse: %s",

nomeArquivoSubmetido));

// Usando modelo anterior a Servlets API 3.1, a partir do cabeçalho.

String nomeArquivo = lerNomeArquivo(arquivo);

arquivo.write(nomeArquivo);

return "success";

}

/**

* Método usado para obter o nome do arquivo a partir de uma coleção de

* campos de cabeçalho identificado pelo nome "content-disposition".

*

* @param arquivo Parte do formulário que guarda um arquivo a ser

* armazenado.

* @return O nome do arquivo, guardando no cabeçalho.

* @throws IOException Caso algum problema de leitura desta parte do

* formulário ocorra.

*/

private String lerNomeArquivo(Part arquivo) throws IOException {

Page 35: A renovação do JSF

String nomeObtido = null;

String[] dadosCD = arquivo.getHeader("content-disposition").split(";");

for (String cd : dadosCD) {

if (cd.trim().startsWith("filename")) {

System.out.println(String.format("Atributo do cabeçalho: %s", cd));

// Removendo as aspas duplas que envolvem o nome do arquivo.

String nomeArquivo = cd.substring(cd.indexOf("=") + 1).

trim().replace("\"", "");

System.out.println(String.format("Valor guardado pelo atributo: %s",

nomeArquivo));

formatarNome(nomeArquivo);

nomeObtido = nomeArquivo;

break;

}

}

return nomeObtido;

}

private void formatarNome(String nomeArquivo) {

// Recuperando o texto imediatamente após a ocorrência da última barra.

nomeArquivo = nomeArquivo.substring(

nomeArquivo.lastIndexOf(File.separatorChar) + 1);

System.out.println(String.format("Atributo do cabeçalho: %s", nomeArquivo));

}

public Part getArquivo() {

return arquivo;

}

public void setArquivo(Part arquivo) {

this.arquivo = arquivo;

}

}

Esta interface é, por si só, suficiente para representar todas as informações de um arquivo, de seu conteúdo a

seu nome e tamanho. Na Java EE 6, esta interface ainda não continha um método cuja assinatura é a

seguinte:

getSubmittedFileName() : String

Este método foi incorporado na Servlet API 3.1, que é outro conjunto de melhorias/correções trazido com a

Java EE 7. Na versão anterior, era necessário implementarmos uma lógica na qual tomávamos um item de

cabeçalho específico, de identificador content-disposition e, a partir dele, verificávamos o campo de nome

filename. Atualmente, a execução do método acima exposto mostrou-se equivalente à lógica anteriormente

empregada, de modo que uma invocação a ele é, a partir de agora, suficiente para obtermos o nome do

arquivo submetido por um usuário.

Page 36: A renovação do JSF

De qualquer maneira, esta lógica foi inserida no código da Listagem 2, de modo que o leitor tenha acesso ao

modelo antigo de se recuperar o nome de arquivos. Quando depuramos a aplicação e analisamos este item de

cabeçalho com calma, vemos que são três os campos retornados. São eles:

· form-data: indica o tipo de codificação de conteúdo;

· name: fornece o ID do campo na árvore de componentes da view;

· filename: fornece o nome do arquivo submetido.

Usando esta abordagem, portanto, basta que percorramos este array de elementos e capturemos o valor

guardado pela célula identificada por filename. Ao encontrá-la, partimos para o processamento de seu

conteúdo, de modo a garantir que, independente do sistema operacional no qual estivermos trabalhando,

tenhamos extraído seu valor corretamente.

O processo de escrita do arquivo em disco, no ambiente servidor, é bastante simplificado com o uso da API

de javax.servlet.http.Part. Ainda na Listagem 2, vemos que a última instrução do método

carregarArquivo() consiste em uma chamada a um método desta API, cuja assinatura é a seguinte:

write (String filename) : void

sendo filename o nome do arquivo obtido de uma dentre as duas maneiras já citadas e, aqui, somente

reforçadas:

· Recuperando-se um campo definido no cabeçalho de ID content-disposition;

· Recuperando-se o nome deste arquivo por meio de uma chamada ao método

javax.servlet.http.Part#geSubmitedFileName().

Isto, por si só, é suficiente para que o arquivo seja gravado em disco, em um caminho relativo àquele

especificado na anotação @MultipartConfig. No caso da implementação de FacesServlet que usamos

(Mojarra), o caminho pré-estabelecido para arquivos é <home_do_servidor

>/glassfish/domains/<dominio>/generated/jsp.

É importante, ainda, mencionarmos que o servidor de aplicações que usamos em nossos testes é o GlassFish

4.

Com o sucesso do upload do arquivo, será apresentada ao usuário uma view de sucesso, cujo código

podemos ver na Listagem 3. Nela, também temos um comando que permite voltarmos à view da Listagem

1, para executarmos novamente todo o processo em uma nova carga.

Listagem 3. success.xhtml. Página de saída quando a carga de arquivos for bem sucedida.

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html">

<h:head>

<title>Testando o File Upload da JSF 2.2</title>

</h:head>

<h:body>

<h:form prependId="false" >

Page 37: A renovação do JSF

Upload realizado com sucesso!!!!!!!!!! <br /><br />

<h:commandButton value="Voltar" action="index" />

</h:form>

</h:body>

</html>

E, assim, cobrimos o recurso de upload de arquivos que o JSF passou a suportar, desde sua versão 2.2,

nativamente, como parte integrante de sua especificação. Como vimos, os primeiros passos com este novo

recurso são bastante simples de serem seguidos, ponto muito positivo para que passemos a adotá-lo em

nossas próximas soluções.

Contratos de bibliotecas de recursos

Neste tópico, analisaremos outra característica do JavaServer Faces rotulada como “Big Ticket Feature”. No

primeiro artigo da série, já vimos duas delas, a saber: Faces Flow e HTML Friendly Markups. Agora, é a vez

de falarmos do que se chamou de Resource Library Contracts, ou “contratos de bibliotecas de recursos”.

Como já sabemos, algumas características planejadas para o JSF 2.2 acabaram sendo prejudicadas por terem

sido iniciadas muito tardiamente. Em alguns casos, tais características foram totalmente postergadas,

enquanto, em outros, sofreram redução de escopo para que pudessem, ainda que sem a sofisticação

planejada, ser incorporadas na especificação. Este é o caso do que, originalmente, deveria se chamar Multi-

templating, característica muito relevante que ainda não teremos como ver funcionando em sua plenitude.

Em linhas gerais esta proposta visa permitir:

· Que se defina múltiplos templates para um mesmo projeto, empacotando-os de forma independente das

aplicações que deles façam uso;

· O suporte “on-the-fly” para mudança de temas, possibilitando a troca de fontes, diagramação e mesmo

padrão de cores de acordo com a preferência do usuário, com o sistema em pleno funcionamento;

· Que usuários criem seus próprios temas e os carreguem na aplicação, de modo que a estilização das

soluções JSF seja um processo não mais vinculado apenas a desenvolvedores, mas também ao público

consumidor de soluções baseadas em JSF.

A redução do escopo desta característica fez com que se atribuísse, ao trabalho, o título mencionado no

início deste tópico: Resource Library Contracts. Embora tenha sido entregue algo muito menor do que o

inicialmente planejado, o que temos em mãos já é, sem dúvidas, muito rico.

Tudo gira em torno do conceito de contratos. Mas, afinal, o que são? Para ajudá-lo a entender, faremos uso

da Figura 1. Todo contrato é composto, como se vê na ilustração, por três elementos:

1. Recursos: imagens, arquivos contendo páginas de estilo, dentre outros;

2. Templates: os modelos de views propriamente ditos, que estabelecem como o conteúdo será apresentado

para o usuário final;

3. Pontos de inserção: pontos, nesses modelos já citados, configurados para acomodar conteúdo das

diversas views que compõem o sistema;

Page 38: A renovação do JSF

Figura 1. Diagrama representando a estrutura de contratos.

Um dos pontos fortes da estratégia de definição de contratos é que cada um pode ser empacotado

separadamente dos demais. Seguindo a ilustração proposta na Figura 1, poderíamos ter três arquivos JAR

contendo, cada qual, o conteúdo correspondente a um contrato. Estes, por sua vez, poderiam ser utilizados

não apenas no projeto que veremos adiante, mas em tantos outros projetos em que pudessem ser úteis.

Apresentado o conceito, passemos para um estudo mais prático. Antes, porém, convidamos o leitor a dedicar

alguma atenção à Figura 2. Nela, temos a estrutura de um projeto criado a partir da IDE NetBeans que,

embora esteja oficialmente na versão 7.3.1, já está com a versão 7.4 Beta disponível para download. Nela,

encontramos suporte direto à criação de contratos, em que a própria IDE monta para nós a estrutura de

diretórios de acordo com a convenção especificada. Esta convenção dita que, em um projeto em Java para a

web, todo contrato deve ser criado dentro de um novo diretório denominado contracts; diz, também, que o

nome que se dá ao diretório referente ao contrato será o nome do contrato em questão. Na Figura 2, de

acordo com o que acabamos de ver, temos um exemplo de dois contratos distintos, de nomes contrato1 e

contrato2.

Figura 2. Estrutura do projeto para estudo de Contratos de Bibliotecas de Recursos do JSF.

A Listagem 4 nos apresenta o template definido para o contrato de nome contrato1. Nela, o leitor perceberá

que existe um ponto de inserção, identificado pelo nome conteudo, que será usado para, em tempo de

execução, acomodar um conteúdo de acordo com a view que for apresentada ao usuário. A Listagem 5, por

sua vez, mostra outro template, definido para o contrato de nome contrato2, que difere do primeiro apenas

na cor de fundo e em alguns poucos textos que serão apresentados ao usuário. Novamente, o mesmo ponto

de inserção, com o mesmo nome que o primeiro, aparece no template. Veremos, a seguir, que o fato do

Page 39: A renovação do JSF

ponto de inserção ser identificado pelo mesmo nome nos dois templates será um ponto decisivo no

comportamento da aplicação.

Listagem 4. template.xhtml. Template definido para o primeiro contrato da aplicação.

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html"

xmlns:ui="http://xmlns.jcp.org/jsf/facelets">

<h:head>

<title>Java Server Faces 2.2 - JAVA MAGAZINE</title>

</h:head>

<h:body style="background-color: brown;">

<p><h2>Testando o uso de templates múltiplos com JSF 2.2 - TEMPLATE 1</h2></p>

<p style="color: whitesmoke;">

<h3>Este é o primeiro contrato definido para a aplicação</h3>

</p>

<ui:insert name="conteudo" />

</h:body>

</html>

Listagem 5. template.xhtml. Template definido para o segundo contrato da aplicação.

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html"

xmlns:ui="http://xmlns.jcp.org/jsf/facelets">

<h:head>

<title>Java Server Faces 2.2 - JAVA MAGAZINE</title>

</h:head>

<h:body style="background-color: blueviolet;">

<p><h2>Testando o uso de templates múltiplos com JSF 2.2 - TEMPLATE 2</h2></p>

<p style="color: darkgreen;">

<h3>Este é o segundo contrato definido para a aplicação</h3>

</p>

<ui:insert name="conteudo" />

</h:body>

</html>

Passemos, agora, à análise do conteúdo da Listagem 6. Este é um exemplo da aplicação do recurso de

contratos em uma view que será, efetivamente, apresentada ao usuário. Nela, vemos o emprego de um novo

Page 40: A renovação do JSF

atributo incorporado no JSF 2.2, de nome contracts. Este atributo é aplicável apenas ao elemento <f:view>,

sendo compatível apenas com views escritas a partir da VDL facelets. Logo, páginas/views escritas em

HTML ou JSP não se beneficiam desta nova feature.

O valor definido para este novo atributo será usado para identificar o contrato a ser seguido. No exemplo

trazido com a Listagem 6, determinamos que o nome do contrato será especificado em tempo de execução,

de acordo com o valor que um bean gerenciado estiver guardando, em um de seus atributos, naquele

momento.

Listagem 6. Index.xhtml. View principal, que faz uso do sistema de contratos implementado.

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html"

xmlns:f="http://xmlns.jcp.org/jsf/core"

xmlns:ui="http://xmlns.jcp.org/jsf/facelets">

<f:view contracts="#{templateBean.templateSelecionado}" >

<ui:composition template="/template.xhtml" >

<ui:define name="conteudo" >

<h:form prependId="false" >

<p style="font-family:Verdana,sans-serif;color: red; font-weight:

bolder;">

O primeiro template foi aplicado, por isso estamos vendo este conteúdo!

</p>

<h:commandButton id=”btnTroca” value="Trocar template"

action="#{templateBean.trocarTemplate()}" />

</h:form>

</ui:define>

</ui:composition>

</f:view>

</html>

Mais abaixo, ainda na Listagem 6, é definido o template que será empregado na composição desta view. No

caso, o nome do template é fixo, e recebeu o valor de template.xhtml.

Na Listagem 7, por sua vez, o que temos é um bean gerenciado que, como apresentamos há alguns

instantes, é responsável por definir qual será o contrato aplicado à view da Listagem 6. Trata-se da classe

TemplateBean, que possui um atributo intitulado templateSelecionado. Esta é a variável de instância que,

por meio da EL (Expression Language), teve seu valor vinculado ao atributo contracts da view.

Inicialmente, este atributo de TemplateBean está associado a uma constante estática identificada como

CONTRATO1, de valor, “contrato1”. Este valor é alternado entre os valores “contrato1” e “contrato2”

(este último guardado em outra constante, CONTRATO2) a cada vez que o usuário clicar no botão

identificado como btnTroca, da view exibida na Listagem 6.

Page 41: A renovação do JSF

Listagem 7. TemplateBean.java. Bean gerenciado responsável por gerenciar a mudança de templates em

runtime.

package br.com.devmedia.multitemplate.mbeans;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;

import javax.inject.Named;

/**

* Bean gerenciado responsável por realizar a troca de template da aplicação em

* tempo de execução, demonstrando a característica intitulada "Resource Library

* Contracts" da especificação JavaServer Faces 2.2.

*

* @author pedrobrigatto

*/

@Named(value = "templateBean")

@SessionScoped

public class TemplateBean implements Serializable {

private static final String CONTRATO1 = "contrato1";

private static final String CONTRATO2 = "contrato2";

private String templateSelecionado = CONTRATO1;

public String getTemplateSelecionado() {

return templateSelecionado;

}

public void setTemplateSelecionado(String templateSelecionado) {

this.templateSelecionado = templateSelecionado;

}

/**

* Método usado para se trocar o contrato em uso pelo cliente no momento.

*/

public void trocarTemplate () {

if (templateSelecionado != null) {

switch (templateSelecionado) {

case CONTRATO1:

templateSelecionado = CONTRATO2;

break;

case CONTRATO2:

templateSelecionado = CONTRATO1;

break;

}

} else {

templateSelecionado = "contrato1";

Page 42: A renovação do JSF

}

}

}

Este cenário é flexível ao ponto de permitir a troca, em tempo de execução, do contrato seguido pela página

em exibição. O nível de flexibilidade seria ainda maior caso a escolha do template fosse também dinâmica,

determinada por um bean gerenciado de acordo com o gosto do usuário. Quando, no exemplo apresentado,

fixamos o nome do template como template.xhtml, acabamos obrigados a nomear cada arquivo de template,

dentro de cada pasta de contrato, exatamente com este nome, de modo que a aplicação seja capaz de

encontrar, para cada contrato selecionado, o modelo a ser seguido pela página em exibição.

Por fim, apresentamos na Figura 3 o resultado da execução desta aplicação. Isto é tudo o que precisamos

saber para começar a trabalhar com múltiplos templates dentro de soluções baseadas no JSF 2.2. Embora

tudo o que vimos já seja suficiente para o desenvolvimento de soluções interessantes, é importante que o

leitor fique atento às novidades que virão na próxima edição da especificação JSF. Como dito no início, esta

é uma das tantas características incorporadas no framework com um escopo significativamente reduzido em

relação ao projeto original. É importante que fiquemos atentos, pois uma nova revisão desta especificação

trará, certamente, ainda mais poder no que tange ao recurso de múltiplos templates em Java para a web.

A seguir, vamos examinar a última das grandes características do JSF 2.2, que é o conceito de views sem

estado (stateless views).

Figura 3. Demonstração do uso de dois templates aplicados a uma mesma view.

Stateless views

Já sabemos, dos conceitos vistos no primeiro artigo desta série, que em JSF há uma preservação do estado de

cada componente e, consequentemente, da view como um todo, no ambiente servidor. Esta é uma

característica que não causa incômodo à maioria dos desenvolvedores na esmagadora maioria dos casos,

mas é constantemente foco de discussão entre outros, que levantam para debate alguns pontos mais

sensíveis, como:

1. Guardar o estado da view pode ser prejudicial para o desempenho da aplicação;

Page 43: A renovação do JSF

2. O consumo de memória acaba se tornando abusivo a partir de frameworks que guardam o estado de

views, uma vez que esta é uma informação adicional que, para toda view, sempre deve ser considerada;

3. Guardar o estado de views gera uma série de inconvenientes no tocante a exceções com relação às views

expiradas;

4. Manter o estado das views impede o roteamento de requisições entre máquinas servidoras executando

uma aplicação JSF em um contexto de clusters e suporte a failover.

No contexto das máquinas servidoras dos dias de hoje, é um grande exagero (e, cabe dizer, até certo

preciosismo) falar em prejuízo tanto no consumo de memória quanto no desempenho da aplicação, pois um

estado de uma view, representado no ambiente servidor, definitivamente não traz qualquer degradação para

o ambiente em si. No entanto, os outros dois pontos merecem uma atenção especial, principalmente aquele

que diz respeito à questão do ambiente de failover. Portanto, dedicaremos um foco maior sobre esses dois

itens a partir de agora.

Sobre expiração de views

Sempre que uma página é requisitada por um usuário e, por algum motivo, ela não se encontra mais salva na

sessão, podemos nos deparar com uma situação de view expirada, sinalizada pela runtime do JSF como uma

instância de javax.faces.application.ViewExpiredException. Um exemplo clássico em que isso acontece é

aquele em que o sistema permaneceu ocioso por um longo tempo, excedendo o tempo máximo de sessão

configurado.

O processo é razoavelmente simples de entender, e falaremos um pouco sobre ele antes de prosseguirmos. Já

abordamos o ciclo de vida de uma requisição JSF em detalhes no primeiro artigo, e focaremos mais

especificamente na primeira daquelas etapas, conhecida como “Restauração de uma view”. Este é o

momento em que casos de expiração de views podem ocorrer.

Tudo começa quando uma view precisa ser recuperada (montada ou restaurada), processo conduzido pela

instância de javax.faces.application.ViewHandler mantida pelo singleton

javax.faces.application.Application, que representa a aplicação propriamente dita. O método invocado,

aqui, é o initView(FacesContext), processado antes mesmo do ciclo de vida JSF ser iniciado.

Caso esta requisição seja do tipo postback (ou seja, trata-se de uma view já visitada anteriormente, à qual se

está retornando), o fluxo segue em frente a partir de uma tentativa, pela já citada instância de ViewHandler,

de restaurar a view, o que é executado a partir da invocação do método restoreView(FacesContext

contexto, String viewId), em que viewId é o identificador da view envolvida na requisição corrente.

O retorno deste método é uma instância de javax.faces.component.UIViewRoot, que representa a árvore de

componentes da view identificada pelo ID fornecido. Sempre que, entretanto, obtivermos como resultado da

execução deste método um ponteiro nulo, estaremos diante de um caso em que a view desejada não pôde ser

encontrada. Este é um caso que, pela especificação, estaremos sujeitos ao lançamento de uma instância da

classe javax.faces.application.ViewExpiredApplication.

Nos casos em que a requisição não é de um postback, haverá a tentativa de se recuperar a instância de

javax.faces.view.ViewDeclarationLanguage da view desejada. Esta busca começa a partir de uma

chamada a um método da instância de ViewHandler de assinatura deriveLogicalViewId(FacesContext

contexto, String rawViewID), cujo papel é o de retornar o identificador da view a partir de um valor bruto

passado pela requisição que, quando submetido a um algoritmo interno de ViewHandler, resulta no

identificador da view em questão. Este algoritmo não será detalhado aqui, mas pode ser encontrado na

documentação oficial da JSR-344 (cujo endereço se encontra na seção Links).

Page 44: A renovação do JSF

De posse do identificador da view, o próximo passo é obter a instância de ViewDeclarationLanguage a

partir dele, o que é feito invocando-se o método, também da instância de ViewHandler, chamado

getViewDeclarationLanguage(FacesContext contexto, String viewId).

Se nenhuma instância de ViewDeclarationLanguage puder ser obtida pela chamada ao método

mencionado, o processo de renderização da resposta será imediatamente acionado. Caso contrário, haverá

uma sequência de passos (identificação de metadados, criação de uma view a partir desses metadados,

dentre outros) que culminarão na criação da view desejada e, por fim, na execução da fase de renderização

da resposta.

De uma forma ou de outra, o ponto importante aqui é que, dados contextos de longo período da aplicação

em modo de repouso (ou seja, um intervalo de tempo razoavelmente longo em que, muito embora a

aplicação esteja aberta em um navegador, não esteja sendo usada) ou mesmo um longo período em que uma

view já visitada não é novamente apresentada ao usuário, teremos configurados cenários em que a view em

questão pode se encontrar expirada.

Nessas situações, invariavelmente, uma exceção será lançada e, em última instância, terá que ser tratada

devidamente para não resultar em uma experiência frustrante para o usuário. Este é um problema que surge

exatamente pelo fato de que o JSF é um framework web que, como tantos outros, preocupa-se com a

preservação do estado da view em ambiente servidor.

Existem muitos pontos positivos nesta abordagem, sendo que a esmagadora maioria dos desenvolvedores

não apresenta queixa alguma sobre este recurso. Entretanto, uma parcela da comunidade vem questionando,

frequentemente e há um bom tempo, os motivos pelos quais não se incluía o suporte a views sem estado no

framework. Com o JSF 2.2, após a longa insistência e, também, a força do argumento associado à expiração

de views, temos finalmente um primeiro passo caminhando neste sentido.

Sobre ambientes rodando em cluster

Em ambientes tolerantes a falhas, é muito comum trabalharmos com clusters de servidores e aplicarmos

algoritmos de balanceamento de carga entre eles. Dessa maneira, garantimos que o sistema estará sempre

disponível a seus usuários, independentemente da carga de requisições que se aplique a ele.

Em JSF, ao guardarmos o estado de uma view na sessão, criamos um vínculo entre ela e o nó (máquina

servidora) que a gerou. Logo, quando o usuário retorna à view já criada, é obrigatório que isso seja feito pelo

mesmo nó que a originou.

Se este nó, por algum motivo, estiver indisponível, estaremos diante de um problema. Da mesma forma,

caso este nó esteja sobrecarregado e esta view seja novamente acessada por um usuário, estaremos

impedidos de trabalhar com balanceamento de carga e poderemos, por isso, ter que enfrentar problemas

como lentidão, indisponibilidade, dentre outros.

Remover nós dinamicamente de um cluster também pode ser muito complicado quando temos views que

guardam estado, pelos mesmos motivos já levantados.

Embora haja contornos possíveis para os dois problemas acima mencionados, nunca resolverão, de fato, o

problema. Logo, encontramos neles justificativas razoáveis para o suporte a views sem estado.

A solução para esta necessidade levantada pela comunidade foi obtida às pressas e incorporada tardiamente

na especificação. Embora fosse um recurso programado para ser apresentado a partir do JSF 2.2, os

trabalhos em torno desta característica começaram com muito atraso e sério risco de postergação. No

entanto, um desenvolvedor de nome Manfred Riem acabou adicionando uma solução à implementação de

referência da especificação JSF (Mojarra) de extrema simplicidade e grande valor, que consiste basicamente

nos pontos listados a seguir:

Page 45: A renovação do JSF

· A tag handler para <f:view> agora passa a processar o atributo transient, que já existia em versões

anteriores do JSF, passando o valor nela guardado para a raiz da árvore de componentes (UIViewRoot)

através de uma chamada ao método UIViewRoot#setTransient(boolean transient);

· Sempre que a raiz da árvore de componentes da view sendo requisitada tiver o seu valor de transiência

definido como true (o que passa a ser interpretado como uma view sem estado), a view não será restaurada.

Esta implementação de Manfred, de tão simples, limpa e eficaz, foi proposta para padronização dentro da

especificação do JSF. O grupo de trabalho da JSR-344 realizou apenas algumas poucas adaptações no

sentido de acomodar toda a lógica no contexto do framework e, finalmente, lançou o recurso tanto na

especificação quanto na implementação de referência do framework.

Naturalmente, há muito espaço para melhorias. Atualmente, a propriedade transient deve ser definida como

true em cada view que quisermos definir como stateless. A propriedade, no entanto, aplica-se a todos os

componentes que constituem uma view, o que pode ser genérico demais em alguns cenários que

desenvolvedores enfrentam no dia a dia. De qualquer forma, o que temos na versão 2.2 já é bastante útil e

interessante, cabendo a nós esperar pela próxima revisão para aproveitar deste recurso de uma maneira mais

plena.

Conclusão

Chegamos ao final de nosso estudo sobre o JSF 2.2. Ao longo desta série de dois artigos, abordamos os

principais recursos inseridos nesta nova revisão da especificação, conhecidos como as Big Ticket Features.

Neste último artigo, especificamente, comprovamos o quanto se tornou simples trabalhar com alguns

recursos muito úteis dentro do desenvolvimento web, como o uso dinâmico de templates variados, a carga

de arquivos e, também, o uso de views stateless.

Todas essas modificações passam um recado bastante claro de que não apenas JSF, mas a plataforma Java

EE em sua plenitude, vem se tornando cada vez mais completa e, principalmente, aderente ao panorama

contemporâneo de desenvolvimento de aplicações web. Desta maneira, figura hoje como um forte candidato

a substituir, definitivamente, alguns frameworks que acabaram surgindo exatamente para cobrir deficiências

que, por anos, foram marcantes na especificação Java EE.

Estes, por não estarem vinculados a um processo tão complexo como o proposto pelo JCP, evoluem em um

ritmo naturalmente mais acelerado, o que também acaba sendo benéfico para o ecossistema como um todo,

ditando o ritmo do progresso e contribuindo para o alinhamento de pensamentos e o clareamento da ideia

por trás de cada demanda da comunidade. Veja, na seção Links, um bom artigo que apresenta uma proposta

de substituição do framework Spring por recursos presentes na própria Java EE, que é uma leitura que vem

de encontro a isto que acabamos de citar aqui.

Falando especificamente de JavaServer Faces, a marcha de seu progresso só não foi mais forte devido,

infelizmente, a algumas intempéries ocasionadas por todas as notícias veiculadas recentemente sobre

vulnerabilidades da tecnologia Java, que mobilizaram boa parte das equipes de engenheiros,

desenvolvedores e arquitetos no sentido de acelerar uma resposta frente aos problemas detectados. A

resposta, de fato, foi consistente e veio em um intervalo muito curto de tempo, mas trouxe consigo um

inevitável efeito colateral refletido no atraso de alguns dos cronogramas internos.

Entretanto, os planos da especificação continuam sólidos, e tudo isso nos faz esperar, para uma próxima

revisão, soluções definitivas para todas as características que, neste momento, ainda se mostram

timidamente, nos limites do que seus escopos, hoje um pouco reduzidos, nos permitem enxergar.

Desejamos a todos os leitores um bom divertimento e uma trajetória de muito sucesso e muitos e bons frutos

ao adotarem todos esses recursos do JSF 2.2 em seus projetos em Java para a Web.