Motivação

Antes do lançamento da versão 2 do JavaServer Faces, a forma mais usual de reutilizar trechos de código que envolvessem interface gráfica era através da tag ui:include, que permite inserir uma página, ou um trecho de uma página, dentro da outra. No entanto, com o passar do tempo, o aumento da busca pela reutilização de código/componentes fez com que essa prática se mostrasse não tão eficiente. A partir dessa necessidade, no JSF 2 foram criados os Composite Components, recurso dá ao desenvolvedor a possibilidade de construir seus próprios componentes.

Estrutura básica

Os Composite Components são páginas XHTML, assim como aquelas utilizadas no ui:include, mas que diferem em sua estrutura, pois foram criados com o intuito de representar componentes reutilizáveis em todo o projeto.

Na Listagem 1 temos a estrutura básica de um Composite Component vazio.


01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
02 <html xmlns="http://www.w3.org/1999/xhtml"
03   xmlns:composite="http://java.sun.com/jsf/composite">
04 <composite:interface>
05 </composite:interface>
06 <composite:implementation>
07 </composite:implementation>
08 </html>
Listagem 1. Estrutura básica de um Composite Component

Linhas 4 e 5: A seção interface é responsável por receber os argumentos/parâmetros que serão utilizados na construção do componente, semelhante à assinatura de um método;

Linhas 6 e 7: Na seção implementation fica o conteúdo propriamente dito do componente, o qual pode fazer uso dos argumentos definidos na seção anterior.

Utilizando os componentes

Após criar um Composite Component, você precisa salvá-lo em um local específico que possa ser lido pelo JSF a fim de utilizá-lo em outras páginas do seu projeto. O local no qual salvamos os componentes é de fundamental importância, pois ele define o namespace que precisa ser referenciado nas demais páginas.

Por padrão, devemos criar uma pasta com o nome desejado no caminho /src/main/webapp/resources/nome_da_pasta. Essa pasta armazenará todos os componentes do projeto e definirá o namespace no qual estão contidos. Por exemplo, se optarmos por utilizar o nome “devcomp” para esse diretório, o namespace será referenciado nas páginas da seguinte forma:


<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:devcomp="http://java.sun.com/jsf/composite/devcomp">

Declarando corretamente o namespace, podemos começar a usar os componentes contidos na respectiva pasta. Dessa forma, caso tenhamos criado um componente chamado calculadora, podemos utilizar o seguinte código para incluí-lo na página:


  <devcomp:calculadora operacao="soma" />
  

Nesse trecho utilizamos o alias (apelido dado ao namespace) devcomp para fazer uso do componente calculadora, que está contido no arquivo calculadora.xhtml, dentro da pasta devcomp, e cujo código pode ser visto na Listagem 2. Neste ponto é válido ressaltar que o nome do componente é o mesmo do arquivo. Também podemos perceber a passagem do parâmetro solicitado pelo componente, que pode ser um valor fixo, como fizemos aqui, ou uma variável, passada através da Expression Language.


01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
02 <html xmlns="http://www.w3.org/1999/xhtml"
03    xmlns:h="http://java.sun.com/jsf/html"
04    xmlns:composite="http://java.sun.com/jsf/composite">
05 <composite:interface>
06    <composite:attribute name="operacao" required="true" />
07 </composite:interface>
08 <composite:implementation>
09    <h:outputLabel value="Valor A" />
10    <h:inputText value="#{calculadoraMB.valorA}" />
11    <h:outputLabel value="Valor B" />
12    <h:inputText value="#{calculadoraMB.valorB}" />
13    <h:outputLabel value="Resultado" />
14    <h:inputText value="#{calculadoraMB.resultado}" />
15    <h:commandButton value="Calcular" actionListener="#{calculadoraMB.calcular(cc.attrs.operacao)}" />
16 </composite:implementation>
17 </html>
Listagem 2. Composite Component calculadora

Linhas 5 a 7: Definimos o argumento operação como obrigatório (required=true). Esse parâmetro será usado para passar ao ManagedBean o tipo de operação que gostaríamos de realizar com os dois valores informados na calculadora;

Linhas 8 a 16: Criamos três inputText e seus respectivos labels, para que o usuário possa informar os valores de A e B, e visualizar o resultado. Em seguida, criamos um commandButton, que irá fazer a chamada ao método calcular() do ManagedBean calculadoraMB. Aqui é importante notar como o JSF acessa os atributos do componente: na expressão #{cc.attrs}, o cc faz referência ao Composite Component atual, e o attrs dá acesso aos argumentos declarados na seção interface.

Na Figura 1 podemos ver o resultado da inclusão do componente na página.

Componente em uso em uma página
Figura 1. Componente em uso em uma página

As possibilidades de uso dos Composite Components são várias: menus, formulários de uso comum e elementos que precisem ser empregados em diferentes partes do sistema são alguns dos muitos exemplos.