Aplicações sérias em JSF usam Facelets

Não há exagero no título do post, de fato, aplicações sérias desenvolvidas em JSF deveriam utilizar Facelets. Desenvolvedores que abrem mão de todas as vantagens oferecidas por este framework estão “pisando na bola”.

Já é de conhecimento da maioria que JSF sozinho [apenas a implementação] não nos fornece os recursos necessários para desenvolver médias ou grandes aplicações webs de maneira produtiva, o framework possui vários problemas (mas qual não possui?), muitos deles são facilmente resolvidos com a adoção de algum framework ou conjunto de componentes, outros podemos resolver apenas com algum conhecimento/conceito base sobre o framework ou seguindo algumas boas práticas.

E por falar em boas práticas, certamente uma das melhores práticas -e praticamente obrigatória- é a utilização de algum framework de templating para construção das páginas, não somente em JSF, claro.

Pois se estamos trabalhando com páginas, por que então não utilizarmos algum framework para definição de templates?

Templating frameworks

Hoje existem várias opções de frameworks com essa finalidade, porém a grande maioria deles não foi desenvolvido para trabalhar com JSF, a maioria deles não foi desenvolvido para trabalhar de acordo com o ciclo de vida das requisições processadas pelo JSF. Alguns deles funcionam até bem, porém com toda certeza em determinados momentos eles te deixarão na mão.

Acredito que hoje os frameworks para definição de templates mais comuns são o Struts Tiles e o Sitemesh, ambos funcionam bem com JSF até que em algumas situações os problemas começam a surgir, problemas como perda do FacesContext, código duplicado, conflito de componentes, funcionalidades AJAX param de funcionar etc. Sendo, com certeza nem Struts Tiles nem Sitemesh são boas opções de frameworks para se trabalhar com JSF.

Pior do que usar um dos dois frameworks citados acima é criar seu próprio mini-fashion-templating-framework, seja utilizando-se de JSP taglibs ou mesmo de um Servlet Filter, não importa, fuja disso, evite reinventar a roda, aliás, evite reinventar uma roda ainda pior do que as já existentes [não quero entrar na discussão dos malefícios de criar seu framework caseiro].

A melhor opção

Já faz um bom tempo que temos excelentes opções de templating frameworks desenvolvidos especialmente para JavaServer Faces como o Facelets ou JSFTemplating. Ambos trabalham perfeitamente bem com JSF e trazem diversos benefícios tanto em termos de perfomance como em produtividade.

Mas com toda certeza o mais utilizado, mais popular, com maior suporte da comunidade, maior documentação e provavelmente mais estável entre eles é o Facelets.

Iniciar um projeto web com JSF e não adotar Facelets é começar um projeto “pisando na bola”, é abrir mão de diversos benefícios para a equipe de desenvolvedores e para a aplicação em si.

Facelets possui várias vantagens que vão desde a facilidade na criação e reutilização de páginas e componentes, melhor depuração de erros, AJAX nativo, uma melhor compatibilidade entre XHTML, JSTL e os componentes, ele é independente de web container, e claro, Facelets é de 30% a 50% mais rápido que JSP.

Ah, claro, como poderia esquecer, JSF2.0 adotou Facelets como view handler padrão, então, provavelmente migrar uma aplicação de JSF1.2 (ou mesmo JSF1.1) para JSF2.0 será menos trabalhoso ainda caso você não o estive usando.

Estas são somente algumas vantagens ao se adotar Facelets em um projeto, existem várias outras, mas eu considero estas como as principais.

Concluindo

Infelizmente JSF1.2 utiliza-se de JSP como view handler padrão por questões políticas e principalmente comercias, mas acreditem em mim, eles são como água e óleo, não combinam juntos. Para falar a verdade, por que você acha que todos os exemplos dos produtos da JBoss (Richfaces, Seam etc) estão utilizando-se massivamente de Facelets e não de JSP?

Enfim, não há motivos para não adotar Facelets em um novo projeto ou mesmo em um projeto já em andamento [é possível ir migrando de JSP para Facelets aos poucos], todos os conjuntos de componentes que conheço funcionam perfeitamente bem com ele e algumas vezes até melhor, o que não falta são artigos, blogs, tutoriais, fóruns, revistas e listas de discussão com informações suficientes para configurar e tirar melhor proveito do Facelets na sua aplicação.

Volto a dizer, iniciar um projeto sério em JSF sem adotar Facelets como framework para templating é começar errado. Eu falo sério.

JSF e Naming Container

Todo desenvolvedor que se utiliza de JavaServer Faces deveria saber como funciona o mecanismo de geração de identificação (ID) dos componentes, pois uma hora querendo ou não ele precisará deste conhecimento, principalmente se houver a necessidade de se escrever algum código JavaScript.

Enfim, vamos ao que interessa..

Entendendo o mecanismo

Uma das caracteristicas do JSF é que todos os seus componentes possuem um atribudo “id” e este atributo deve conter um valor único, caso não seja definido um ID pelo desenvolvedor então será gerado automaticamente um ID único para cada componente durante a construção da árvore de componentes.

Sendo, observem o seguinte trecho de código JSF:

<h:form>
	<h:inputText id="nome"/>
</h:form>

No final será gerado para o cliente (browser) o seguinte código -ou algo parecido- (X)HTML:

<form id="j_id_jsp_1761815803_1" name="j_id_jsp_1761815803_1" method="post">
	<input id="j_id_jsp_1761815803_1:nome" type="text" name="j_id_jsp_1761815803_1:nome" />
</form>

Reparem que o atributo “id” do componente h:form não foi definido, porém o framework gerou um ID único para o componente, no caso o ID foi “j_id_jsp_1761815803_1“, que foi renderizado juntamente com a tag <form/> do (X)HTML.

Atentem também que o ID (gerado) do componente h:form foi concatenado ao ID (que nós definimos) do componente h:inputText separados por ‘:’ (dois pontos) na tag <input/>, logo o ID da nossa tag <input/> é “j_id_jsp_1761815803_1:nome“.

Infelizmente os IDs gerados pelo framework não são nada legíveis para nós desenvolvedores -e provavelmente não deveriam-, então para consertar isso basta definirmos o ID de cada componente na nossa página, logo nosso código JSF ficará assim:

<h:form id="form">
    <h:inputText id="nome"/>
</h:form>

E consequentemente o código (X)HTML gerado será algo semelhante a isto:

<form id="form" name="form" method="post">
	<input id="form:nome" type="text" name="form:nome" />
</form>

Como podem ver, os IDs na página gerada ficam bem mais legíveis, facilitando assim o trabalho com JavaScript no lado cliente.

Naming container

E onde afinal de contas entra essa história de Naming Container?

Se vocês observaram o componente h:inputText teve seu ID concatenado ao ID do formulário no cliente, ou seja, na tag <input/> (X)HTML, e isso aconteceria com todos os componentes dentro do componente h:form. Logo, o componente h:form é um componente e ao mesmo tempo um naming container.

Basicamente, Naming Container é uma caracteristica que alguns componentes possuem, caracteristica essa que o framework utiliza para garantir que dentro de um naming container (componente) seus componentes filhos possuam IDs  únicos, evitando assim a duplicidade de componentes com o mesmo ID na página (viewroot).

Outra caracteristica importante que você deve saber sobre naming containers é que eles podem ser aninhados, logo os componentes mais internos terão seus IDs no cliente concatenados com os IDs dos naming containers mais externos também.

Logo em um caso como:

<h:form id="form">
    <f:subview id="subview">
        <h:inputText id="nome"/>
    </f:subview>
</h:form>

Teríamos o código (X)HTML abaixo gerado:

<form id="form" name="form" method="post">
	<input id="form:subview:nome" type="text" name="form:subview:nome" />
</form>

O componente f:subview também é um naming container, porém ele não gera qualquer output no cliente, ele é utilizado basicamente para servir como naming container, principalmente quando se faz includes de páginas dinâmicas.

Simples até demais, não?

Componentes padrões como h:form, f:subview e h:dataTable são naming containers. A maioria dos conjuntos de componentes possuem alguns naming containers, logo isso depende do conjunto de componentes.

Evitando naming container no formulário

As vezes temos páginas simples em que o único naming container é o próprio componente h:form, e nestas páginas precisamos manipular alguns dados no formulário através de JavaScript, porém é algo realmente chato ficar concatenando IDs para obter o ID de um input do formulário.

Para resolver isso o componente h:form (no JSF1.2) possui o atributo “prependId” que define se o componente se comportará no cliente como naming container ou não. Para evitar que o h:form se comporte como naming container basta setarmos o atributo “prependId” para false. Assim quando o código (X)HTML for gerado para o cliente as tags internas não terão seus IDs modificados.

<h:form id="form" prependId="false">
    <h:inputText id="nome"/>
</h:form>

Sem complicações, certo?

Essa caracteristica funciona somente para os componentes filhos do h:form, caso haja um naming container dentro do h:form então os filhos deste name container terão seus IDs alterados normalmente no cliente.

Concluindo

O post ficou até longo para um assunto básico, mas acredito que consegui abordar os fundamentos sobre naming container para quem pretende apenas utilizar os componentes na construção de páginas. Para quem realmente pretende criar (ou estender) seus próprios componentes seria interessante conhecer o conceito mais a fundo.

Enfim, o conceito é básico, porém fundamental para desenvolvedores que usam JavaServer Faces. Contudo é incrível como a maioria dos desenvolvedores não se interessam pelos fundamentos do framework, fundamentos estes que evitariam diversas dúvidas e problemas durante o desenvolvimento.

Não era mais uma receita de bolo JSF!

É incrível como depois do post Utilizando AJAX com JSF de maneira eficiente muitos desenvolvedores tem utilizado o exemplo básico do post -que nada mais era do que uma prova de conceito- como receita de bolo para criar aplicações sérias. Talvez eu não tenha sido claro, mas o intuito do post não era demonstrar um passo-a-passo de como desenvolver uma aplicação com alguns conjuntos de componentes, mas sim passar o conceito de como aproveitar melhor os recursos oferecidos pela tecnologia para criar aplicações mais ricas e leves.

Eu tentei ao máximo deixar claro que não eram os componentes X, Y ou Z que me forneciam recursos para implementar o conceito, como está bem claro nos trechos do post abaixo:

Utilizar um conjunto de componentes ricos e um framework AJAX. (Neste caso eu optei pelo Richfaces/Ajax4jsf por ser bastante simples de usar e integrar, por ser estável e por ser bastante utilizado na comunidade, contudo, qualquer outro conjunto de componentes AJAX poderia ser utilizado, como Trinidad ou mesmo o IceFaces);

E este,

Eu não me prendi a utilização dos frameworks ou conjuntos de componentes utilizados pois este não era o intuito do post, isso é algo simples e acredito que a maioria dos leitores não tenham dificuldades em relação a isso. Além do mais é possível implementar isso não somente com o Richfaces/Ajax4jsf, mas com qualquer outro framework ou conjuntos de componentes AJAX, por exemplo, […]

Não é necessário utilizar Richfaces/Ajax4jsf, Tomahawk e Facelets para aproveitar os recursos da tecnologia de forma eficiente, você poderá conseguir isso com qualquer outro framework ou conjunto de componentes que te permitam unir AJAX e JSF de maneira prática, sejam eles Trinidad, JBoss Seam, IceFaces, Ajax4jsf, ADF Faces e/ou JSFTemplating.

Mais claro que isso é impossível.. porém ainda não acabou, um fato engraçado é que alguns desenvolvedores chegaram a se queixar de que eu fui muito radical ao dizer para desenvolverem toda uma aplicação em uma única página. Eu em nenhum momento disse ou mesmo insinuei isto, o que eu disse foi:

A idéia principal tem por objetivo evitar escrever muitas páginas para representar cada view (tela), diminuindo assim o número de páginas no projeto, o número de regras de navegação no faces-config.xml, diminuindo o overhead no servidor e no cliente a cada refresh de página, […]

Vocês não precisam e provavelmente não deveriam implementar suas aplicações seguindo o exemplo do post, ele é básico, ele serve como referência, possui uma implementação simples e não se preocupa com alguns requisitos não funcionais como a paginação sob demanda ou quais os objetos que deveriam permanecer entre as requisições. Além do mais o exemplo é um CRUD, e não uma interface com o usuário mais complexa no sistema.

Entendam uma vez por todas que não existe uma arquitetura de referência ou receita de bolo para desenvolver sistemas, cada sistema possui suas necessidades e peculiaridades, e estas devem ser estudadas e analisadas para se chegar a uma solução plausível.

O importante é que vocês compreendam o conceito, seus prós e contras e principalmente onde e quando utiliza-lo. Não se prendam ao framework ou conjunto de componentes, a maioria deles hoje em dia te fornecem os recursos necessários para implementar a idéia sem muitas dificuldades.

Enfim, estudem, entendam, aprimorem, façam testes e implementem o conceito onde for necessário, com os componentes e frameworks cabíveis e sempre com bom senso.