O JavaServer Faces (JSF) é um framework de interface com o usuário no lado servidor para aplicações web baseadas em Java e está definido na especificação JSR 344. Diversas novidades foram incorporadas à nova especificação do JSF 2.2.

Nas próximas seções veremos as novidades do JSF 2.2 com mais profundidade. Entre eles estudaremos as novidades introduzidas no Facelets, Gerenciamento de recursos e o ciclo de vida para o processamento de requisições.

Facelets

Facelets é uma tecnologia de template para JSF. Os Facelets são uma substituição para o JSP, que atualmente só está sendo mantido para fins de compatibilidade com sistemas legados. Algumas das novidades da versão 2 da especificação JSF, tais como composição de componentes e Ajax, são disponibilizados para aqueles que usam Facelets. Usar Facelets permite que tenhamos em mãos um poderoso sistema de templates, reuso, facilidade de desenvolvimento, um melhor relatório de erros, etc.

As páginas utilizando Facelets são criadas através do XHTML 1.0, que é uma reformulação do HTML 4 seguindo regras do XML 1.0 e Cascading Style Sheets (CSS).

Além disso, as páginas devem estar em conformidade com o DTD XHTML-1.0-Transitional. Segue na Listagem 1 um exemplo uma página Facelet.

Listagem 1. Exemplo de uma página Facelet.


  <?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>Titulo da Pagina Facelet</title>
           </h:head>
   
           <h:body>
                     Exemplo de Página Facelet
           </h:body>
  </html>

Nesse exemplo temos uma declaração de um DTD, o elemento principal da página <html> com o namespace http://www.w3.org/1999/xhtml. Além disso, temos também tags HTML (começando com h:) e também tags HTML regulares utilizadas para adicionar componentes.

Segue na Tabela 1 as tags suportadas pelo Facelets.

Prefixo

URI

Exemplos

h

http://xmlns.jcp.org/jsf/html

h:head, h:inputText

f

http://xmlns.jcp.org/jsf/core

f:facet, f:actionListener

c

http://xmlns.jcp.org/jsp/jstl/core

c:forEach, c:if

fn

http://xmlns.jcp.org/jsp/jstl/functions

fn:toUpperCase, fn:contains

ui

http://xmlns.jcp.org/jsf/facelets

ui:component, ui:insert

Tabela 1. Tags suportadas pelo Facelet.

Páginas XHTML possuem a extensão “.xhtml” como padrão.

Facelets possuem integração com as Expression Language (EL). Com isso poderíamos ter um bean como o da Listagem 2.

Listagem 2. Exemplo de um bean que será utilizado com EL.


  @Named
  @RequestScoped
  public class Nome {
           private String valor;
           //. . .
  }
  

E na nossa página poderíamos utilizar um código como:

"Exemplo de Facelets, meu nome é #{nome.valor}!".

A anotação @Named é utilizada para habilitar a injeção de dependência numa EL.

Podemos notar que no JSF 2.2, a tag @javax.faces.bean.ManagedBean está destina para ser obsoleta numa versão futura, portanto é altamente recomendável a utilização de @Named.

O JSF 2.2 também ganhou um novo escopo do CDI: javax.faces.view.ViewScoped. Esta anotação, quando especificada, liga o bean com a visão corrente sendo processada. A antiga javax.faces.bean.ViewScoped está destinada para ser obsoleta em uma versão futura, portanto devemos utilizar o novo escopo introduzido.

Um EJB agora também pode ser injetado numa expressão EL, como da Listagem 3.

Listagem 3. Exemplo de um EJB que será utilizado numa EL.


  @Stateless
  @Named
  public class ClienteSessionBean {
           public List<Nome> getNomesClientes() {
                     //. . .
           }
  }
  

No exemplo acima temos um bean sem estado de sessão com um método de negócio que retorna uma lista de nomes de clientes. A anotação @Named indica que este bean pode será injetado numa EL. Dessa forma, poderíamos usar o código da Listagem 4 numa página Facelet.

Listagem 4. Exemplo de utilização do EJB num Facelet.


  <h:dataTable value="#{clienteSessionBean.nomesClientes}" var="c">
           <h:column>#{c.valor}</h:column>
  </h:dataTable>
  

Neste código, a lista de nomes dos clientes retornada é exibida numa tabela. Podemos observar que o método getNomesClientes está disponível como uma propriedade na EL. Outra vantagem é que os Facelets proveem uma validação EL em tempo de compilação.

Os Facelets também proveem aos desenvolvedores um sistema de template que permite uma visualização padrão para múltiplas páginas na nossa aplicação web. Uma página base é criada via tags de template do Facelets. Esta página define uma estrutura padrão para a página, incluindo um espaço reservado para o conteúdo que será definido nas páginas usando o template padrão. Dessa forma, um "template cliente" usa o “template padrão” e provê conteúdo para este local reservado que foi definido no “template padrão”.

A Tabela 2 lista as tags do Facelets usadas no “template padrão” e no template das páginas cliente.

Tag

Descrição

ui:composition

Define um layout de página que opcionalmente usa um template. Se o atributo “template” é usado, o filho desta tag define o layout do template. Se não for usado, isto será apenas um grupo de composição de elementos que pode ser inserido em qualquer lugar. Conteúdos fora desta tag são ignorados.

ui:insert

Usado no “template padrão”. Define o local reservado para inserir conteúdo no template. Uma combinação com a tag ui:define na página do “template cliente” sobrescreve o conteúdo.

ui:define

Usado no “template cliente”. Define o conteúdo que sobrescreve o conteúdo definido no “template padrão” com uma combinação com a tag ui:insert.

ui:component

Insere um novo componente de interface com o usuário na árvore de componentes do JSF. Qualquer componente ou fragmento de conteúdo fora desta tag será ignorado.

ui:fragment

Similar ao ui:component, porém não ignora o conteúdo fora desta tag.

ui:include

Inclui o documento especificado pelo atributo “src” como parte da página Facelet atual.

Tabela 2. Tags utilizadas nos Facelets.

Uma página “template padrão” assemelha-se com o código da Listagem 5.

Listagem 5. Exemplo de uma página “template padrão”.


  <h:body>
           <div id="top">
                     <ui:insert name="top">
                              <h1>Teste com Facelets!</h1>
                     </ui:insert>
           </div>
   
           <div id="content" class="center_content">
                     <ui:insert name="content">Conteudo Aqui</ui:insert>
           </div>
   
           <div id="bottom">
                     <ui:insert name="bottom">
                              <center>Desenvolvido por Devmedia</center>
                     </ui:insert>
           </div>
  </h:body>
  

Neste template podemos notar a utilização de divs para organizar a página e das tags ui:insert que define um local reservado para inserir conteúdo no template.

No template cliente usaremos a tag “ui:define” que irá sobrescrever o conteúdo do template padrão. Segue na Listagem 6 o código do template cliente.

Listagem 6. Exemplo de uma página “template cliente”.


  <html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
  xmlns:h="http://xmlns.jcp.org/jsf/html">
    <body>
           <ui:composition template="./template.xhtml">
                     <ui:define name="content">
                              <h:dataTable value=
                                   "#{clienteSessionBean.nomesClientes}" var="c">
                                        <h:column>#{c.valor}</h:column>
                              </h:dataTable>
                     </ui:define>
           </ui:composition>
    </body>
  </html>

A primeira coisa que devemos notar no “template cliente” é que não definimos nenhuma tag “ui:define” para top e bottom, apenas para content. Isto diz ao template cliente que iremos utilizar o conteúdo de top e bottom existentes no “template padrão”. Na tag “ui:composition” especificamos o “template padrão” que iremos utilizar.

Gerenciando Recursos

O JSF também permite o gerenciamento de recursos como: imagens, arquivos CCS ou arquivos JavaScript. Os recursos podem ser empacotados no diretório “/resources” na aplicação Web ou então no “/META-INF/resources” no classpath.

Para referenciarmos um recurso com a EL utilizamos:

<a href="#{resource['cabecalho.jpg']}">Clique aqui</a>

Dessa forma, o recurso “cabecalho.jpg” está no diretório padrão resource. Caso o recurso esteja numa biblioteca podemos acessar com o atributo library conforme o exemplo abaixo:

<h:graphicImage library="corp" name="cabecalho.jpg" />

Para incluir um JavaScript utilizamos o código abaixo:

<h:outputScript name="meuScript.js" library="scripts" target="head"/>

O arquivo meuScript.js está nas pasta “scripts” no diretório “resources”.

Para incluirmos um CSS utilizamos o código abaixo:

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

Podemos notar como a API ResourceHandler facilita a vida do programador provendo recursos programaticamente de maneira organizada.

Fases do Ciclo de Vida no Processamento de Requisições (Request Processing Life-Cycle Phases)

O JSF define um padrão para as fases do ciclo de vida no processamento de requisições. Desenvolvedores de aplicação não precisam necessariamente saber detalhes sobre o ciclo de vida, mas o seu entendimento ajuda aqueles que necessitam saber mais informações a respeito de quando as validações, conversões e eventos são geralmente gerenciados e o que se pode fazer para alterar como e quando eles são gerenciados.

Uma página JSF é representada por uma árvore de componentes de interface com o usuário, chamada View. Quando um cliente requisita uma página, o ciclo de vida inicia. Durante o ciclo de vida a implementação do JavaServer Faces deve construir a View enquanto considera o estado salvo de uma submissão anterior da página. Quando o cliente submete a página, a implementação do JavaServer Faces deve executar várias tarefas, tais como validar as informações de entrada dos componentes na View, converter as informações de entrada para tipos específicos no lado servidor, e ligar informações com os backing beans.

A implementação do JavaServer Faces executa todas essas tarefas como uma série de passos no ciclo de vida. Os diferentes componentes da aplicação passam pelas seguintes fases do ciclo de vida no processamento de requisições:

  • Restore view: Restaura e cria uma árvore de componentes no lado servidor para representar as informações da interface do usuário.
    Se a solicitação for feita para uma URL, pela primeira vez, então um novo objeto View é criado e processado. Esta View é armazenada na instância corrente do FacesContext. Se o estado da View é encontrado no FacesContext, então ele é restaurado e exibido. Qualquer converter, validador ou renderer customizado, se anexado ao componente de interface com o usuário, será restaurado nesta fase. Se os valores do componente estão diretamente mapeados para a propriedade definida em um Managed Bean, então o valor da propriedade é restaurado e associado com a View. A maior parte do trabalho é feito pelo método ViewHandler.restoreView.
  • Apply request values: Esta fase atualiza os componentes do lado servidor com parâmetros de requisição, cabeçalhos, cookies, etc, a partir do cliente. Mais especificamente, o método UIComponent.processDecodes é chamado em todos os componentes.
    O resultado desta fase pode ou terminar na fase validações de processo ou na fase de processamento da resposta.
    Se qualquer das conversões ou validações falhar, então o processamento atual é encerrado e o controle vai diretamente para o processamento da resposta a fim de processar a conversão ou a validação dos erros para o cliente.
  • Process validations: Esta fase processará qualquer validação e conversão de tipos configurada para UIComponents. Nesta fase o método UIComponent.processValidators é chamado em todos os componentes. Se qualquer erro de conversão ou validação acontecer, então o processo atual é encerrado e o controle é direcionado para a fase de processamento de resposta relatando quaisquer erros.
  • Update model values: Alcançando esta fase indica que os valores das requisições estão sintaticamente corretos. O valores de UIComponents são sincronizados com o modelos de objetos, que são freqüentemente backing beans. Nesta fase o método UIComponent.processUpdates é chamado em todos os componentes. Configurar os valores das requisições para o modelo de objetos pode também resultar em eventos sendo enfileirados e disparados.
  • Invoke application: Invoca a lógica da aplicação e executa o processamento da navegação. Todos os listeners que estão registrados para o UIComponents são invocados.
  • Render response: Processa a resposta de volta para a aplicação do cliente.

Antes de processar a resposta, a aplicação armazena o estado da View no cache chamando o método UIViewRoot.saveState.

Bibliografia

[1]Josh Juneau. Java EE 7 Recipes: A Problem-Solution Approach. Apress, 2013.

[2]Josh Juneau. Introducing Java EE 7: A Look at What's New. Apress, 2013.

[3]Arun Gupta. Java EE 7 Essentials. O'Reilly, 2013.