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