Artigo do tipo Exemplos Práticos
Recursos especiais neste artigo:
Artigo no estilo Curso Online

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. 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 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.

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

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 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 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) 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 (). 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.
  4. ...

    Quer ler esse conteúdo completo? Tenha acesso completo